【发布时间】:2019-05-24 16:58:09
【问题描述】:
现在您必须双击或单击 + 图标。如果用户点击它展开的节点上的任何位置,有什么办法可以做到这一点?
【问题讨论】:
现在您必须双击或单击 + 图标。如果用户点击它展开的节点上的任何位置,有什么办法可以做到这一点?
【问题讨论】:
感谢another StackOverflow post,我遇到了同样的问题并找到了一个很好的解决方案。
在control.xaml的TreeView元素中,可以直接hook到TreeViewItem的Selected事件中:
<TreeView ItemsSource="{StaticResource Array}" TreeViewItem.Selected="TreeViewItem_Selected"/>
然后在您的 control.xaml.cs 代码中,您可以从 RoutedEventArgs 中获取选定的 TreeViewItem 并将其设置为 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;
}
干净整洁。希望对某人有所帮助!
【讨论】:
if (!e.Handled) {...} 中封装事件处理程序,并在切换IsExpanded 属性后立即设置e.Handled = true;。
也许不是最优雅的解决方案,但这是可行的:
static DependencyObject VisualUpwardSearch<T>(DependencyObject source)
{
while (source != null && source.GetType() != typeof(T))
source = VisualTreeHelper.GetParent(source);
return source;
}
然后在 TreeViewItem.Selected 处理程序中:
private void Treeview_Selected(object sender, RoutedEventArgs e)
{
var treeViewItem = VisualUpwardSearch<TreeViewItem>(e.OriginalSource as DependencyObject) as TreeViewItem;
if (treeViewItem != null) treeViewItem.IsExpanded = true;
}
VisualUpwardSearch 魔法取自这里:Select TreeView Node on right click before displaying ContextMenu
问候
【讨论】:
我遇到了同样的问题,我使用样式功能做到了,这样您就不需要处理事件了。
我为 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>
重要的部分是在 ControlTemplate 中定义 checkBox 并与之绑定。勾选 CheckBox 后,项目一键展开。
<CheckBox Style="{StaticResource TreeViewItemCB}" IsChecked="{Binding Path=IsExpanded,Mode=OneWayToSource,RelativeSource={RelativeSource TemplatedParent}}" ClickMode="Press">
这是复选框的样式,因此它可以拉伸并且不显示带有笔划的框。
<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 提供了一个很好的答案。但是,如果您想展开或折叠已选择的项目,则它不起作用。为了改善这一点,您可以简单地添加: tvi.IsSelected = false; (如果您不关心项目是否处于选中状态。)
所以,整个代码如下所示:
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;
}
【讨论】:
另一种方法是使用附加属性。
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;
}
}
然后你就可以这样使用了。
<TreeView controls:VirtualOneClickExpandButtonBehavior.Enabled="true" ItemsSource="{Binding HierarchicalModel}"/>
如果您使用 MVVM 模式,这是一个很好的方法,因为您不需要代码隐藏。
感谢 Markust 的 VisualUpwardSearch(DependencyObject 源)
【讨论】:
当您使用键盘导航时,接受的解决方案会出现奇怪的行为,并且在项目已被选中时不会折叠它。或者,只需从 TreeViewItem 派生一个新类并覆盖 MouseLeftButtonDown 方法。您还需要将 TreeView.ItemsSource 设置为新 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);
}
【讨论】:
<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);
}
这就是答案,尽情享受吧
回答者:阿里·拉希米
【讨论】: