经过前两章文章所述,对treeview有了理解,那么我们就扩展它的应用范围,走起。
假设我遇见一个需求,如图所示
有个下拉框,每个子项还能继续分,这种需求用WPF怎么实现?
简单分析需求可知:下拉框—》ComboBox,子项还能分—》就是递归结构,我就想到用treeview。
那就写代码吧,还是老样子,基础的就不说了,如图
其中DelegateCommand和BindableObject 是上一篇的内容,这就不展示代码了。
public class TreeModel : BindableObject
{
private string name;
public string Name
{
get => name;
set
{
name = value;
OnPropertyChanged();
}
}
public ObservableCollection<TreeModel> Children { get; set; } = new ObservableCollection<TreeModel>();
}
结构很简单,就一个展示属性。
view代码如图所示,没什么难道,用到的也是上篇讲过的知识点(可能不懂的是ScrollViewer.CanContentScroll,如果是false,内容展示会有这种情况,一半展示,一半没展示,true则是,你不管怎么滑动,展示的内容都是完整的)
<Grid>
<ComboBox
Width="200"
Height="30"
HorizontalAlignment="Center"
VerticalContentAlignment="Center"
IsEditable="True"
IsReadOnly="True"
ScrollViewer.CanContentScroll="True"
ScrollViewer.VerticalScrollBarVisibility="Auto"
Text="{Binding SelectItem.Name, Mode=TwoWay}">
<ComboBoxItem MinHeight="40" MaxHeight="300">
<ComboBoxItem.Template>
<ControlTemplate>
<ComboBoxItem Width="210">
<TreeView
x:Name="tree"
Width="200"
ItemsSource="{Binding TreeModels}">
<i:Interaction.Triggers>
<i:EventTrigger EventName="SelectedItemChanged">
<i:InvokeCommandAction Command="{Binding DataContext.Selected, RelativeSource={RelativeSource AncestorType=Window, Mode=FindAncestor}}" CommandParameter="{Binding ElementName=tree}" />
</i:EventTrigger>
</i:Interaction.Triggers>
<TreeView.ItemTemplate>
<HierarchicalDataTemplate ItemsSource="{Binding Children}">
<TextBlock
Grid.Column="1"
HorizontalAlignment="Center"
VerticalAlignment="Center"
FontFamily="Palatino Linotype"
Text="{Binding Name}">
</TextBlock>
</HierarchicalDataTemplate>
</TreeView.ItemTemplate>
</TreeView>
</ComboBoxItem>
</ControlTemplate>
</ComboBoxItem.Template>
<ComboBoxItem />
</ComboBoxItem>
</ComboBox>
</Grid>
viewModel也一样简单,就不叙述了
public class MainViewModel : BindableObject
{
public ObservableCollection<TreeModel> TreeModels { get; set; } = new ObservableCollection<TreeModel>();
private TreeModel selectItem;
public TreeModel SelectItem
{
get => selectItem;
set
{
selectItem = value;
Console.WriteLine(SelectItem);
OnPropertyChanged();
}
}
public DelegateCommand<TreeView> Selected { get; private set; }
public MainViewModel()
{
Selected = new DelegateCommand<TreeView>(Tree_SelectedItemChanged);
CreateTree();
}
private void CreateTree()
{
for (int i = 0; i < 5; i++)
{
TreeModel treeModel = new TreeModel()
{
Name = $"我是{i}"
};
TreeModels.Add(treeModel);
for (int j = 0; j < 10; j++)
{
treeModel.Children.Add(new TreeModel()
{
Name = $"我是{i}的{j}个孩子"
});
}
}
}
public void Tree_SelectedItemChanged(TreeView view)
{
SelectItem = view.SelectedItem as TreeModel;
}
}
运行结果:
注意:
(1)在编写前端时,注意要在treeview外套一个ComboBoxItem ,原理是这样的,我是拿一个ComboBoxItem 来做下拉内容的展示,然后用ControlTemplate来重写了ComboBoxItem,也就是说,如果不套一个ComboBoxItem,直接用treeview,那么当你点击下拉框看见的内容,其实就是一个ComboBoxItem,那么根据平常的经验,一点下拉宽就消失了,而且展示的内容也会错,套了ComboBoxItem后,treeview其实就是ComboBoxItem的内容,不管你怎么点,都在一个ComboBoxItem中点击的,就不会触发到ComboBox的默认触发器(如果你不想套也可以去改ComboBox的默认模板)
赠一个小案例,wpf实现上下标
<TextBlock
Grid.Column="1"
HorizontalAlignment="Center"
VerticalAlignment="Center"
FontFamily="Palatino Linotype">
<Run Text="M" />
<Run BaselineAlignment="Subscript" Text="2" />
<Run BaselineAlignment="Superscript" Text="3" />
</TextBlock>
它的用途是做一些简单的符号,让用户下拉选中,就不需要用户去手输入了
(2)代码在这:https://github.com/TQtong/TreeViewExtensionApplication.git
结束
这次的内容就这么多,请各位多多批评指正