如何让文本框填充树视图项
How to get textbox to fill a treeview item
我有一个 TreeView,其中有 3 个级别,由 HierarchicalDataTemplate
驱动。这是部分 xaml 清单:
<TreeView
Name="TreeView"
ItemsSource="{Binding GTOs}"
ScrollViewer.HorizontalScrollBarVisibility="Hidden">
<TreeView.ItemsPanel>
<ItemsPanelTemplate>
<!-- This binding prevents the TreeView from slipping over to the right when an item is clicked. -->
<StackPanel MaxWidth="{Binding ActualWidth, RelativeSource={RelativeSource AncestorType=ContentPresenter, AncestorLevel=1}}" />
</ItemsPanelTemplate>
</TreeView.ItemsPanel>
<TreeView.Resources>
<HierarchicalDataTemplate DataType="{x:Type local:TreeGTOViewModel}" ItemsSource="{Binding Children}">
<TextBlock
Width="{Binding RelativeSource={RelativeSource AncestorType={x:Type TreeView}}, Path=ActualWidth}"
MouseDown="TextBlock_MouseDown"
Tag="{Binding Uri}"
Text="{Binding Title}" />
</HierarchicalDataTemplate>
TextBlock 的 Width
属性上的 Binding
确保每个 TreeViewItem
都采用 TreeView 容器的整个宽度(而不仅仅是文本框的宽度)。结合 Material 设计样式,当鼠标悬停在树中的特定项目上时,这会产生很好的阴影效果。
只有一个问题。虽然我可以让宽度假定 TreeViewItem 的整个宽度,但我似乎无法对高度做同样的事情。这意味着用户可以在 TreeView 项目的边缘附近单击并查看所有效果,就像单击该项目一样,但不会触发 MouseDown
事件。
这是应该可点击的区域(红色虚线):
这是实际可点击的区域(文本框的外边框):
我尝试了多种不同的方法,包括这个:
VerticalAlignment="Stretch"
还有这个:
Height="{Binding RelativeSource={RelativeSource AncestorType={x:Type TreeViewItem}}, Path=ActualHeight}"
但它们要么没有效果,要么以意想不到的方式破坏了 TreeView。我认为部分问题是 ItemsPanelTemplate
中使用的 StackPanel 通常的高度怪异。
如何让每个 TreeViewItem 中的 TextBox 假定实际 TreeViewItem 的高度?
下面是可视化树相关部分的图像,从 TreeView 到可点击的文本框。 Ripple
元素是一个 MaterialDesignThemes.Wpf.Ripple
对象。
好吧,我通过不同的途径解决了这个问题。我不在文本块上挂钩 MouseDown
事件,而是在树视图上挂钩 SelectedItemChanged
事件。
<TreeView
ItemsSource="{Binding GTOs}"
SelectedItemChanged="TreeView_SelectedItemChanged">
SelectedItemChanged
事件的 RoutedPropertyChangedEventArgs
包含特定 TreeViewItem
的 ViewModel,它产生了导航所需的 Uri 属性(我之前绑定了这个属性 到文本框的标签 属性).
新的事件处理程序如下所示:
private void TreeView_SelectedItemChanged(object sender, RoutedPropertyChangedEventArgs<object> e)
{
dynamic viewModel = e.NewValue;
var uri = viewModel.Uri;
(DataContext as TreeViewModel).Navigate(uri);
}
树的每一层都包含不同的 ViewModel 类型,但它们都有一个 Uri 属性,因此 dynamic
绑定提供了所需的 "don't care what type it is" 行为。
我现在可以从 TextBlock 中删除 Tag
绑定和 MouseDown
事件。
<HierarchicalDataTemplate DataType="{x:Type local:TreeGTOViewModel}" ItemsSource="{Binding Children}">
<TextBlock
Width="{Binding RelativeSource={RelativeSource AncestorType={x:Type TreeView}}, Path=ActualWidth}"
Text="{Binding Title}" />
树视图项现在可以正确响应,无论在何处单击它们。
我制作了一个非常简单的 MahApp 测试项目,其中包含一个 treeview 和一个 treeviewitem(无绑定)。
在实时可视化树中,PART_Header 的 VerticalAlignment 值为 Center。如果我将其更改为 Stretch(使用 Live 属性 Explorer),文本块会垂直填充 space。
因此,我使用 VS 中的文档大纲来编辑树视图模板的副本。在里面,我看到了 <Setter Property="VerticalContentAlignment" Value="Center">
,所以我决定在我的 TreeView 上将它设置为 Stretch,它似乎起作用了。
<TreeView x:Name="TreeView"
ScrollViewer.HorizontalScrollBarVisibility="Hidden"
VerticalContentAlignment="Stretch">
我有一个 TreeView,其中有 3 个级别,由 HierarchicalDataTemplate
驱动。这是部分 xaml 清单:
<TreeView
Name="TreeView"
ItemsSource="{Binding GTOs}"
ScrollViewer.HorizontalScrollBarVisibility="Hidden">
<TreeView.ItemsPanel>
<ItemsPanelTemplate>
<!-- This binding prevents the TreeView from slipping over to the right when an item is clicked. -->
<StackPanel MaxWidth="{Binding ActualWidth, RelativeSource={RelativeSource AncestorType=ContentPresenter, AncestorLevel=1}}" />
</ItemsPanelTemplate>
</TreeView.ItemsPanel>
<TreeView.Resources>
<HierarchicalDataTemplate DataType="{x:Type local:TreeGTOViewModel}" ItemsSource="{Binding Children}">
<TextBlock
Width="{Binding RelativeSource={RelativeSource AncestorType={x:Type TreeView}}, Path=ActualWidth}"
MouseDown="TextBlock_MouseDown"
Tag="{Binding Uri}"
Text="{Binding Title}" />
</HierarchicalDataTemplate>
TextBlock 的 Width
属性上的 Binding
确保每个 TreeViewItem
都采用 TreeView 容器的整个宽度(而不仅仅是文本框的宽度)。结合 Material 设计样式,当鼠标悬停在树中的特定项目上时,这会产生很好的阴影效果。
只有一个问题。虽然我可以让宽度假定 TreeViewItem 的整个宽度,但我似乎无法对高度做同样的事情。这意味着用户可以在 TreeView 项目的边缘附近单击并查看所有效果,就像单击该项目一样,但不会触发 MouseDown
事件。
这是应该可点击的区域(红色虚线):
这是实际可点击的区域(文本框的外边框):
我尝试了多种不同的方法,包括这个:
VerticalAlignment="Stretch"
还有这个:
Height="{Binding RelativeSource={RelativeSource AncestorType={x:Type TreeViewItem}}, Path=ActualHeight}"
但它们要么没有效果,要么以意想不到的方式破坏了 TreeView。我认为部分问题是 ItemsPanelTemplate
中使用的 StackPanel 通常的高度怪异。
如何让每个 TreeViewItem 中的 TextBox 假定实际 TreeViewItem 的高度?
下面是可视化树相关部分的图像,从 TreeView 到可点击的文本框。 Ripple
元素是一个 MaterialDesignThemes.Wpf.Ripple
对象。
好吧,我通过不同的途径解决了这个问题。我不在文本块上挂钩 MouseDown
事件,而是在树视图上挂钩 SelectedItemChanged
事件。
<TreeView
ItemsSource="{Binding GTOs}"
SelectedItemChanged="TreeView_SelectedItemChanged">
SelectedItemChanged
事件的 RoutedPropertyChangedEventArgs
包含特定 TreeViewItem
的 ViewModel,它产生了导航所需的 Uri 属性(我之前绑定了这个属性 到文本框的标签 属性).
新的事件处理程序如下所示:
private void TreeView_SelectedItemChanged(object sender, RoutedPropertyChangedEventArgs<object> e)
{
dynamic viewModel = e.NewValue;
var uri = viewModel.Uri;
(DataContext as TreeViewModel).Navigate(uri);
}
树的每一层都包含不同的 ViewModel 类型,但它们都有一个 Uri 属性,因此 dynamic
绑定提供了所需的 "don't care what type it is" 行为。
我现在可以从 TextBlock 中删除 Tag
绑定和 MouseDown
事件。
<HierarchicalDataTemplate DataType="{x:Type local:TreeGTOViewModel}" ItemsSource="{Binding Children}">
<TextBlock
Width="{Binding RelativeSource={RelativeSource AncestorType={x:Type TreeView}}, Path=ActualWidth}"
Text="{Binding Title}" />
树视图项现在可以正确响应,无论在何处单击它们。
我制作了一个非常简单的 MahApp 测试项目,其中包含一个 treeview 和一个 treeviewitem(无绑定)。
在实时可视化树中,PART_Header 的 VerticalAlignment 值为 Center。如果我将其更改为 Stretch(使用 Live 属性 Explorer),文本块会垂直填充 space。
因此,我使用 VS 中的文档大纲来编辑树视图模板的副本。在里面,我看到了 <Setter Property="VerticalContentAlignment" Value="Center">
,所以我决定在我的 TreeView 上将它设置为 Stretch,它似乎起作用了。
<TreeView x:Name="TreeView"
ScrollViewer.HorizontalScrollBarVisibility="Hidden"
VerticalContentAlignment="Stretch">