2010-05-27 7 views

Odpowiedz

5

Może nie jest to najbardziej eleganckie rozwiązanie, ale to działa:

static DependencyObject VisualUpwardSearch<T>(DependencyObject source) 
    { 
     while (source != null && source.GetType() != typeof(T)) 
      source = VisualTreeHelper.GetParent(source); 

     return source; 
    } 

następnie w TreeViewItem.Selected Handler:

 private void Treeview_Selected(object sender, RoutedEventArgs e) 
     { 
      var treeViewItem = VisualUpwardSearch<TreeViewItem>(e.OriginalSource as DependencyObject) as TreeViewItem; 
      if (treeViewItem != null) treeViewItem.IsExpanded = true; 
     } 

magia VisualUpwardSearch pochodzi stąd: Select TreeView Node on right click before displaying ContextMenu

Pozdrowienia

+0

wpadając bardzo starą odpowiedź. Próbuję tego rozwiązania, ale mam etykietę z AccessText i otrzymuję element System.Windows.Documents.Run jako OriginalSource. Nie jest to element wizualny ani wizualny3d, a zatem GetParent zgłasza wyjątek. Masz pomysł, jak sobie z tym poradzić? –

15

Miałem ten sam problem i f Dobre rozwiązanie dzięki another StackOverflow post.

W elementu TreeView w control.xaml, można podpiąć bezpośrednio do wybranego wydarzenia TreeViewItem za:

<TreeView ItemsSource="{StaticResource Array}" TreeViewItem.Selected="TreeViewItem_Selected"/> 

Następnie w kodzie control.xaml.cs tyle, że można pobrać wybrany TreeViewItem z RoutedEventArgs i ustaw tę opcję na IsExpanded:

private void TreeViewItem_Selected(object sender, RoutedEventArgs e) 
{ 
    TreeViewItem tvi = e.OriginalSource as TreeViewItem; 

    if (tvi == null || e.Handled) return; 

    tvi.IsExpanded = !tvi.IsExpanded; 
    e.Handled = true; 
} 

Ładnie i czysto. Mam nadzieję, że to komuś pomaga!

+0

+1 dla kodu XAML. Idealnie rozwiązany problem. (Tak samo jest z zaakceptowaną odpowiedzią (którą również przegłosowałem)). –

+2

Moim zdaniem jest to najlepsza metoda! Jest tylko jedna wada: gdy spróbujesz zwinąć niewybrany element, klikając ikonę zwijania, zostanie on wybrany, a procedura obsługi zdarzenia nie zapakuje go. Musisz enkapsulować obsługę zdarzeń w 'if (! E.Handled) {...}' i ustawić 'e.Handled = true;' zaraz po przełączeniu właściwości 'IsExpanded'. – kroimon

+0

Inną kwestią związaną z tym jest to, że po kliknięciu już wybranego widoku drzewa nie zwija się ani nie rozwija. –

0

Przyjęte rozwiązanie ma dziwne zachowanie podczas nawigacji za pomocą klawiatury i nie zwija elementu, gdy jest już wybrany. Alternatywnie, po prostu wyprowadź nową klasę z TreeViewItem i nadpisz metodę MouseLeftButtonDown. Musisz również ustawić TreeView.ItemsSource na zbiorze swojej nowej klasy TreeViewItem.

protected override void OnMouseLeftButtonDown(System.Windows.Input.MouseButtonEventArgs e) 
{ 
    if (!e.Handled && base.IsEnabled) 
    { 
     this.IsExpanded = !this.IsExpanded; 
     e.Handled = true; 
    } 
    base.OnMouseLeftButtonDown(e); 
} 
2

Miałem ten sam problem i zrobiłem to z funkcją Functionnality, dzięki czemu nie trzeba obsługiwać zdarzenia.

I zdefiniowany styl dla TreeViewItem

<Style x:Key="{x:Type TreeViewItem}" TargetType="{x:Type TreeViewItem}"> 
    <!--<Setter Property="FocusVisualStyle" Value="{StaticResource TreeViewItemFocusVisual}"/>--> 
    <Setter Property="Template"> 
     <Setter.Value> 
      <ControlTemplate TargetType="{x:Type TreeViewItem}"> 
         <CheckBox Style="{StaticResource TreeViewItemCB}" IsChecked="{Binding Path=IsExpanded,Mode=OneWayToSource,RelativeSource={RelativeSource TemplatedParent}}" ClickMode="Press"> 
          <Grid Background="{StaticResource TreeViewItemBackground}" Margin="0"> 
          <Grid.RowDefinitions> 
           <RowDefinition Height="Auto"/> 
           <RowDefinition/> 
          </Grid.RowDefinitions> 
          <Border Name="Bd"> 
            <ContentPresenter x:Name="PART_Header" ContentSource="Header"/> 
          </Border> 
          <ItemsPresenter x:Name="ItemsHost" Grid.Row="1"/> 
          </Grid> 
         </CheckBox> 
      </ControlTemplate> 
     </Setter.Value> 
    </Setter> 
