2011-07-25 33 views
2

複数のTabItemを持つTabControlを持つSilverlightアプリケーションがあります。ユーザーがタブ項目を選択すると、そのTabItem内の特定のコントロールにフォーカスを設定したいと思う。これはどうすればいいですか?TabItemが選択されているときに、TabItemのTextBoxにフォーカスを設定します。

私はTabControlののSelectionChangedイベントのイベントハンドラを作成しようとしたし、次のコードを追加:txtTextBox1txtTextBox2が問題になっているタブにTextBoxコントロールです

private void tcTabs_SelectionChanged(object sender, SelectionChangedEventArgs e) 
{ 
    if (tcTabs != null) 
    { 
     switch (tcTabs.SelectedIndex) 
     { 
      case 0: 
       txtTextBox1.Focus(); 
       break; 

      case 1: 
       txtTextBox2.Focus(); 
       break; 

      ... 
     } 
    } 
} 

を。

Focusメソッド呼び出しでブレークポイントを設定すると、あるタブから別のタブに切り替えるときに呼び出されているように見えますが、タブが表示されてもコントロールにフォーカスが当てられません。私の前提は、ちょっと後でFocusに電話する必要があるということですが、いつ電話をかけるのか、どうすればいいですか。

大変助かりました。

感謝のTabControlの

答えて

6

楽しい事実:あなたはタブを切り替えるたびに、のTabItemの子コントロールを再ロードされます。つまり、Loadedイベントが発生します。だから代わりにイベントをアタッチすることができます。

私の好みは、Expression SDKで使用可能なトリガー/アクションビヘイビアを使用することです。これをXAML経由で行うことができます(私には、これが必要なたびにイベントをアタッチする必要がありません) 。

System.Windows.Interactivity.dllへの参照がない場合は、これを追加します。

使用このトリガー・アクションのサブクラス:

using System.Windows; 
using System.Windows.Controls; 
using System.Windows.Interactivity; 

namespace SilverlightApplication1 { 
    public class SetFocusAction : TriggerAction<DependencyObject> { 
     public static readonly DependencyProperty TargetProperty = 
      DependencyProperty.Register("Target", typeof(Control), typeof(SetFocusAction), new PropertyMetadata(null)); 

     public Control Target { 
      get { return (Control) GetValue(TargetProperty); } 
      set { SetValue(TargetProperty, value); } 
     } 

     protected override void Invoke(object parameter) { 
      if(Target != null) { 
       Target.Focus(); 
      } 
     } 
    } 
} 

そしてそうのようにそれをフックアップ:あなたが最初にそれにこれでアプリを実行するとSilverlightのオブジェクト自体が持っていないことを

<UserControl x:Class="SilverlightApplication1.MainPage" 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    xmlns:sdk="http://schemas.microsoft.com/winfx/2006/xaml/presentation/sdk" 
    xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity" 
    xmlns:local="clr-namespace:SilverlightApplication1"> 
    <Grid x:Name="LayoutRoot"> 
     <sdk:TabControl> 
      <sdk:TabItem Header="Tab 1"> 
       <Grid> 
        <i:Interaction.Triggers> 
         <i:EventTrigger EventName="Loaded"> 
          <local:SetFocusAction Target="{Binding ElementName=tb1}"></local:SetFocusAction> 
         </i:EventTrigger> 
        </i:Interaction.Triggers> 
        <TextBox Width="200" Height="30" x:Name="tb1"></TextBox> 
       </Grid> 
      </sdk:TabItem> 
      <sdk:TabItem Header="Tab 2"> 
       <Grid> 
        <i:Interaction.Triggers> 
         <i:EventTrigger EventName="Loaded"> 
          <local:SetFocusAction Target="{Binding ElementName=tb2}"></local:SetFocusAction> 
         </i:EventTrigger> 
        </i:Interaction.Triggers> 
        <TextBox Width="200" Height="30" x:Name="tb2"></TextBox> 
       </Grid> 
      </sdk:TabItem> 
     </sdk:TabControl> 
    </Grid> 
</UserControl> 

注意あなたは手動でフォーカスするためにjavascriptをフックする必要があります。しかし、ユーザーがSilverlightアプリをクリックする(またはJavaScriptがフォーカスを合わせる)と、このアクションはその仕事をします。

楽しくは、データフォームで動作する他のテンプレートコントロールで動作する完全なBehaviorサブクラスがあります。

using System; 
using System.Windows; 
using System.Windows.Controls; 
using System.Windows.Interactivity; 
using System.Windows.Media; 

