开发者

How to expand WPF TreeView on single click of item

Right now you h开发者_如何转开发ave to double click or click the + icon. Is there any way to make it so if a user clicks anywhere on the node it expands?


I had this same problem and found a good solution thanks to another StackOverflow post.

In the control.xaml's TreeView element, you can hook directly into the TreeViewItem's Selected event:

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

Then in your control.xaml.cs code behind, you can grab that selected TreeViewItem from the RoutedEventArgs and set it to 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;
}

Nice and clean. Hopefully that helps someone!


Maybe is not the most elegant solution but this works:

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

        return source;
    }

then in the 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;
        }

the VisualUpwardSearch magic is taken from here: Select TreeView Node on right click before displaying ContextMenu

Regards


I had the same problem and I did it with the Style functionnality so that you don't need to handle the event.

I defined a style for the 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>

The important part is to defined the checkBox in the ControlTemplate and the binding with it. When the CheckBox is checked, the item will be expanded with just one click.

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

this is the style for the checkBox so that it stretches and doesn't display the box with the stroke.

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


@BJennings provided a great answer. However, if you want to expand or collapse an already selected item, it doesn't work. To improve that, you can simply add: tvi.IsSelected = false; (if you do not care whether the item is in a selected state.)

So, the whole codes look like this:

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

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

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


Another approch would be to use Attached 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;
    }
}

And then you can use it like this.

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

This is a good approch if you use the MVVM pattern because you don't need the codebehind.

And thaks to Markust for his VisualUpwardSearch(DependencyObject source)


The accepted solution has odd behaviour when you're navigating with the keyboard, and doesn't collapse the item when it's already selected. Alternatively, just derive a new class from TreeViewItem and override the MouseLeftButtonDown method. You also need to set your TreeView.ItemsSource to a collection of your new TreeViewItem class.

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


<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);
        }

Here is the answer, Enjoy it

Answer by: Ali Rahimy

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