2009-06-12 8 views
6

この例のウィンドウでは、最初のテキストボックスから最後のテキストボックスに、次に展開ヘッダーにタブインスルーします。WPFエクスパンダーコントロールでTabIndexを設定するにはどうすればよいですか?

<Window x:Class="ExpanderTab.Window1" 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    Title="Window1" Height="300" Width="300" 
    FocusManager.FocusedElement="{Binding ElementName=FirstField}"> 
    <StackPanel> 
     <TextBox TabIndex="10" Name="FirstField"></TextBox> 
     <Expander TabIndex="20" Header="_abc"> 
      <TextBox TabIndex="30"></TextBox> 
     </Expander> 
     <TextBox TabIndex="40"></TextBox> 
    </StackPanel> 
</Window> 

明らかに、これは最初のテキストボックス、エキスパンダーヘッダー、最後のテキストボックスに行きたいと思います。 TabIndexをエキスパンダーのヘッダーに割り当てる簡単な方法はありますか?

KeyboardNavigation.IsTabStop="True"を使用してエキスパンダーをタブストップにしようとしましたが、エキスパータ全体がフォーカスを取得し、エキスパンダー全体がスペースバーに反応しません。さらに2つのタブの後、ヘッダーが再び選択され、スペースバーで開くことができます。

編集: これを行うためのよりクリーンな方法を考え出すことができる人のために、私は恩恵を受けるでしょう - そうでなければ、rmoore、あなたは担当者を持つことができます。ご協力いただきありがとうございます。

+0

が、それは絶対的な獣です。あなたが言ったように、良い方法があるはずです。 – jjxtra

答えて

10

次のコードがしますがTabIndexプロパティがなくても動作しますが、期待されるタブ順序を明確にするために含まれています。

<Window x:Class="ExpanderTab.Window1" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="Window1" Height="300" Width="300" FocusManager.FocusedElement="{Binding ElementName=FirstField}"> 
    <StackPanel> 
     <TextBox TabIndex="10" Name="FirstField"></TextBox> 
     <Expander TabIndex="20" Header="Section1" KeyboardNavigation.TabNavigation="Local"> 
      <StackPanel KeyboardNavigation.TabNavigation="Local"> 
       <TextBox TabIndex="30"></TextBox> 
       <TextBox TabIndex="40"></TextBox> 
      </StackPanel> 
     </Expander> 
     <Expander TabIndex="50" Header="Section2" KeyboardNavigation.TabNavigation="Local"> 
      <StackPanel KeyboardNavigation.TabNavigation="Local"> 
       <TextBox TabIndex="60"></TextBox> 
       <TextBox TabIndex="70"></TextBox> 
      </StackPanel> 
     </Expander> 
     <TextBox TabIndex="80"></TextBox> 
    </StackPanel> 
</Window> 
私はあなたがええ、私は自分のControlTemplateで遊んでてきた
+0

非常にクールな、それは同様に展開時にTabIndexを尊重する方法はありますか? – rmoore

+0

私はそれを調べて、この回答を更新します。 – jjxtra

+0

これまでのところとても良いです! – Eclipse

3

私は方法を見つけましたが、もっと良いものがあるはずです。


Expander through Moleを見るか、Blendによって生成されたControlTemplateを見ると、Space/Enter/Click/etcに応答しているヘッダー部分が本当にToggleButtonであることがわかります。今や悪いニュースです。ヘッダーのToggleButtonにはExpanderのExpandedプロパティの異なるレイアウトがあるため、ExpanderのControlTemplateを使用して既にスタイルが割り当てられています。これはExpanderのリソースでデフォルトのToggleButtonスタイルを作成するような簡単なことを私たちに排除します。あなたが背後にあるコードへのアクセス権を持っている、またはエクスパンダがであることをリソースディクショナリに分離コードを追加する気にしないならば、あなたはトグルボタンにアクセスし、エキスパンダーでのTabIndexを設定することができます

alt text http://i44.tinypic.com/2dlq1pl.png

<Expander x:Name="uiExpander" 
      Header="_abc" 
      Loaded="uiExpander_Loaded" 
      TabIndex="20" 
      IsTabStop="False"> 
    <TextBox TabIndex="30"> 

    </TextBox> 
</Expander> 


private void uiExpander_Loaded(object sender, RoutedEventArgs e) 
{ 
    //Gets the HeaderSite part of the default ControlTemplate for an Expander. 
    var header = uiExpander.Template.FindName("HeaderSite", uiExpander) as Control; 
    if (header != null) 
    { 
     header.TabIndex = uiExpander.TabIndex; 
    } 
} 

あなたはまた、単に経験に送信者のオブジェクトをキャストすることができます。このようにロードされたイベント、複数のエクスパンダで動作する必要がある場合は、 もう一つのオプションは、Expanderのための独自のControlTemplateを作成し、そこに設定することです。

我々はまた、それは非常にクリーンで使いやすく、AttachedPropertyにコード部分を移動することができ EDIT:

<Expander local:ExpanderHelper.HeaderTabIndex="20"> 
    ... 
</Expander> 

そしてAttachedProperty:

public class ExpanderHelper 
{ 
    public static int GetHeaderTabIndex(DependencyObject obj) 
    { 
     return (int)obj.GetValue(HeaderTabIndexProperty); 
    } 

    public static void SetHeaderTabIndex(DependencyObject obj, int value) 
    { 
     obj.SetValue(HeaderTabIndexProperty, value); 
    } 

    // Using a DependencyProperty as the backing store for HeaderTabIndex. This enables animation, styling, binding, etc... 
    public static readonly DependencyProperty HeaderTabIndexProperty = 
     DependencyProperty.RegisterAttached(
     "HeaderTabIndex", 
     typeof(int), 
     typeof(ExpanderHelper), 
     new FrameworkPropertyMetadata(
      int.MaxValue, 
      FrameworkPropertyMetadataOptions.None, 
      new PropertyChangedCallback(OnHeaderTabIndexChanged))); 

    private static void OnHeaderTabIndexChanged(DependencyObject o, DependencyPropertyChangedEventArgs e) 
    { 
     var expander = o as Expander; 
     int index; 

     if (expander != null && int.TryParse(e.NewValue.ToString(), out index)) 
     { 
      if (expander.IsLoaded) 
      { 
       SetTabIndex(expander, (int)e.NewValue); 
      } 
      else 
      { 
       // If the Expander is not yet loaded, then the Header will not be costructed 
       // To avoid getting a null refrence to the HeaderSite control part we 
       // can delay the setting of the HeaderTabIndex untill after the Expander is loaded. 
       expander.Loaded += new RoutedEventHandler((i, j) => SetTabIndex(expander, (int)e.NewValue)); 
      } 
     } 
     else 
     { 
      throw new InvalidCastException(); 
     } 
    } 

    private static void SetTabIndex(Expander expander, int index) 
    { 
     //Gets the HeaderSite part of the default ControlTemplate for an Expander. 
     var header = expander.Template.FindName("HeaderSite", expander) as Control; 
     if (header != null) 
     { 
      header.TabIndex = index; 
     } 
    } 
} 
+0

たいすべてを行うために私の答えを更新し – Eclipse

関連する問題