重写TreeView,多层级节点下批量显示图片,图片支持缩略图和文件名列表切换,支持调用者动态匹配选中,支持外界拖入图片并添加到对应节点下
1、先看下整体效果
2、前端代码
1 <UserControl x:Class="iPIS.UI.Base.Tree.ImageTreeControl" 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="45" 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="treename"> 15 <Setter Property="Foreground" Value="{Binding RelativeSource={RelativeSource Mode=FindAncestor,AncestorType=local:ImageTreeControl},Path=ImageTreeControlFontColor}"></Setter> 16 <Setter Property="FontSize" Value="14"></Setter> 17 </Style> 18 </ResourceDictionary> 19 </UserControl.Resources> 20 <TreeView x:Name="tree" 21 ItemsSource="{Binding DataList}" 22 Background="{Binding RelativeSource={RelativeSource Mode=FindAncestor,AncestorType=local:ImageTreeControl},Path=ImageTreeControlBackground}" 23 > 24 <TreeView.ItemTemplate> 25 <HierarchicalDataTemplate ItemsSource="{Binding Children}"> 26 <Grid Margin="-1 0 0 0" 27 Cursor="Hand" 28 Background="{Binding RelativeSource={RelativeSource Mode=FindAncestor,AncestorType=local:ImageTreeControl},Path=ImageTreeControlBackground}" 29 > 30 <StackPanel x:Name="Classify" Orientation="Horizontal"> 31 <Image Source="{Binding IconSource}" 32 Width="25" 33 Height="25" 34 VerticalAlignment="Center" 35 Margin="0 0 10 0" 36 ></Image> 37 <TextBlock Text="{Binding Text}" 38 VerticalAlignment="Center" 39 Style="{StaticResource treename}"> 40 </TextBlock> 41 <TextBlock Style="{StaticResource treename}" 42 VerticalAlignment="Center" 43 >(</TextBlock> 44 <TextBlock Text="{Binding ImagesCount}" 45 VerticalAlignment="Center" 46 Style="{StaticResource treename}" 47 ></TextBlock> 48 <TextBlock Style="{StaticResource treename}" 49 VerticalAlignment="Center" 50 >)</TextBlock> 51 </StackPanel> 52 <!--缩略图视图--> 53 <ListBox x:Name="Image_slt" 54 ItemsSource="{Binding Images}" 55 Visibility="Collapsed" 56 Width="{Binding RelativeSource={RelativeSource Mode=FindAncestor,AncestorType=local:ImageTreeControl},Path=ThumbnailWidth}" 57 Background="Transparent" 58 Margin="-35 0 0 0" 59 > 60 <ListBox.Template> 61 <ControlTemplate TargetType="{x:Type ListBox}"> 62 <ScrollViewer VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Disabled"> 63 <WrapPanel Orientation="Horizontal" IsItemsHost="True"></WrapPanel> 64 </ScrollViewer> 65 </ControlTemplate> 66 </ListBox.Template> 67 <ListBox.ItemTemplate> 68 <DataTemplate> 69 <Border x:Name="border" 70 BorderBrush="{Binding RelativeSource={RelativeSource Mode=FindAncestor,AncestorType=local:ImageTreeControl},Path=ImageTreeControlImageBoderColor}" 71 Background="{Binding RelativeSource={RelativeSource Mode=FindAncestor,AncestorType=local:ImageTreeControl},Path=ImageTreeControlImageBoderColor}" 72 BorderThickness="3" 73 Width="{Binding RelativeSource={RelativeSource Mode=FindAncestor,AncestorType=local:ImageTreeControl},Path=ImageTreeControlImageWidth}" 74 Height="{Binding RelativeSource={RelativeSource Mode=FindAncestor,AncestorType=local:ImageTreeControl},Path=ImageTreeControlImageHeight}" 75 > 76 <Grid> 77 <Image Source="{Binding ImageSource}" 78 Width="{Binding RelativeSource={RelativeSource Mode=FindAncestor,AncestorType=local:ImageTreeControl},Path=ImageTreeControlImageWidth}" 79 Height="{Binding RelativeSource={RelativeSource Mode=FindAncestor,AncestorType=local:ImageTreeControl},Path=ImageTreeControlImageHeight}" 80 ></Image> 81 <Image x:Name="icon" Visibility="Collapsed" Width="13" Height="14" Margin="-72 -50 0 0"></Image> 82 </Grid> 83 </Border> 84 <DataTemplate.Triggers> 85 <DataTrigger Binding="{Binding Type}" Value="1"> 86 <Setter TargetName="icon" Property="Visibility" Value="Visible"></Setter> 87 <Setter TargetName="icon" Property="Source" Value="{StaticResource icon_kou}"></Setter> 88 </DataTrigger> 89 <DataTrigger Binding="{Binding Type}" Value="2"> 90 <Setter TargetName="icon" Property="Visibility" Value="Visible"></Setter> 91 <Setter TargetName="icon" Property="Source" Value="{StaticResource icon_jiandao}"></Setter> 92 </DataTrigger> 93 <DataTrigger Binding="{Binding IsSelected}" Value="true"> 94 <Setter TargetName="border" 95 Property="BorderBrush" 96 Value="{Binding RelativeSource={RelativeSource Mode=FindAncestor,AncestorType=local:ImageTreeControl},Path=ImageTreeControlImageSelectedBoderColor}" 97 ></Setter> 98 </DataTrigger> 99 <Trigger Property="IsMouseOver" Value="true"> 100 <Setter TargetName="border" 101 Property="BorderBrush" 102 Value="{Binding RelativeSource={RelativeSource Mode=FindAncestor,AncestorType=local:ImageTreeControl},Path=ImageTreeControlImageMouseOverBoderColor}" 103 ></Setter> 104 </Trigger> 105 </DataTemplate.Triggers> 106 </DataTemplate> 107 </ListBox.ItemTemplate> 108 <ListBox.ItemContainerStyle> 109 <Style TargetType="ListBoxItem"> 110 <Setter Property="Padding" Value="0"></Setter> 111 <Setter Property="BorderThickness" Value="0"></Setter> 112 <Setter Property="Margin" Value="1"></Setter> 113 </Style> 114 </ListBox.ItemContainerStyle> 115 </ListBox> 116 <!--文件名视图--> 117 <ListBox x:Name="Image_file" 118 ItemsSource="{Binding Images}" 119 BorderThickness="0" 120 Background="Transparent" 121 Width="{Binding RelativeSource={RelativeSource Mode=FindAncestor,AncestorType=local:ImageTreeControl},Path=ListWidth}" 122 Margin="-35 0 0 0" 123 > 124 <ListBox.ItemTemplate> 125 <DataTemplate> 126 <TextBlock x:Name="text" 127 Text="{Binding Text}" 128 Foreground="{Binding RelativeSource={RelativeSource Mode=FindAncestor,AncestorType=local:ImageTreeControl},Path=ImageTreeControlImageImgNameColor}" 129 ></TextBlock> 130 <DataTemplate.Triggers> 131 <DataTrigger Binding="{Binding IsSelected}" Value="true"> 132 <Setter TargetName="text" 133 Property="Foreground" 134 Value="{Binding RelativeSource={RelativeSource Mode=FindAncestor,AncestorType=local:ImageTreeControl},Path=ImageTreeControlImageSelectedImgNameColor}" 135 ></Setter> 136 </DataTrigger> 137 </DataTemplate.Triggers> 138 </DataTemplate> 139 </ListBox.ItemTemplate> 140 </ListBox> 141 </Grid> 142 <HierarchicalDataTemplate.Triggers> 143 <DataTrigger Binding="{Binding Type}" Value="0"> 144 <Setter TargetName="Classify" Property="Visibility" Value="Visible"></Setter> 145 <Setter TargetName="Image_slt" Property="Visibility" Value="Collapsed"></Setter> 146 <Setter TargetName="Image_file" Property="Visibility" Value="Collapsed"></Setter> 147 </DataTrigger> 148 <DataTrigger Binding="{Binding Type}" Value="1"> 149 <Setter TargetName="Classify" Property="Visibility" Value="Collapsed"></Setter> 150 </DataTrigger> 151 <MultiDataTrigger> 152 <MultiDataTrigger.Conditions> 153 <Condition Binding="{Binding Type}" Value="1"></Condition> 154 <Condition Binding="{Binding RelativeSource={RelativeSource Mode=FindAncestor,AncestorType=local:ImageTreeControl},Path=ImageTreeControlViewState}" Value="0"></Condition> 155 </MultiDataTrigger.Conditions> 156 <Setter TargetName="Image_slt" Property="Visibility" Value="Collapsed"></Setter> 157 <Setter TargetName="Image_file" Property="Visibility" Value="Visible"></Setter> 158 </MultiDataTrigger> 159 <MultiDataTrigger> 160 <MultiDataTrigger.Conditions> 161 <Condition Binding="{Binding Type}" Value="1"></Condition> 162 <Condition Binding="{Binding RelativeSource={RelativeSource Mode=FindAncestor,AncestorType=local:ImageTreeControl},Path=ImageTreeControlViewState}" Value="1"></Condition> 163 </MultiDataTrigger.Conditions> 164 <Setter TargetName="Image_slt" Property="Visibility" Value="Visible"></Setter> 165 <Setter TargetName="Image_file" Property="Visibility" Value="Collapsed"></Setter> 166 </MultiDataTrigger> 167 </HierarchicalDataTemplate.Triggers> 168 169 </HierarchicalDataTemplate> 170 </TreeView.ItemTemplate> 171 </TreeView> 172 </UserControl>
3、控件后台代码
1 using iPIS.UI.Base.Model; 2 using iPIS.UI.Base.ViewModel; 3 using iPIS.Utility; 4 using System; 5 using System.Collections.Generic; 6 using System.Linq; 7 using System.Text; 8 using System.Threading.Tasks; 9 using System.Windows; 10 using System.Windows.Controls; 11 using System.Windows.Data; 12 using System.Windows.Documents; 13 using System.Windows.Input; 14 using System.Windows.Media; 15 using System.Windows.Media.Imaging; 16 using System.Windows.Navigation; 17 using System.Windows.Shapes; 18 19 namespace iPIS.UI.Base.Tree 20 { 21 /// <summary> 22 /// ImageTreeControl.xaml 的交互逻辑 23 /// </summary> 24 public partial class ImageTreeControl : UserControl 25 { 26 public ImageTreeControl() 27 { 28 InitializeComponent(); 29 var vm = new ImageTreeControlViewModel(this); 30 this.DataContext = vm; 31 this.PreviewDragOver += ImageTreeControl_PreviewDragOver; 32 this.PreviewDrop += ImageTreeControl_PreviewDrop; 33 this.SizeChanged += ImageTreeControl_SizeChanged; 34 35 //默认样式 36 ImageTreeControlViewState = 1; 37 ImageTreeControlImageWidth = 85; 38 ImageTreeControlImageHeight = 65; 39 ImageTreeControlBackground = "#36353a"; 40 ImageTreeControlFontColor = "#89888d"; 41 ImageTreeControlImageBoderColor = "#000000"; 42 ImageTreeControlImageSelectedBoderColor = "#019e97"; 43 ImageTreeControlImageMouseOverBoderColor = ImageTreeControlImageSelectedBoderColor; 44 ImageTreeControlImageImgNameColor = ImageTreeControlFontColor; 45 ImageTreeControlImageSelectedImgNameColor = ImageTreeControlImageSelectedBoderColor; 46 47 //测试数据 48 test(); 49 } 50 51 /// <summary> 52 /// 大小发送变化时 53 /// </summary> 54 /// <param name="sender"></param> 55 /// <param name="e"></param> 56 private void ImageTreeControl_SizeChanged(object sender, SizeChangedEventArgs e) 57 { 58 ThumbnailWidth = (int)this.Width - 10; 59 ListWidth = (int)this.Width - 25; 60 } 61 62 private void test() 63 { 64 //模拟数据 65 var list = new Client.WebApiWrap.PVL.FileCategoryApiWrap().GetFileCategoryList("ac165316-6630-40ba-84bb-fba75475d713", 2, 2, -1, 1); 66 var datas = new List<ImageTreeControlItemModel>(); 67 for (int j = 0; j < list.Count; j++) 68 { 69 var item = list[j]; 70 ImageTreeControlItemModel root = new ImageTreeControlItemModel(); 71 root.Text = item.CategoryName; 72 root.Value = item; 73 root.Images = new List<ImageTreeControlImageModel>(); 74 for (int i = 0; i < 10; i++) 75 { 76 root.Images.Add(new ImageTreeControlImageModel() 77 { 78 ImageSource = new BitmapImage(new Uri(PublicMethod.GetSet("Web") + "/images/defaut.png")), 79 Text = "我是名称" 80 }); 81 } 82 if (j == list.Count - 1) 83 { 84 ImageTreeControlItemModel m = new ImageTreeControlItemModel(); 85 m.Text = "我是第二级"; 86 m.Images = new List<ImageTreeControlImageModel>(); 87 for (int i = 0; i < 10; i++) 88 { 89 m.Images.Add(new ImageTreeControlImageModel() 90 { 91 ImageSource = new BitmapImage(new Uri(PublicMethod.GetSet("Web") + "/images/defaut.png")), 92 Text = "我是第二级的图片" 93 }); 94 } 95 root.Children = new List<ImageTreeControlItemModel>() { m }; 96 } 97 datas.Add(root); 98 } 99 vm.SetDataList(datas); 100 } 101 102 /// <summary> 103 /// 上下文 104 /// </summary> 105 public ImageTreeControlViewModel vm 106 { 107 get 108 { 109 return this.DataContext as ImageTreeControlViewModel; 110 } 111 } 112 113 /// <summary> 114 /// 背景色 115 /// </summary> 116 public string ImageTreeControlBackground 117 { 118 get { return (string)GetValue(ImageTreeControlBackgroundProperty); } 119 set { SetValue(ImageTreeControlBackgroundProperty, value); } 120 } 121 122 /// <summary> 123 /// 视图状态,默认文件名形式 124 /// 0:文件名称;1:缩略图 125 /// </summary> 126 public int ImageTreeControlViewState 127 { 128 get { return (int)GetValue(ImageTreeControlViewStateProperty); } 129 set { SetValue(ImageTreeControlViewStateProperty, value); } 130 } 131 132 /// <summary> 133 /// 缩略图模式,显示的图片宽度 134 /// </summary> 135 public int ImageTreeControlImageWidth 136 { 137 get { return (int)GetValue(ImageTreeControlImageWidthProperty); } 138 set { SetValue(ImageTreeControlImageWidthProperty, value); } 139 } 140 141 /// <summary> 142 /// 缩略图模式,显示的图片高度 143 /// </summary> 144 public int ImageTreeControlImageHeight 145 { 146 get { return (int)GetValue(ImageTreeControlImageHeightProperty); } 147 set { SetValue(ImageTreeControlImageHeightProperty, value); } 148 } 149 150 /// <summary> 151 /// 树状控件的节点名称字体样式 152 /// </summary> 153 public string ImageTreeControlFontColor 154 { 155 get { return (string)GetValue(ImageTreeControlFontColorProperty); } 156 set { SetValue(ImageTreeControlFontColorProperty, value); } 157 } 158 159 /// <summary> 160 /// 默认状态下,图片的边框样式 161 /// </summary> 162 public string ImageTreeControlImageBoderColor 163 { 164 get { return (string)GetValue(ImageTreeControlImageBoderColorProperty); } 165 set { SetValue(ImageTreeControlImageBoderColorProperty, value); } 166 } 167 168 /// <summary> 169 /// 缩略图模式的容器宽度 170 /// </summary> 171 public int ThumbnailWidth 172 { 173 get { return (int)GetValue(ThumbnailWidthProperty); } 174 private set { SetValue(ThumbnailWidthProperty, value); } 175 } 176 177 /// <summary> 178 /// 文件名称视图的容器宽度 179 /// </summary> 180 public int ListWidth 181 { 182 get { return (int)GetValue(ListWidthProperty); } 183 private set { SetValue(ListWidthProperty, value); } 184 } 185 186 /// <summary> 187 /// 选中状态下,图片边框的样式 188 /// </summary> 189 public string ImageTreeControlImageSelectedBoderColor 190 { 191 get { return (string)GetValue(ImageTreeControlImageSelectedBoderColorProperty); } 192 set { SetValue(ImageTreeControlImageSelectedBoderColorProperty, value); } 193 } 194 195 /// <summary> 196 /// 鼠标悬浮图片上,图片边框的样式 197 /// </summary> 198 public string ImageTreeControlImageMouseOverBoderColor 199 { 200 get { return (string)GetValue(ImageTreeControlImageMouseOverBoderColorProperty); } 201 set { SetValue(ImageTreeControlImageMouseOverBoderColorProperty, value); } 202 } 203 204 /// <summary> 205 /// 默认状态,列表模式,图片名称的样式 206 /// </summary> 207 public string ImageTreeControlImageImgNameColor 208 { 209 get { return (string)GetValue(ImageTreeControlImageImgNameColorProperty); } 210 set { SetValue(ImageTreeControlImageImgNameColorProperty, value); } 211 } 212 213 /// <summary> 214 /// 选中状态下,列表模式,图片名称的样式 215 /// </summary> 216 public string ImageTreeControlImageSelectedImgNameColor 217 { 218 get { return (string)GetValue(ImageTreeControlImageSelectedImgNameColorProperty); } 219 set { SetValue(ImageTreeControlImageSelectedImgNameColorProperty, value); } 220 } 221 222 #region 附加属性 223 224 public static readonly DependencyProperty ListWidthProperty = 225 DependencyProperty.Register("ListWidth", typeof(int), typeof(ImageTreeControl), new PropertyMetadata(0)); 226 227 public static readonly DependencyProperty ThumbnailWidthProperty = 228 DependencyProperty.Register("ThumbnailWidth", typeof(int), typeof(ImageTreeControl), new PropertyMetadata(0)); 229 230 public static readonly DependencyProperty ImageTreeControlImageMouseOverBoderColorProperty = 231 DependencyProperty.Register("ImageTreeControlImageMouseOverBoderColor", typeof(string), typeof(ImageTreeControl), new PropertyMetadata("")); 232 233 public static readonly DependencyProperty ImageTreeControlImageImgNameColorProperty = 234 DependencyProperty.Register("ImageTreeControlImageImgNameColor", typeof(string), typeof(ImageTreeControl), new PropertyMetadata("")); 235 236 public static readonly DependencyProperty ImageTreeControlImageSelectedImgNameColorProperty = 237 DependencyProperty.Register("ImageTreeControlImageSelectedImgNameColor", typeof(string), typeof(ImageTreeControl), new PropertyMetadata("")); 238 239 public static readonly DependencyProperty ImageTreeControlImageSelectedBoderColorProperty = 240 DependencyProperty.Register("ImageTreeControlImageSelectedBoderColor", typeof(string), typeof(ImageTreeControl), new PropertyMetadata("")); 241 242 public static readonly DependencyProperty ImageTreeControlImageBoderColorProperty = 243 DependencyProperty.Register("ImageTreeControlImageBoderColor", typeof(string), typeof(ImageTreeControl), new PropertyMetadata("")); 244 245 public static readonly DependencyProperty ImageTreeControlFontColorProperty = 246 DependencyProperty.Register("ImageTreeControlFontColor", typeof(string), typeof(ImageTreeControl), new PropertyMetadata("")); 247 248 public static readonly DependencyProperty ImageTreeControlImageHeightProperty = 249 DependencyProperty.Register("ImageTreeControlImageHeight", typeof(int), typeof(ImageTreeControl), new PropertyMetadata(0)); 250 251 public static readonly DependencyProperty ImageTreeControlImageWidthProperty = 252 DependencyProperty.Register("ImageTreeControlImageWidth", typeof(int), typeof(ImageTreeControl), new PropertyMetadata(0)); 253 254 public static readonly DependencyProperty ImageTreeControlViewStateProperty = 255 DependencyProperty.Register("ImageTreeControlViewState", typeof(int), typeof(ImageTreeControl), new PropertyMetadata(0)); 256 257 public static readonly DependencyProperty ImageTreeControlBackgroundProperty = 258 DependencyProperty.Register("ImageTreeControlBackground", typeof(string), typeof(ImageTreeControl), new PropertyMetadata("")); 259 260 #endregion 261 262 /// <summary> 263 /// 拖进来了 264 /// </summary> 265 /// <param name="sender"></param> 266 /// <param name="e"></param> 267 private void ImageTreeControl_PreviewDrop(object sender, DragEventArgs e) 268 { 269 var data = e.Data.GetData(typeof(ImageTreeControlImageModel)); 270 if (data == null) return; 271 Point point = e.GetPosition(tree); 272 HitTestResult result = VisualTreeHelper.HitTest(tree, point); 273 if (result == null) 274 return; 275 TreeViewItem treeitem = Utils.FindVisualParent<TreeViewItem>(result.VisualHit); 276 if (treeitem == null) 277 return; 278 var vm_item = treeitem.DataContext as ImageTreeControlItemModelPackage; 279 if (vm_item == null) 280 return; 281 if (vm_item.Type == ImageTreeControlItemType.Classify) 282 { 283 var imags = vm_item.Children.Where(c => c.Type == ImageTreeControlItemType.Images).ToList(); 284 if (imags.Count == 0) 285 { 286 ImageTreeControlItemModelPackage item = new ImageTreeControlItemModelPackage(vm_item); 287 item.Type = ImageTreeControlItemType.Images; 288 vm_item.Children.Add(item); 289 imags = vm_item.Children.Where(c => c.Type == ImageTreeControlItemType.Images).ToList(); 290 } 291 else if (imags.Count > 1) 292 { 293 MessageBox.Show("抱歉,当前节点下面有多个子集,无法确定你想存放的位置,请拖到对应节点下!"); 294 return; 295 } 296 var imgItem = imags.FirstOrDefault(); 297 imgItem.Images.Insert(0, data as ImageTreeControlImageModel); 298 imgItem.Parent.NotifyToImagesCount();//图片集合发生变动,发出通知 299 } 300 else if (vm_item.Type == ImageTreeControlItemType.Images) 301 { 302 vm_item.Images.Insert(0, data as ImageTreeControlImageModel); 303 vm_item.Parent.NotifyToImagesCount();//图片集合发生变动,发出通知 304 } 305 } 306 307 /// <summary> 308 /// 当有数据拖动进来时 309 /// </summary> 310 /// <param name="sender"></param> 311 /// <param name="e"></param> 312 private void ImageTreeControl_PreviewDragOver(object sender, DragEventArgs e) 313 { 314 e.Effects = DragDropEffects.Copy; 315 e.Handled = e.Data.GetData(typeof(ImageTreeControlImageModel)) != null; 316 } 317 } 318 319 internal static class Utils 320 { 321 public static T FindVisualParent<T>(DependencyObject obj) where T : class 322 { 323 while (obj != null) 324 { 325 if (obj is T) 326 return obj as T; 327 328 obj = VisualTreeHelper.GetParent(obj); 329 } 330 331 return null; 332 } 333 } 334 }
4、控件datacontext对象
1 using iPIS.Server.Core; 2 using iPIS.UI.Base.Model; 3 using iPIS.UI.Base.Tree; 4 using iPIS.Utility; 5 using System; 6 using System.Collections.Generic; 7 using System.Collections.ObjectModel; 8 using System.ComponentModel; 9 using System.Linq; 10 using System.Text; 11 using System.Threading.Tasks; 12 13 namespace iPIS.UI.Base.ViewModel 14 { 15 public class ImageTreeControlViewModel : System.ComponentModel.INotifyPropertyChanged 16 { 17 public event PropertyChangedEventHandler PropertyChanged; 18 private ImageTreeControl imageTreeControl; 19 20 public ImageTreeControlViewModel(ImageTreeControl imageTreeControl) 21 { 22 this.imageTreeControl = imageTreeControl; 23 } 24 25 private ObservableCollection<ImageTreeControlItemModelPackage> _DataList = new ObservableCollection<ImageTreeControlItemModelPackage>(); 26 27 /// <summary> 28 /// 数据集合,请使用 函数SetDataList,进行赋值构建 29 /// </summary> 30 public ObservableCollection<ImageTreeControlItemModelPackage> DataList 31 { 32 get => _DataList; 33 private set 34 { 35 _DataList = value; 36 PropertyChanged?.Notify(() => this.DataList); 37 } 38 } 39 40 /// <summary> 41 /// 视图状态,默认文件名形式 42 /// 0:文件名称;1:缩略图 43 /// </summary> 44 public int ViewState 45 { 46 get => imageTreeControl.ImageTreeControlViewState; 47 set 48 { 49 imageTreeControl.ImageTreeControlViewState = value; 50 } 51 } 52 53 /// <summary> 54 /// 发出数据变更通知通知 55 /// </summary> 56 /// <param name="vm"></param> 57 public void NotifyToDataList() 58 { 59 PropertyChanged?.Notify(() => this.DataList); 60 } 61 62 /// <summary> 63 /// 选中匹配成功的 text 64 /// </summary> 65 /// <param name="text">需要匹配的名称</param> 66 /// <param name="isfullvalue">true:全值匹配;false:模糊匹配</param> 67 /// <returns></returns> 68 public List<object> SelectedItem(string text, bool isfullvalue) 69 { 70 if (string.IsNullOrEmpty(text)) return new List<object>(); ; 71 List<object> outlist = new List<object>(); 72 SetSelected(DataList, text, isfullvalue, outlist); 73 if (outlist.Count > 0) 74 PropertyChanged?.Notify(() => this.DataList); 75 return outlist; 76 } 77 78 /// <summary> 79 /// 选中匹配成功的 id 80 /// </summary> 81 /// <param name="Id"></param> 82 /// <returns></returns> 83 public object SelectedItem(string Id) 84 { 85 if (string.IsNullOrEmpty(Id)) return new { }; 86 object outob = null; 87 SetSelected(DataList, Id, ref outob); 88 if (outob != null) 89 PropertyChanged?.Notify(() => this.DataList); 90 return outob; 91 } 92 93 /// <summary> 94 /// 获取所有的图片 95 /// </summary> 96 /// <param name="imageType">图片类型,默认返回所有类型</param> 97 /// <returns></returns> 98 public List<ImageTreeControlImageModel> GetAllImages(ImageTreeControlImageType imageType = ImageTreeControlImageType.None) 99 { 100 List<ImageTreeControlImageModel> list = new List<ImageTreeControlImageModel>(); 101 return list; 102 } 103 104 /// <summary> 105 /// 设置选中状态 106 /// </summary> 107 /// <param name="items"></param> 108 /// <param name="text"></param> 109 /// <param name="isfullvalue"></param> 110 /// <param name="selecteditems"></param> 111 private void SetSelected(ObservableCollection<ImageTreeControlItemModelPackage> items, string text, bool isfullvalue, List<object> selecteditems = null) 112 { 113 if (selecteditems == null) selecteditems = new List<object>(); 114 115 foreach (var item in items) 116 { 117 if (item.Type == ImageTreeControlItemType.Classify) 118 { 119 item.IsSelected = isfullvalue && item.Text.Equals(text) || !isfullvalue && item.Text.Contains(text); 120 if (item.IsSelected) 121 selecteditems.Add(item); 122 } 123 else 124 { 125 foreach (var img in item.Images) 126 { 127 img.IsSelected = isfullvalue && img.Text.Equals(text) || !isfullvalue && img.Text.Contains(text); 128 if (img.IsSelected) 129 selecteditems.Add(img); 130 } 131 } 132 SetSelected(item.Children, text, isfullvalue, selecteditems); 133 } 134 } 135 136 /// <summary> 137 /// 设置选中状态 138 /// </summary> 139 /// <param name="items"></param> 140 /// <param name="id"></param> 141 /// <param name="selecteditem"></param> 142 private void SetSelected(ObservableCollection<ImageTreeControlItemModelPackage> items, string id, ref object selecteditem) 143 { 144 foreach (var item in items) 145 { 146 if (item.Type == ImageTreeControlItemType.Classify) 147 { 148 item.IsSelected = item.Id.Equals(id); 149 if (item.IsSelected) 150 selecteditem = item; 151 } 152 else 153 { 154 foreach (var img in item.Images) 155 { 156 img.IsSelected = img.Id.Equals(id); 157 if (img.IsSelected) 158 selecteditem = img; 159 } 160 } 161 SetSelected(item.Children, id, ref selecteditem); 162 } 163 } 164 165 /// <summary> 166 /// 设置数据源 167 /// </summary> 168 /// <param name="items"></param> 169 public void SetDataList(List<ImageTreeControlItemModel> items) 170 { 171 DataList.Clear(); 172 ObservableCollection<ImageTreeControlItemModelPackage> roots = new ObservableCollection<ImageTreeControlItemModelPackage>(); 173 foreach (var item in items) 174 { 175 ImageTreeControlItemModelPackage itemP = new ImageTreeControlItemModelPackage(null); 176 itemP.Type = ImageTreeControlItemType.Classify; 177 itemP.Id = item.Id; 178 itemP.Text = item.Text; 179 itemP.Value = item.Value; 180 //递归设置子集 181 SetChildren(item.Children, itemP); 182 //处理图片 183 SetImages(item, itemP); 184 //设置图标 185 itemP.IconSource = item.IconSource; 186 //系统内置的root图标给予覆盖 187 SetRootIcon(itemP); 188 roots.Add(itemP); 189 } 190 DataList = roots; 191 } 192 193 /// <summary> 194 /// 递归设置子集 195 /// </summary> 196 /// <param name="items"></param> 197 /// <param name="parent"></param> 198 private void SetChildren(List<ImageTreeControlItemModel> items, ImageTreeControlItemModelPackage parent) 199 { 200 if (items == null || items.Count == 0) return; 201 202 foreach (var item in items) 203 { 204 ImageTreeControlItemModelPackage itemP = new ImageTreeControlItemModelPackage(parent); 205 itemP.Id = item.Id; 206 itemP.Text = item.Text; 207 itemP.Value = item.Value; 208 //递归设置子集 209 SetChildren(item.Children, itemP); 210 //处理图片 211 SetImages(item, itemP); 212 parent.Children.Add(itemP); 213 } 214 } 215 216 /// <summary> 217 /// 设置当前实体的图片集合 218 /// </summary> 219 /// <param name="item"></param> 220 /// <param name="parent"></param> 221 private void SetImages(ImageTreeControlItemModel item, ImageTreeControlItemModelPackage parent) 222 { 223 if (item.Images == null || item.Images.Count == 0) return; 224 225 ImageTreeControlItemModelPackage imgP = new ImageTreeControlItemModelPackage(parent); 226 imgP.Type = ImageTreeControlItemType.Images; 227 foreach (var img in item.Images) 228 { 229 imgP.Images.Add(img); 230 } 231 parent.Children.Add(imgP); 232 } 233 234 /// <summary> 235 /// 设置根节点的图标 236 /// </summary> 237 private void SetRootIcon(ImageTreeControlItemModelPackage root) 238 { 239 if (root.Parent != null) return; 240 var fc = root.Value as filecategory; 241 if (fc == null) return; 242 if (fc.CategorySource != 1) return; 243 var url = string.Empty; 244 switch (fc.CategoryName) 245 { 246 case "头部五官": 247 url = PublicMethod.GetSet("Web") + "/Images/ImageCategoryIcons/人像鉴定系统-文书icons正面.png"; 248 break; 249 case "人体动态": 250 url = PublicMethod.GetSet("Web") + "/Images/ImageCategoryIcons/人像鉴定系统-文书icons人体动态.png"; 251 break; 252 case "身高": 253 url = PublicMethod.GetSet("Web") + "/Images/ImageCategoryIcons/人像鉴定系统-文书icons身高.png"; 254 break; 255 case "特殊标示": 256 url = PublicMethod.GetSet("Web") + "/Images/ImageCategoryIcons/人像鉴定系统-文书icons特殊.png"; 257 break; 258 case "衣着配饰": 259 url = PublicMethod.GetSet("Web") + "/Images/ImageCategoryIcons/人像鉴定系统-文书icons衣服.png"; 260 break; 261 case "其他": 262 break; ; 263 default: 264 break; 265 } 266 if (!string.IsNullOrEmpty(url)) 267 root.IconSource = new System.Windows.Media.Imaging.BitmapImage(new Uri(url, UriKind.Absolute)); 268 } 269 } 270 }
5、数据真实实体
1 using iPIS.UI.Base.ViewModel; 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.Media.Imaging; 10 11 namespace iPIS.UI.Base.Model 12 { 13 /// <summary> 14 /// 图片树状,子项实体的包装类,请使用 ImageTreeControlItemModel 完成构建 15 /// </summary> 16 public class ImageTreeControlItemModelPackage : INotifyPropertyChanged 17 { 18 19 public event PropertyChangedEventHandler PropertyChanged; 20 private string _Id = string.Empty; 21 private bool _IsSelected = false; 22 23 /// <summary> 24 /// 当前的父级 25 /// </summary> 26 /// <param name="Parent">当前元素的父级,null代表无父级,顶层元素</param> 27 public ImageTreeControlItemModelPackage(ImageTreeControlItemModelPackage Parent) 28 { 29 this.Parent = Parent; 30 } 31 32 /// <summary> 33 /// 唯一标示 34 /// </summary> 35 public string Id 36 { 37 get 38 { 39 if (string.IsNullOrEmpty(_Id)) _Id = Guid.NewGuid().ToString(); 40 return _Id; 41 } 42 set => _Id = value; 43 } 44 45 /// <summary> 46 /// 当前类型 47 /// </summary> 48 public ImageTreeControlItemType Type { get; set; } = ImageTreeControlItemType.Classify; 49 50 /// <summary> 51 /// 分类名称,type=Classify 时有效 52 /// </summary> 53 public string Text { get; set; } 54 55 /// <summary> 56 /// 绑定值 57 /// </summary> 58 public object Value { get; set; } 59 60 /// <summary> 61 /// 分类图标,type=Classify 时有效 62 /// </summary> 63 public BitmapImage IconSource { get; set; } = null; 64 65 /// <summary> 66 /// 所属的集合,type=Classify 时有效 67 /// </summary> 68 public ObservableCollection<ImageTreeControlItemModelPackage> Children { get; set; } = new ObservableCollection<ImageTreeControlItemModelPackage>(); 69 70 /// <summary> 71 /// 当前的父级 72 /// </summary> 73 public ImageTreeControlItemModelPackage Parent { get; set; } 74 75 /// <summary> 76 /// 所属的图片集合,type=Images 时有效 77 /// UI已经构建的模块,新增插入编辑集合,请使用帮助函数 78 /// </summary> 79 public ObservableCollection<ImageTreeControlImageModel> Images { get; set; } = new ObservableCollection<ImageTreeControlImageModel>(); 80 81 /// <summary> 82 /// 当前下的图片集合,type=Classify 时有效 83 /// </summary> 84 public ObservableCollection<ImageTreeControlImageModel> GetImages 85 { 86 get 87 { 88 if (Type == ImageTreeControlItemType.Images) 89 return new ObservableCollection<ImageTreeControlImageModel>(); 90 ObservableCollection<ImageTreeControlImageModel> list = new ObservableCollection<ImageTreeControlImageModel>(); 91 foreach (var item in Children.Where(c => c.Type == ImageTreeControlItemType.Images)) 92 { 93 foreach (var img in item.Images) 94 { 95 list.Add(img); 96 } 97 } 98 return list; 99 } 100 } 101 102 /// <summary> 103 /// 是否选中 104 /// </summary> 105 public bool IsSelected 106 { 107 get 108 { 109 return _IsSelected; 110 } 111 set 112 { 113 _IsSelected = value; 114 PropertyChanged?.Notify(() => this.IsSelected); 115 } 116 } 117 118 /// <summary> 119 /// 当前下的图片集合数量,type=Classify 时有效 120 /// </summary> 121 public int ImagesCount 122 { 123 get => GetImages.Count; 124 } 125 126 /// <summary> 127 /// 当前下的图片集合数量,type=Classify 时有效 128 /// </summary> 129 public void NotifyToImagesCount() 130 { 131 if (Type == ImageTreeControlItemType.Classify) 132 PropertyChanged?.Notify(() => this.ImagesCount); 133 } 134 } 135 136 /// <summary> 137 /// 图片树状,所属子项的图片实体 138 /// </summary> 139 public class ImageTreeControlImageModel : INotifyPropertyChanged 140 { 141 public event PropertyChangedEventHandler PropertyChanged; 142 private string _Id = string.Empty; 143 private bool _IsSelected = false; 144 private ImageTreeControlImageType _Type = ImageTreeControlImageType.Default; 145 146 /// <summary> 147 /// 唯一标示 148 /// </summary> 149 public string Id 150 { 151 get 152 { 153 if (string.IsNullOrEmpty(_Id)) _Id = Guid.NewGuid().ToString(); 154 return _Id; 155 } 156 set => _Id = value; 157 } 158 159 /// <summary> 160 /// 图片名称 161 /// </summary> 162 public string Text { get; set; } 163 164 /// <summary> 165 /// 绑定值 166 /// </summary> 167 public object Value { get; set; } 168 169 /// <summary> 170 /// 图片资源 171 /// </summary> 172 public BitmapImage ImageSource { get; set; } = null; 173 174 /// <summary> 175 /// 图片类型 176 /// </summary> 177 public ImageTreeControlImageType Type 178 { 179 get 180 { 181 return _Type; 182 } 183 set 184 { 185 _Type = value; 186 PropertyChanged?.Notify(() => this.Type); 187 } 188 } 189 190 /// <summary> 191 /// 是否选中 192 /// </summary> 193 public bool IsSelected 194 { 195 get 196 { 197 return _IsSelected; 198 } 199 set 200 { 201 _IsSelected = value; 202 PropertyChanged?.Notify(() => this.IsSelected); 203 } 204 } 205 } 206 207 /// <summary> 208 /// 图片树状,子项类型 209 /// </summary> 210 public enum ImageTreeControlItemType 211 { 212 /// <summary> 213 /// 分类 214 /// </summary> 215 Classify = 0, 216 /// <summary> 217 /// 图片资源 218 /// </summary> 219 Images = 1 220 } 221 222 /// <summary> 223 /// 图片树状,所属子项的图片的类型 224 /// </summary> 225 public enum ImageTreeControlImageType 226 { 227 /// <summary> 228 /// 什么也不是 229 /// </summary> 230 None = -1, 231 /// <summary> 232 /// 默认 233 /// </summary> 234 Default = 0, 235 /// <summary> 236 /// 抠图 237 /// </summary> 238 Matting = 1, 239 /// <summary> 240 /// 已经对此抠图了 241 /// </summary> 242 AlreadyMatting = 2 243 } 244 }
6、调用者关心的数据实体(因为绑定数据构建有点麻烦,所以封装了下,使调用者不关心复杂逻辑)
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 using System.Threading.Tasks; 6 using System.Windows.Media.Imaging; 7 8 namespace iPIS.UI.Base.Model 9 { 10 /// <summary> 11 /// 图片树状,子项实体 12 /// </summary> 13 public class ImageTreeControlItemModel 14 { 15 /// <summary> 16 /// 唯一标示符 17 /// </summary> 18 public string Id { get; set; } 19 20 /// <summary> 21 /// 显示名称 22 /// </summary> 23 public string Text { get; set; } 24 25 /// <summary> 26 /// 绑定值 27 /// </summary> 28 public object Value { get; set; } 29 30 /// <summary> 31 /// 当前的下级 32 /// </summary> 33 public List<ImageTreeControlItemModel> Children { get; set; } 34 35 /// <summary> 36 /// 当前节点下的图片集合 37 /// </summary> 38 public List<ImageTreeControlImageModel> Images { get; set; } 39 40 /// <summary> 41 /// 类别显示图标 42 /// </summary> 43 public BitmapImage IconSource { get; set; } = null; 44 } 45 }
好了,该控件的全部代码已经看完了,下面我就把我遇到的问题进行按个阐述,且附上解决方案
1、首要问题就是如何才能节点下面再批量显示图片
答:通过假节点来实现,每个节点绑定一个Type类型,标示当前是节点还是节点下的图片显示,如果是节点下的图片,该节点不显示头,显示下面的图片集合
附上关键代码
2、如何缩略图和文件列表的动图切换
答:起初考虑这个属性设置在datacontext还是控件里,最开始是想放在datacontext里的,但是,UI上的绑定出了问题,找了几圈没得合适的解决办法,迫于无奈就放在控件里了,通过附加属性控制,细心的朋友应该会发现是利用的多条件的触发器,因为需要首先满足当前节点是图片集合的容器,详情可参照问题1
附上关键代码
3、调用者需要动态的设置选中
答:通过数据实体继承INotifyPropertyChanged接口,实现通知即可实现;特别说明,因为在vm里面只能对数据集发起变更的通知,所以数据源发送的变动需要自助发起通知,子集会自动更新的,至于原理我也不是很清楚,反正不通知就没戏,亲测
附上关键代码
4、因为实现了拖住,允许接收外界的数据,需要动态载入节点中,如何更新UI和更新父级节点的统计数量
答:实现原理和问题3差不多,需要提醒的是,由于集合发生变动,需要发起通知才行,否则是不会更新的,请看关键代码
附上关键代码
5、由于数据结果过于复杂,调用是无需关心的,所以需要给调用者提供简易的数据构建函数
答:数据源的赋值访问设置为私有,杜绝外部写入,通过公开函数构建
附上关键代码