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圖
這是獲得焦點
這