如何使WPF TreeView数据绑定变为惰性和异步?

3
我正在学习如何在WPF中使用数据绑定来实现TreeView。我正在程序化地创建Binding对象,并将Source、Path和Converter属性设置为指向我的自定义类。我甚至可以设置IsAsync,当我浏览树时,我可以异步地看到GUI更新。到目前为止都很好!
我的问题是,WPF会急切地评估GUI中未展开的树的部分。如果长时间不处理,这将导致整个树被评估(实际上,在这个例子中,我的树是无限的,但你明白我的意思)。我希望仅在用户展开节点时按需评估树。使用WPF中现有的异步数据绑定技术,是否可能实现这一点?
另外,我还没有弄清楚ObjectDataProvider与此任务的关系。
我的XAML代码只包含一个TreeView对象,我的C#代码是:
public partial class Window1 : Window
{
    public Window1() {
        InitializeComponent();

        treeView.Items.Add( CreateItem(2) );
    }

    static TreeViewItem CreateItem(int number)
    {
        TreeViewItem item = new TreeViewItem();
        item.Header = number;

        Binding b = new Binding();
        b.Converter = new MyConverter();
        b.Source = new MyDataProvider(number);
        b.Path = new PropertyPath("Value");
        b.IsAsync = true;
        item.SetBinding(TreeView.ItemsSourceProperty, b);

        return item;
    }

    class MyDataProvider
    {
        readonly int m_value;

        public MyDataProvider(int value) {
            m_value = value;
        }

        public int[] Value {
            get {
                // Sleep to mimick a costly operation that should not hang the UI
                System.Threading.Thread.Sleep(2000);
                System.Diagnostics.Debug.Write(string.Format("Evaluated for {0}\n", m_value));
                return new int[] {
                    m_value * 2, 
                    m_value + 1,
                };
            }
        }
    }

    class MyConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) {
            // Convert the double to an int.
            int[] values = (int[])value;
            IList<TreeViewItem> result = new List<TreeViewItem>();
            foreach (int i in values) {
                result.Add(CreateItem(i));
            }
            return result;
        }

        public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) {
            throw new InvalidOperationException("Not implemented.");
        }
    }    
}

注意:我之前通过添加WPF事件处理程序并在触发事件处理程序时直接添加项来实现树节点的惰性评估。我试图摆脱这种方法,改用数据绑定(我理解这更符合“WPF方式”)。


你能描述一下你的树形结构吗?有多少层?项目和子项目是否属于同一类型? - Amsakanna
1个回答

3

一个通用的解决方案(因为我不确定您的代码是否是模拟的)

  1. 创建包含父级和子级的模型(在本例中是一个整数和一个整数列表)
  2. 创建一个ViewModel,除了Model的属性外还有一个IsExpanded属性
  3. 将您的IsExpanded属性绑定到视图(xaml)中TreeViewItem的IsExpanded属性
  4. 在IsExpanded属性的setter中,使用Dispatcher填充您的Children列表,优先级为Background。每添加一个项目到您的Children List中都应触发PropertyChanged事件。

如果您不熟悉,请查看MVVM设计模式。这里是Jason的好视频


这是一段非常棒的视频。在我消化了内容并制作出一个可用的应用之前,我会等待一下再接受答案。 - pauldoo
该视频展示了如何在模型层进行后台工作的同时,异步地将事物填充到视图层。 - pauldoo
我的解决方案是使用MVVM模型进行异步更新,就像你提供的视频中所做的那样。这与一些ModelView绑定的“IsExpanded”结合使用,以触发后台工作,一切都很好。 :) - pauldoo
@Amsakanna,如果您正在使用HierarchicalDataTemplate,是否可以实现这个功能?我很难弄清楚如何从自动生成的TreeViewItem创建到HierarchicalDataTemplate的ViewModel的绑定。 - Greg
@Greg,你最后解决了这个问题吗? - MarkB
抱歉,我不记得了。我已经多年没有参与那个项目了。 - Greg

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接