2009-06-12 4 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"을 사용하여 탭 스톱이되도록했으나 전체 확장기가 포커스를 얻게되어 전체 확장기가 스페이스 바에 반응하지 않습니다. 두 번 더 탭을 누르면 머리글이 다시 선택되고 스페이스 바를 사용하여 열 수 있습니다.

편집 : 나는 이것을 할 수있는 더 깨끗한 방법을 생각해 낼 수있는 사람을 위해 현상금을 던질 것입니다. 그렇지 않다면, 당신은 담당자를 가질 수 있습니다. 당신의 도움을 주셔서 감사합니다.

+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> 
+0

아주 멋지다, 확장했을 때 TabIndex를 존중할 수있는 방법이 있습니까? – rmoore

+0

나는 그것을 조사해보고 일단이 대답을 업데이트 할 것입니다. – jjxtra

+0

아주 좋은 지금까지! – Eclipse

3

나는 길을 찾았지만 더 나은 것이 있어야합니다.


Expander through Mole을 보거나 Blend에서 생성 한 ControlTemplate을 보면 Space/Enter/Click/etc에 응답하는 헤더 부분이 실제로 ToggleButton이라는 것을 알 수 있습니다. 이제 나쁜 소식입니다. Header의 ToggleButton에는 Expander의 Expanded 속성에 대한 다른 레이아웃이 있으므로 Up/Down/Left/Right에는 이미 Expander의 ControlTemplate을 통해 스타일이 할당되어 있습니다. Expander 's Resources에서 기본 ToggleButton 스타일을 만드는 것과 같은 간단한 작업을 수행 할 수 없게됩니다. 당신은 뒤에 코드에 액세스 할 수, 또는 확장기가있는 것을 리소스 사전에 숨김을 추가 괜찮다면

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

는, 당신은 ToggleButton을 액세스하고 확장기에 tabIndex를 설정할 수 있습니다. 이 같은로드 이벤트 :

<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 (s)에 대한 고유 한 ControlTemplate을 만들고 거기에 설정하는 것입니다.

우리는 또한 훨씬 깨끗하고 쉽게 사용할 수 있도록, AttachedProperty에 코드 부분을 이동할 수 있습니다 편집 :

<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

예, 저는 제 자신의 ControlTemplate을 가지고 놀았지만 절대적인 짐승입니다. 당신이 말했듯이, 더 좋은 방법이 있어야합니다. – Eclipse

관련 문제