如何确定TreeViewItem是在进行扩展还是已经扩展

时间:2011-02-01 12:51:18

标签: wpf treeview

我有以下问题。我的树视图中有一些项目位于层次结构的顶部。当我单击某个项目以展开它时,事件需要5秒钟才能加载所选节点中的所有项目。如何在此过程中显示“请稍候......扩展节点...”消息?如何确定项目是否仍在扩展或现在是否已加载和显示所有嵌套项目?

我已经在这里提出了非常相似的问题Show "Please wait.." message when expanding TreeView in WPF,我甚至将答案标记为已被接受但是,我现在的解决方案并不令人满意,因为“请等待......”对话框闪烁(显示并关闭)和嵌套项目的数量一样多。)

1 个答案:

答案 0 :(得分:1)

正如我在你的帖子评论中提到的那样,我们需要解决两个问题。

  1. 你有很多项目,所以当你展开节点时 - wpf开始生成项目容器并将它们放入可视树中。这可能很烦人。
  2. 另一方面,我想下一个场景 - 用户展开节点项并向数据库/远程服务器发送请求,这可能会执行一段时间。
  3. WPF不提供BeforeExpand事件,因此您应该使用视图数据,更改属性的通知,数据绑定和可观察集合。我将在简单的应用程序中说明这一点。

    整个方法可以大致描述为:

    • 将视图数据的IsExpanded属性绑定到TreeViewItem的IsExpanded属性
    • 在某处(可能在模型中)收听IsExpanded属性更改通知
    • 设置IsLoading属性(在我的sapmle中,它在视图数据中声明)
    • 启动一些填充内部项目的任务
    • 重置IsLoading属性
    • 将DataTrigger放在xaml中,它对IsLoading属性作出反应。

    我设计了我的树项ViewData类,其中包含可观察的属性IsExpanded,IsLoaded,可观察的子项集合以及将显示的名称:

    public class TreeItem : ObservableObject
    {
        public TreeItem (string name)
        {
            this.Name = name;
        }
    
        public string Name 
        {
            get; 
            private set; 
        }
    
        private bool _isExpanded;
        public bool IsExpanded
        {
            get
            {
                return this._isExpanded;
            }
            set
            {
                if (this._isExpanded != value)
                {
                    this._isExpanded = value;
                    this.OnPropertyChanged("IsExpanded");
                }
            }
        }
    
        private bool _isLoading;
        public bool IsLoading
        {
            get
            {
                return this._isLoading;
            }
            set
            {
                if (this._isLoading != value)
                {
                    this._isLoading = value;
                    this.OnPropertyChanged("IsLoading");
                }
            }
        }
    
    
        private ObservableCollection<TreeItem> _innerItems = new ObservableCollection<TreeItem>();
        public IEnumerable<TreeItem> InnerItems
        {
            get
            {
                return this._innerItems;
            }
    
        }
    
        public void LoadInnerItems()
        {
            this.IsLoading = true;
            var sc= SynchronizationContext.Current;
            new Thread(new ThreadStart(() => 
                {
                    Thread.Sleep(5000);
                    sc.Send(o =>
                        {
                            this._innerItems.Add(new TreeItem("1223"));
                            this._innerItems.Add(new TreeItem("2345"));
                            this._innerItems.Add(new TreeItem("666678"));
                            this.IsLoading = false;
                        }, null);
                }))
                .Start();
        }
    }
    

    下一步是开发Presentation Model。如您所见,我们的模型侦听IsExpanded PropertyChanged事件,当它等于true时,启动LoadingInnerItems。:

    public class SampleModel : ObservableObject
    {
        public SampleModel()
        {
            this._items.Add(new TreeItem("AAA"));
            this._items.Add(new TreeItem("BBB"));
            this._items.Add(new TreeItem("CCC"));
    
            foreach (var i in this._items)
            {
                i.PropertyChanged += new PropertyChangedEventHandler(Item_PropertyChanged);
            }
    
        }
    
        void Item_PropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            if (e.PropertyName == "IsExpanded")
            {
                var item = (TreeItem)sender;
                if(item.IsExpanded)
                {
                    item.LoadInnerItems();
                }
            }
        }
    
        private ObservableCollection<TreeItem> _items = new ObservableCollection<TreeItem>();
        public IEnumerable<TreeItem> Items
        {
            get
            {
                return this._items;
            }
        }
    }
    

    我们的TreeView的XAML。当我们加载内部项目时 - 我们的treeviewitem的前景变为红色:

    <TreeView ItemsSource="{Binding Items}">
        <TreeView.ItemTemplate>
            <HierarchicalDataTemplate ItemsSource="{Binding InnerItems}">
                <TextBlock Text="{Binding Name}"/>
            </HierarchicalDataTemplate>
        </TreeView.ItemTemplate>
        <TreeView.ItemContainerStyle>
            <Style TargetType="TreeViewItem">
                <Setter Property="IsExpanded"
                        Value="{Binding IsExpanded, Mode=TwoWay}"/>
                <Setter Property="Foreground"
                        Value="Aqua"/>
                <Style.Triggers>
                    <DataTrigger Binding="{Binding IsLoading}"
                                 Value="True">
                        <Setter Property="Foreground" 
                                Value="Red"/>
                    </DataTrigger>
                </Style.Triggers>
            </Style>
        </TreeView.ItemContainerStyle>
    </TreeView>
    

    并且不要忘记在后面的代码中将模型设置为视图的datacontext:

        public MainWindow()
        {
            InitializeComponent();
    
            this.Model = new SampleModel();
        }