zoukankan      html  css  js  c++  java
  • 重写TreeView,自定义图标,生成通行的下划线,取消默认获得焦点失去焦点的效果,并支持拖拽节点到外界

    1、运行效果:

    2、前端代码

     1 <UserControl x:Class="iPIS.UI.Base.Tree.VideoTreeControl"
     2              xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
     3              xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
     4              xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
     5              xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
     6              xmlns:local="clr-namespace:iPIS.UI.Base.Tree"
     7              mc:Ignorable="d" 
     8              d:DesignHeight="50" d:DesignWidth="80">
     9     <UserControl.Resources>
    10         <ResourceDictionary>
    11             <ResourceDictionary.MergedDictionaries>
    12                 <ResourceDictionary Source="/iPIS.UI.Themes.Black;component/Base/Tree/VideoTreeControlImages.xaml"/>
    13             </ResourceDictionary.MergedDictionaries>
    14             <Style TargetType="TextBlock" x:Key="fontstyle">
    15                 <Setter Property="Foreground" Value="{Binding RelativeSource={RelativeSource Mode=FindAncestor,AncestorType=local:VideoTreeControl},Path=VideoTreeControlFontColor}"></Setter>
    16                 <Setter Property="FontSize" Value="14"></Setter>
    17                 <Setter Property="VerticalAlignment" Value="Center"></Setter>
    18             </Style>
    19         </ResourceDictionary>
    20     </UserControl.Resources>
    21     <Grid>
    22         <TreeView x:Name="tree" 
    23               AllowDrop="True" 
    24               ItemsSource="{Binding DataList}"                  
    25               Background="{Binding RelativeSource={RelativeSource Mode=FindAncestor,AncestorType=local:VideoTreeControl},Path=VideoTreeControlBackground}"
    26               >
    27             <TreeView.ItemTemplate>
    28                 <HierarchicalDataTemplate ItemsSource="{Binding Children}">
    29                     <Grid x:Name="grid"
    30                           Margin="-1 0 0 0" 
    31                           Background="{Binding RelativeSource={RelativeSource Mode=FindAncestor,AncestorType=local:VideoTreeControl},Path=VideoTreeControlBackground}"
    32                           >
    33                         <StackPanel Grid.Column="1" 
    34                                     Orientation="Horizontal" 
    35                                     Cursor="Hand" 
    36                                     Height="40"
    37                                     VerticalAlignment="Center"
    38                                 >
    39                             <Image x:Name="icon" Width="19" Height="16" VerticalAlignment="Center" Margin="0 0 5 0"></Image>
    40                             <TextBlock Text="{Binding Text}" Style="{StaticResource fontstyle}"></TextBlock>
    41                             <StackPanel x:Name="cc" 
    42                                         Orientation="Horizontal" 
    43                                         Visibility="Collapsed"
    44                                         Margin="0 0 -1 0"
    45                                         Background="{Binding RelativeSource={RelativeSource Mode=FindAncestor,AncestorType=local:VideoTreeControl},Path=VideoTreeControlBackground}"
    46                                         >
    47                                 <TextBlock Style="{StaticResource fontstyle}">(</TextBlock>
    48                                 <TextBlock Text="{Binding FileCount}" Style="{StaticResource fontstyle}"></TextBlock>
    49                                 <TextBlock Style="{StaticResource fontstyle}">)</TextBlock>
    50                             </StackPanel>
    51                         </StackPanel>
    52                         <!--模拟通行下划线-->
    53                         <Canvas>
    54                             <Line X1="0" Y1="39" X2="1000" Y2="39" Stroke="#4a4a4a" Margin="-500 0 0 0" StrokeThickness="1"></Line>
    55                         </Canvas>
    56                     </Grid>
    57                     <HierarchicalDataTemplate.Triggers>
    58                         <DataTrigger Binding="{Binding Type}" Value="-1">
    59                             <Setter TargetName="icon" Property="Source" Value="{StaticResource icon_default}"></Setter>
    60                         </DataTrigger>
    61                         <DataTrigger Binding="{Binding Type}" Value="0">
    62                             <Setter TargetName="icon" Property="Source" Value="{StaticResource icon_yuan}"></Setter>
    63                         </DataTrigger>
    64                         <DataTrigger Binding="{Binding Type}" Value="1">
    65                             <Setter TargetName="icon" Property="Source" Value="{StaticResource icon_pian}"></Setter>
    66                         </DataTrigger>
    67                         <DataTrigger Binding="{Binding Type}" Value="2">
    68                             <Setter TargetName="icon" Property="Source" Value="{StaticResource icon_xulie}"></Setter>
    69                         </DataTrigger>
    70                         <DataTrigger Binding="{Binding Type}" Value="-1">
    71                             <Setter TargetName="cc" Property="Visibility" Value="Visible"></Setter>
    72                         </DataTrigger>
    73                     </HierarchicalDataTemplate.Triggers>
    74                 </HierarchicalDataTemplate>
    75             </TreeView.ItemTemplate>
    76         </TreeView>
    77     </Grid>
    78 </UserControl>
    View Code

    3、控件的后台代码

      1 using iPIS.UI.Base.Model;
      2 using iPIS.UI.Base.ViewModel;
      3 using System;
      4 using System.Collections.Generic;
      5 using System.Linq;
      6 using System.Text;
      7 using System.Threading.Tasks;
      8 using System.Windows;
      9 using System.Windows.Controls;
     10 using System.Windows.Data;
     11 using System.Windows.Documents;
     12 using System.Windows.Input;
     13 using System.Windows.Media;
     14 using System.Windows.Media.Imaging;
     15 using System.Windows.Navigation;
     16 using System.Windows.Shapes;
     17 
     18 namespace iPIS.UI.Base.Tree
     19 {
     20     /// <summary>
     21     /// VideoTreeControl.xaml 的交互逻辑
     22     /// </summary>
     23     public partial class VideoTreeControl : UserControl
     24     {
     25         public VideoTreeControl()
     26         {
     27             InitializeComponent();
     28             this.DataContext = new VideoTreeControlViewModel();
     29             //默认样式
     30             VideoTreeControlBackground = "#36353a";
     31             VideoTreeControlFontColor = "#9a9a9a";
     32 
     33             tree.SelectedItemChanged += Tree_SelectedItemChanged;
     34             tree.MouseDoubleClick += Tree_MouseDoubleClick;
     35         }
     36 
     37         /// <summary>
     38         /// 上下文
     39         /// </summary>
     40         VideoTreeControlViewModel vm
     41         {
     42             get
     43             {
     44                 return this.DataContext as VideoTreeControlViewModel;
     45             }
     46         }
     47 
     48         /// <summary>
     49         /// 背景颜色
     50         /// </summary>
     51         public string VideoTreeControlBackground
     52         {
     53             get { return (string)GetValue(VideoTreeControlBackgroundProperty); }
     54             set { SetValue(VideoTreeControlBackgroundProperty, value); }
     55         }
     56 
     57         /// <summary>
     58         /// 字体颜色
     59         /// </summary>
     60         public string VideoTreeControlFontColor
     61         {
     62             get { return (string)GetValue(VideoTreeControlFontColorProperty); }
     63             set { SetValue(VideoTreeControlFontColorProperty, value); }
     64         }
     65 
     66         #region 附加属性
     67 
     68         public static readonly DependencyProperty VideoTreeControlFontColorProperty =
     69             DependencyProperty.Register("VideoTreeControlFontColor", typeof(string), typeof(VideoTreeControl), new PropertyMetadata(""));
     70 
     71         public static readonly DependencyProperty VideoTreeControlBackgroundProperty =
     72             DependencyProperty.Register("VideoTreeControlBackground", typeof(string), typeof(VideoTreeControl), new PropertyMetadata(""));
     73         #endregion
     74 
     75         #region 公开事件
     76         /// <summary>
     77         /// 双击节点
     78         /// </summary>
     79         public event EventHandler<VideoTreeControlItemModel> DoubleClickTreeItem;
     80 
     81         /// <summary>
     82         /// 节点选中变更
     83         /// </summary>
     84         public event EventHandler<VideoTreeControlItemModel> SelectedItemChanged;
     85         #endregion
     86 
     87         /// <summary>
     88         /// 选中时
     89         /// </summary>
     90         /// <param name="sender"></param>
     91         /// <param name="e"></param>
     92         private void Tree_SelectedItemChanged(object sender, RoutedPropertyChangedEventArgs<object> e)
     93         {
     94             var datamodel = e.NewValue as VideoTreeControlItemModel;
     95             if (datamodel.Type == VideoTreeControlItemType.Root) return;//过滤root
     96             SelectedItemChanged?.Invoke(vm, datamodel);
     97             //获取方式   e.Data.GetData(typeof(Base.Model.VideoTreeControlItemModel))
     98             DragDrop.DoDragDrop(sender as FrameworkElement, datamodel, DragDropEffects.Copy);
     99 
    100             /*
    101             DragDrop.DoDragDrop(sender as FrameworkElement, new ImageTreeControlImageModel()
    102             {
    103                 Text = "我是拖进来的",
    104                 Type = ImageTreeControlImageType.AlreadyMatting,
    105                 ImageSource = new BitmapImage(new Uri("D:\上传资源\xxx.png", UriKind.Absolute))
    106             }, DragDropEffects.Copy);
    107             */
    108         }
    109 
    110         /// <summary>
    111         /// 双击节点
    112         /// </summary>
    113         /// <param name="sender"></param>
    114         /// <param name="e"></param>
    115         private void Tree_MouseDoubleClick(object sender, MouseButtonEventArgs e)
    116         {
    117             var datamodel = tree.SelectedValue as VideoTreeControlItemModel;
    118             if (datamodel == null || datamodel.Type == VideoTreeControlItemType.Root) return;//过滤root
    119             DoubleClickTreeItem?.Invoke(vm, datamodel);
    120         }
    121     }
    122 }
    View Code

    4、控件的datacontext对象

     1 using iPIS.UI.Base.Model;
     2 using System;
     3 using System.Collections.Generic;
     4 using System.Collections.ObjectModel;
     5 using System.ComponentModel;
     6 using System.Linq;
     7 using System.Text;
     8 using System.Threading.Tasks;
     9 using System.Windows.Input;
    10 
    11 namespace iPIS.UI.Base.ViewModel
    12 {
    13     public class VideoTreeControlViewModel : INotifyPropertyChanged
    14     {
    15         public event PropertyChangedEventHandler PropertyChanged;
    16 
    17         private ObservableCollection<VideoTreeControlItemModel> _DataList;
    18 
    19         /// <summary>
    20         /// 数据源
    21         /// </summary>
    22         public ObservableCollection<VideoTreeControlItemModel> DataList
    23         {
    24             get => _DataList;
    25             set
    26             {
    27                 //检查是否有roo,不存在生成默认root
    28                 if (value.Where(c => c.Type == VideoTreeControlItemType.Root).Count() == 0)
    29                 {
    30                     _DataList = new ObservableCollection<VideoTreeControlItemModel>() {
    31                         new VideoTreeControlItemModel(){
    32                             Text = "默认",
    33                             Children = value,
    34                             Type = VideoTreeControlItemType.Root//标示为root
    35                         }
    36                     };
    37                 }
    38                 else
    39                     _DataList = value;
    40                 PropertyChanged?.Notify(() => this.DataList);
    41             }
    42         }
    43     }
    44 }
    View Code

    5、数据实体 

      1 using System;
      2 using System.Collections.Generic;
      3 using System.Collections.ObjectModel;
      4 using System.Linq;
      5 using System.Text;
      6 using System.Threading.Tasks;
      7 
      8 namespace iPIS.UI.Base.Model
      9 {
     10     /// <summary>
     11     /// 视频图片树状控件,数据映射实体
     12     /// </summary>
     13     public class VideoTreeControlItemModel
     14     {
     15         private string _id = string.Empty;
     16         /// <summary>
     17         /// 唯一标示符
     18         /// </summary>
     19         public string Id
     20         {
     21             get
     22             {
     23                 //如果调用者未显示给入唯一标识符,将默认生成一个唯一标识符
     24                 if (string.IsNullOrEmpty(_id)) _id = Guid.NewGuid().ToString();
     25                 return _id;
     26             }
     27             set
     28             {
     29                 _id = value;
     30             }
     31         }
     32 
     33         /// <summary>
     34         /// 显示值
     35         /// </summary>
     36         public string Text { get; set; }
     37 
     38         /// <summary>
     39         /// 绑定值
     40         /// </summary>
     41         public object Value { get; set; }
     42 
     43         /// <summary>
     44         /// 类型,-1:根;0:原始视频;1:片段
     45         /// </summary>
     46         public VideoTreeControlItemType Type { get; set; } = VideoTreeControlItemType.Original;
     47 
     48         /// <summary>
     49         /// 子集
     50         /// </summary>
     51         public ObservableCollection<VideoTreeControlItemModel> Children { get; set; } = new ObservableCollection<VideoTreeControlItemModel>();
     52 
     53         /// <summary>
     54         /// 文件个数,Type=root时有效
     55         /// </summary>
     56         public int FileCount
     57         {
     58             get
     59             {
     60                 if (Type != VideoTreeControlItemType.Root) return 0;
     61                 List<VideoTreeControlItemModel> outlist = new List<VideoTreeControlItemModel>();
     62                 GetFiles(this, outlist);
     63                 return outlist.Count;
     64             }
     65         }
     66 
     67         /// <summary>
     68         /// 获取当前model下所有的文件实体,包含自己
     69         /// </summary>
     70         /// <param name="model">指定的对象</param>
     71         /// <param name="outlist">匹配到的从这里返回</param>
     72         private void GetFiles(VideoTreeControlItemModel model, List<VideoTreeControlItemModel> outlist)
     73         {
     74             if (outlist == null) outlist = new List<VideoTreeControlItemModel>();
     75 
     76             if (model.Type != VideoTreeControlItemType.Root)
     77             {
     78                 outlist.Add(model);
     79             }
     80             foreach (var item in model.Children)
     81             {
     82                 GetFiles(item, outlist);
     83             }
     84         }
     85     }
     86 
     87     /// <summary>
     88     /// 视频树,子项类型
     89     /// </summary>
     90     public enum VideoTreeControlItemType
     91     {
     92         /// <summary>
     93         /// 94         /// </summary>
     95         Root = -1,
     96         /// <summary>
     97         /// 原始视频
     98         /// </summary>
     99         Original = 0,
    100         /// <summary>
    101         /// 片段
    102         /// </summary>
    103         Fragment = 1,
    104         /// <summary>
    105         /// 序列化
    106         /// </summary>
    107         Sequence = 2
    108     }
    109 }
    View Code

    上面是完整效果的全部源码,下面我讲介绍我在封装的时候遇到的问题,并附上解决方案

    1、如何自定义图标

    答:系统内置一些图标在资源里面,通过属性值绑定不同的图片,因为图标总共就3个所有无需调用者指定,直接内置,通过类型区分匹配即可

    下面圈注关键代码

    2、如何生成通行的分割线

    答:通过Canvas来画线,线条尽可能的长,已达到通行的效果,并且还要距左为负数,已抵消数字控件的子集缩进

    附上关键代码

    3、自定义树的背景效果加上上,发现一个很囧的问题,获得焦点和失去焦点的节点背景很丑,默认获得焦点是蓝色背景,失去焦点是白色背景,欧码噶

    答:肯定是要干掉,必须干掉

    附上关键代码

    4、由于问题3,又新出一个诡异的问题,就是遮挡不完全,会出现一个1-2像素的竖线,经过调试查看发现是节点内置了border导致的,然后这个又没办法重写掉

    答:几经周折,发现利用Margin可以抵消,真是大快人心

    附上bug图

    这是获得焦点

    这是失去焦点

    解决的关键代码

  • 相关阅读:
    Linux防火墙--iptables学习
    LVS持久化
    LVS管理工具--ipvsadm
    Linux负载均衡--LVS(IPVS)
    一步步学习python
    驱动工程师需要的技能
    红外图像盲元补偿matlab实现源码与效果验证
    红外图像非均匀矫正——两点矫正
    夏日炎炎 python写个天气预报
    解决OV系列摄像头寄存器读数据无法收到的问题
  • 原文地址:https://www.cnblogs.com/xuling-297769461/p/9327712.html
Copyright © 2011-2022 走看看