</Style> 

Ważną częścią jest do określonej pole wyboru w ControlTemplate i wiążące się z nim. Po zaznaczeniu elementu CheckBox element zostanie rozwinięty za pomocą jednego kliknięcia.

<CheckBox Style="{StaticResource TreeViewItemCB}" IsChecked="{Binding Path=IsExpanded,Mode=OneWayToSource,RelativeSource={RelativeSource TemplatedParent}}" ClickMode="Press"> 

Jest to styl pola wyboru, który rozciąga się i nie wyświetla okna z obrysem.

<Style x:Key="TreeViewItemCB" TargetType="CheckBox" BasedOn="{StaticResource baseStyle}"> 
    <Setter Property="SnapsToDevicePixels" Value="true"/> 
    <Setter Property="OverridesDefaultStyle" Value="true"/> 
    <Setter Property="KeyboardNavigation.TabNavigation" Value="None" /> 
    <Setter Property="Background" Value="Transparent"/> 
    <Setter Property="VerticalAlignment" Value="Stretch"/> 
    <Setter Property="HorizontalAlignment" Value="Stretch"/> 
    <Setter Property="Template"> 
     <Setter.Value> 
      <ControlTemplate TargetType="CheckBox"> 
       <ContentPresenter VerticalAlignment="Stretch" HorizontalAlignment="Stretch" RecognizesAccessKey="True"/> 
      </ControlTemplate> 
     </Setter.Value> 
    </Setter> 
</Style> 
+0

Wspaniałe rozwiązanie! – l33t

-1
<TreeView.ItemContainerStyle> 
    <Style TargetType="{x:Type TreeViewItem}"> 
    <Setter Property="Cursor" Value="Hand" /> 
    <EventSetter Event="MouseUp" Handler="TreeViewItem_Click"/> 
    </Style> 
</TreeView.ItemContainerStyle> 


private void TreeViewItem_Click(object sender, MouseButtonEventArgs e) 
     { 
      ((TreeViewItem) sender).IsExpanded = !((TreeViewItem) sender).IsExpanded; 
      Thread.Sleep(700); 
     } 

Oto odpowiedź, cieszyć się nim

Odpowiedź: Ali Rahimy

0

Innym approch byłoby użyć Załączone propperties.

public class VirtualOneClickExpandButtonBehavior : DependencyObject 
{ 
    public static bool GetEnabled(DependencyObject obj) 
    { 
     return (bool)obj.GetValue(EnabledProperty); 
    } 

    public static void SetEnabled(DependencyObject obj, bool value) 
    { 
     obj.SetValue(EnabledProperty, value); 
    } 


    public static readonly DependencyProperty EnabledProperty = 
     DependencyProperty.RegisterAttached("Enabled", typeof(bool), typeof(VirtualOneClickExpandButtonBehavior), 
      new UIPropertyMetadata(false, EnabledPropertyChangedCallback 
       )); 

    private static void EnabledPropertyChangedCallback(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs dependencyPropertyChangedEventArgs) 
    { 
     var treeView = dependencyObject as TreeView; 

     if (treeView == null) return; 

     treeView.MouseUp += TreeView_MouseUp; 
    } 

    private static void TreeView_MouseUp(object sender, System.Windows.Input.MouseButtonEventArgs e) 
    { 
     var treeViewItem = VisualUpwardSearch<TreeViewItem>(e.OriginalSource as DependencyObject) as TreeViewItem; 
     if (treeViewItem != null) treeViewItem.IsExpanded = !treeViewItem.IsExpanded; 
    } 

    static DependencyObject VisualUpwardSearch<T>(DependencyObject source) 
    { 
     while (source != null && source.GetType() != typeof(T)) 
      source = VisualTreeHelper.GetParent(source); 

     return source; 
    } 
} 

A następnie można go używać w ten sposób.

<TreeView controls:VirtualOneClickExpandButtonBehavior.Enabled="true" ItemsSource="{Binding HierarchicalModel}"/> 

Jest to dobry approch, jeśli używasz wzorca MVVM, ponieważ nie potrzebujesz codebehind.

I thaks do Markust dla jego VisualUpwardSearch (źródło DependencyObject)