重寫TreeView,自定義圖標,生成通行的下劃線,取消預設獲得焦點失去焦點的效果,並支持拖拽節點到外界

来源:https://www.cnblogs.com/xuling-297769461/archive/2018/07/18/9327712.html
-Advertisement-
Play Games

1、運行效果: 2、前端代碼 1 <UserControl x:Class="iPIS.UI.Base.Tree.VideoTreeControl" 2 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 3 xmlns ...


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圖

這是獲得焦點

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...