zoukankan      html  css  js  c++  java
  • MVVM打造无限级TreeView

        自从了解了MVVM,就迷恋上了它,基本上抛弃了传统的开发方式~

        前些天无意中看到一篇关于用MVVM打造TreeView的文章(http://www.codeproject.com/KB/WPF/TreeViewWithViewModel.aspx),感觉比较美妙,遂拿来简单改造一下,使它支持无限级。

        首先,定义一个实体类:

        public class TreeItem
        {
            readonly List<TreeItem> _children = new List<TreeItem>();
            public List<TreeItem> Children
            {
                get { return _children; }
            }
    
            public string Name { get; set; }
            public int ID { get; set; }
            public int ParentID { get; set; }
        }

        接下来,把TreeViewItemViewModel、以及PropertyChangedBase直接搬过来。

        然后定义一个ViewModel:

    	public class TreeItemViewModel : TreeViewItemViewModel
    	{
    		private TreeItem item;
    
    		public TreeItemViewModel(TreeItem item) :
    			this(item, null)
    		{
    
    		}
    
    		public TreeItemViewModel(TreeItem item, TreeItemViewModel parent) :
    			base(parent, true)
    		{
    			this.item = item;
    		}
    
    		public string Name
    		{
    			get { return item.Name; }
    			set
    			{
    				item.Name = value;
    				this.NotifyPropertyChanged(p => p.Name);
    			}
    		}
    		
    		protected override void LoadChildren()
    		{
    			var loadedData = TreeItemDemoData.LoadChildrens(item.ID);
    			if (loadedData.Count > 0)
    			{
    				Children.Clear();
    				foreach (var t in loadedData)
    				{
    					Children.Add(new TreeItemViewModel(t, this));
    				}
    			}
    		}
    	}

        以及相关Demo数据:

    	public class TreeItemDemoData
    	{
    		private static readonly List<TreeItem> data;
    
    		static TreeItemDemoData()
    		{
    			data = new List<TreeItem>();
    			for (int i = 0; i < 10; i++)
    			{
    				data.Add(new TreeItem
    		         {
    		         	Name = string.Format("Name {0}", i.ToString()),
    		         	ID = i,
    		         	ParentID = i - 1
    		         });
    			}
    		}
    
    		public static List<TreeItem> LoadChildrens(int parentId)
    		{
    			return data.Where(t => t.ParentID == parentId).ToList();
    		}
    	}

        定义界面:

    <Window x:Class="TreeViewDemo.Window1"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:vm="clr-namespace:TreeViewDemo.ViewModel"
            Title="TreeViewDemo" Height="300" Width="300"
    >
    	<StackPanel>
    		<TreeView ItemsSource="{Binding}">
    			<TreeView.ItemContainerStyle>
    				<Style TargetType="{x:Type TreeViewItem}">
    					<Setter Property="IsExpanded" Value="{Binding IsExpanded, Mode=TwoWay}" />
    					<Setter Property="IsSelected" Value="{Binding IsSelected, Mode=TwoWay}" />
    					<Setter Property="FontWeight" Value="Normal" />
    					<Style.Triggers>
    						<Trigger Property="IsSelected" Value="True">
    							<Setter Property="FontWeight" Value="Bold" />
    						</Trigger>
    					</Style.Triggers>
    				</Style>
    			</TreeView.ItemContainerStyle>
    			<TreeView.Resources>
    				<HierarchicalDataTemplate
    					DataType="{x:Type vm:TreeItemViewModel}"
    					ItemsSource="{Binding Children}">
    					<StackPanel Orientation="Horizontal">
    						<TextBlock Text="{Binding Name}" />
    					</StackPanel>
    				</HierarchicalDataTemplate>
    			</TreeView.Resources>
    		</TreeView>
    	</StackPanel>
    </Window>

        最后,绑定数据:

    	public partial class Window1 : Window
    	{
    		public Window1()
    		{
    			InitializeComponent();
    			DataContext = new ObservableCollection<TreeItemViewModel>(
    				TreeItemDemoData.LoadChildrens(0).Select(t => new TreeItemViewModel(t))
    			);
    		}
    	}

        OK,完成,发现HierarchicalDataTemplate挺神奇的~_~。

        相信TreeView应用范围还是相当广的,比如某些应用的数据N级分类。

        当然,如果是数据库应用,可能会有一定延迟,造成界面的假死,在此对本文例子稍加改造,使用多线程提高UI的响应速度。

        对TreeItemViewModel进行改造:

    		protected override void LoadChildren()
    		{
    			PreLoad();
    		}
    		
    		private string originalName;
    		private Dispatcher uiThreadDispatcher;
    		private void PreLoad()
    		{
    			originalName = Name;
    			Name = Name + " (expanding...)";
    			uiThreadDispatcher = Dispatcher.CurrentDispatcher;			
    			ThreadPool.QueueUserWorkItem(Loading);
    		}
    		
    		private void Loading(object state)
    		{
    			Thread.Sleep(500);//模拟延迟
    			var loadedData = TreeItemDemoData.LoadChildrens(item.ID);
    			if (loadedData.Count > 0)
    			{
    				uiThreadDispatcher.BeginInvoke(DispatcherPriority.Background,
    				                               new Action(() => Children.Clear()));
    				foreach (var t in loadedData)
    				{
    					uiThreadDispatcher.BeginInvoke(DispatcherPriority.Background,
    					                               new Action<TreeItem>(vm => Children.Add(new TreeItemViewModel(vm, this))),
    					                               t);
    				}
    			}
    			Name = originalName;
    		}

        只是简单的小技巧~本文就到这里。

        DEMO地址

  • 相关阅读:
    区块链匿名资产的发行原理
    14亿条记录,12c 做不到2小时内变更表结构字段类型?
    MySQL修改有存量数据的数据库字符集实战
    Linux之HugePages快速配置
    快手大数据架构师:实时OLAP分析平台这么做,才可能超越抖音
    Oracle 12c 能否在2小时内完成一张14亿条记录的表结构字段类型变更
    Redis NoSQL
    对python virtualenv虚拟环境的理解
    16、SpringBoot------整合MapStruct
    16、SpringBoot------整合MapStruct
  • 原文地址:https://www.cnblogs.com/lwme/p/1816438.html
Copyright © 2011-2022 走看看