namespace SilverlightApplication1 { 
    public class SetFocusBehavior : Behavior<FrameworkElement> { 
     public static readonly DependencyProperty TargetNameProperty = 
      DependencyProperty.Register("TargetName", typeof(string), typeof(SetFocusBehavior), new PropertyMetadata(null)); 

     private bool _setFocusOnLayoutUpdated; 

     public string TargetName { 
      get { return (string) GetValue(TargetNameProperty); } 
      set { SetValue(TargetNameProperty, value); } 
     } 

     protected override void OnAttached() { 
      base.OnAttached(); 

      this.AssociatedObject.LayoutUpdated += new EventHandler(AssociatedObject_LayoutUpdated); 
      this.AssociatedObject.Loaded += new RoutedEventHandler(AssociatedObject_Loaded); 
     } 

     protected override void OnDetaching() { 
      base.OnDetaching(); 

      this.AssociatedObject.LayoutUpdated -= new EventHandler(AssociatedObject_LayoutUpdated); 
      this.AssociatedObject.Loaded -= new RoutedEventHandler(AssociatedObject_Loaded); 
     } 

     private void AssociatedObject_Loaded(object sender, RoutedEventArgs e) { 
      if(!FindAndSetFocus()) { 
       _setFocusOnLayoutUpdated = true; 
      } 
     } 

     private void AssociatedObject_LayoutUpdated(object sender, EventArgs e) { 
      if(_setFocusOnLayoutUpdated) { 
       _setFocusOnLayoutUpdated = false; 
       FindAndSetFocus(); 
      } 
     } 

     private bool FindAndSetFocus() { 
      var found = Find(this.AssociatedObject) as Control; 
      if(found != null) { 
       found.Focus(); 

       return true; 
      } 

      return false; 
     } 

     private DependencyObject Find(DependencyObject root) { 
      if(root != null) { 
       if((string) root.GetValue(FrameworkElement.NameProperty) == TargetName) { 
        return root; 
       } 

       for(int i = 0; i < VisualTreeHelper.GetChildrenCount(root); i++) { 
        var result = Find(VisualTreeHelper.GetChild(root, i)); 
        if(result != null) 
         return result; 
       } 
      } 
      return null; 
     } 
    } 
} 

とXAML:洞察に満ちた答えとコードスニペット用

<UserControl x:Class="SilverlightApplication1.MainPage" 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    xmlns:sdk="http://schemas.microsoft.com/winfx/2006/xaml/presentation/sdk" 
    xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity" 
    xmlns:tk="http://schemas.microsoft.com/winfx/2006/xaml/presentation/toolkit" 
    xmlns:local="clr-namespace:SilverlightApplication1"> 
    <Grid x:Name="LayoutRoot"> 
     <sdk:TabControl> 
      <sdk:TabItem Header="Tab 1"> 
       <Grid> 
        <i:Interaction.Behaviors> 
         <local:SetFocusBehavior TargetName="tb1"></local:SetFocusBehavior> 
        </i:Interaction.Behaviors> 
        <TextBox Width="200" Height="30" x:Name="tb1"></TextBox> 
       </Grid> 
      </sdk:TabItem> 
      <sdk:TabItem Header="Tab 2"> 
       <Grid> 
        <i:Interaction.Behaviors> 
         <local:SetFocusBehavior TargetName="tb2"></local:SetFocusBehavior> 
        </i:Interaction.Behaviors> 
        <tk:DataForm CurrentItem="sometext"> 
         <tk:DataForm.EditTemplate> 
          <DataTemplate> 
           <TextBox Width="200" Height="30" x:Name="tb2"></TextBox> 
          </DataTemplate> 
         </tk:DataForm.EditTemplate> 
        </tk:DataForm> 
       </Grid> 
      </sdk:TabItem> 
     </sdk:TabControl> 
    </Grid> 
</UserControl> 
+0

感謝。これは、TabItemの "直接"コントロールで効果的ですが、一部のTabItemでは、DataForm内のTextBoxにフォーカスを設定する必要があります。私はこれをDataFormID.FindNameInContentを使ってプログラムで行うことができますが、この種の機能をトリガーに組み込む方法はありますか? –

+0

すべてのテンプレートコントロール(DataFormなど)が問題を起こすでしょう。 VisualTreeHelperを使用して指定された名前を再帰的に検索するアクションを変更することはできますが、テンプレートは必ずLoadedによって準備されるわけではないので、LayoutUpdatedに接続する必要がありますロードされたイベントコールごとに)。 –

+0

DataFormで動作するバージョンを追加しました。 –

関連する問題