WPF控件之TreeView扩展应用(一)

         经过前两章文章所述,对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

结束

         这次的内容就这么多,请各位多多批评指正 

  • 5
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
WPF TreeView 件默认提供了展开/折叠图标和单个CheckBox选中功能,如果需要实现扩展图标和多选功能,可以通过自定义TreeViewItem样式来实现。 下面是一个简单的示例,展示如何在WPF TreeView中实现扩展图标和多选功能: 1. 创建一个自定义TreeViewItem样式,并在其中添加一个扩展图标和多选CheckBox: ``` <Style x:Key="TreeViewItemStyle" TargetType="{x:Type TreeViewItem}"> <Setter Property="Template"> <Setter.Value> <ControlTemplate TargetType="{x:Type TreeViewItem}"> <Grid> <Grid.ColumnDefinitions> <ColumnDefinition Width="Auto"/> <ColumnDefinition/> </Grid.ColumnDefinitions> <StackPanel Orientation="Horizontal" Grid.Column="0"> <Image x:Name="ExpandCollapseImage" Source="Expand.png" Width="16" Height="16" Margin="0,0,5,0" Visibility="Collapsed" /> <CheckBox x:Name="CheckBox" VerticalAlignment="Center" Margin="0,0,5,0"/> <ContentPresenter ContentSource="Header" /> </StackPanel> <ItemsPresenter Grid.Column="1" /> </Grid> <ControlTemplate.Triggers> <Trigger Property="IsExpanded" Value="True"> <Setter TargetName="ExpandCollapseImage" Property="Source" Value="Collapse.png" /> <Setter TargetName="ExpandCollapseImage" Property="Visibility" Value="Visible" /> </Trigger> <MultiTrigger> <MultiTrigger.Conditions> <Condition Property="IsSelected" Value="True"/> <Condition Property="IsSelectionActive" Value="True"/> </MultiTrigger.Conditions> <Setter TargetName="CheckBox" Property="IsChecked" Value="True"/> </MultiTrigger> </ControlTemplate.Triggers> </ControlTemplate> </Setter.Value> </Setter> </Style> ``` 2. 在TreeView应用自定义样式: ``` <TreeView x:Name="TreeView" ItemContainerStyle="{StaticResource TreeViewItemStyle}"> <!-- 树节点内容 --> </TreeView> ``` 3. 处理TreeViewItem的展开/折叠事件: ``` private void TreeViewItem_Expanded(object sender, RoutedEventArgs e) { TreeViewItem item = e.OriginalSource as TreeViewItem; if (item != null) { Image image = FindChild<Image>(item, "ExpandCollapseImage"); if (image != null) { image.Source = new BitmapImage(new Uri("Collapse.png", UriKind.Relative)); } } } private void TreeViewItem_Collapsed(object sender, RoutedEventArgs e) { TreeViewItem item = e.OriginalSource as TreeViewItem; if (item != null) { Image image = FindChild<Image>(item, "ExpandCollapseImage"); if (image != null) { image.Source = new BitmapImage(new Uri("Expand.png", UriKind.Relative)); } } } private T FindChild<T>(DependencyObject parent, string childName) where T : DependencyObject { if (parent == null) return null; T child = null; int childrenCount = VisualTreeHelper.GetChildrenCount(parent); for (int i = 0; i < childrenCount; i++) { DependencyObject childElement = VisualTreeHelper.GetChild(parent, i); if (childElement is T && ((FrameworkElement)childElement).Name == childName) { child = (T)childElement; break; } else { child = FindChild<T>(childElement, childName); if (child != null) break; } } return child; } ``` 4. 处理TreeViewItem的多选事件: ``` private void CheckBox_Click(object sender, RoutedEventArgs e) { TreeViewItem item = FindParent<TreeViewItem>(sender as DependencyObject); if (item != null) { // 获取父节点 TreeViewItem parentItem = FindParent<TreeViewItem>(item.Parent); if (parentItem != null) { // 获取所有子节点 List<TreeViewItem> childItems = new List<TreeViewItem>(); GetChildItems(parentItem, childItems); // 更新所有节点的多选状态 foreach (TreeViewItem childItem in childItems) { CheckBox checkBox = FindChild<CheckBox>(childItem, "CheckBox"); if (checkBox != null) { checkBox.IsChecked = GetChildCheckedState(parentItem); } } } } } private TreeViewItem FindParent<T>(DependencyObject child) where T : DependencyObject { if (child == null) return null; DependencyObject parent = VisualTreeHelper.GetParent(child); while (parent != null && !(parent is T)) { parent = VisualTreeHelper.GetParent(parent); } return parent as TreeViewItem; } private void GetChildItems(TreeViewItem item, List<TreeViewItem> childItems) { int childrenCount = VisualTreeHelper.GetChildrenCount(item); for (int i = 0; i < childrenCount; i++) { DependencyObject childElement = VisualTreeHelper.GetChild(item, i); if (childElement is TreeViewItem) { childItems.Add(childElement as TreeViewItem); GetChildItems(childElement as TreeViewItem, childItems); } } } private bool GetChildCheckedState(TreeViewItem parent) { int childrenCount = VisualTreeHelper.GetChildrenCount(parent); bool isChecked = false; for (int i = 0; i < childrenCount; i++) { DependencyObject childElement = VisualTreeHelper.GetChild(parent, i); if (childElement is TreeViewItem) { CheckBox checkBox = FindChild<CheckBox>(childElement as TreeViewItem, "CheckBox"); if (checkBox != null && checkBox.IsChecked == true) { isChecked = true; break; } else { isChecked = GetChildCheckedState(childElement as TreeViewItem); if (isChecked) break; } } } return isChecked; } ``` 通过以上步骤,我们就可以在WPF TreeView中实现扩展图标和多选功能了。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值