有没有一种方法可以在后台线程上构建TreeView控件?

3
我有一个TreeView控件,需要用一个大的三层对象列表来填充它,但构建过程非常耗时。我正在后台线程上加载数据,然后将GUI更新发送到GUI线程,但更新太多了,每次添加节点都必须发送一次,然后必须调用ExpandSubTree()方法才能展开所有子节点,这会触发更多的展开事件,导致程序崩溃。
有没有办法在后台线程上构建控件及其打开/关闭状态,并在完成后仅传递一次?

为什么不使用Windows窗体Control类的Invoke方法? - Mohsen Afshin
2个回答

0
每个树形视图项都有一个Children属性,如果将每个树形视图项的Children绑定到ObservableCollection,则可以从BackGroundWorker或另一个线程向其添加项目。如果使用以下集合来绑定树形视图项的子项,则可以在后台向视图添加或删除子项。它使用同步上下文将项目添加到视图中:
public class ThreadSafeObservableCollection<T> : ObservableCollection<T>
{
    private SynchronizationContext SynchronizationContext;

    public ThreadSafeObservableCollection()
    {
        SynchronizationContext = SynchronizationContext.Current;

        // current synchronization context will be null if we're not in UI Thread
        if (SynchronizationContext == null)
            throw new InvalidOperationException("This collection must be instantiated from UI Thread, if not, you have to pass SynchronizationContext to con                                structor.");
    }

    public ThreadSafeObservableCollection(SynchronizationContext synchronizationContext)
    {
        if (synchronizationContext == null)
            throw new ArgumentNullException("synchronizationContext");

        this.SynchronizationContext = synchronizationContext;
    }

    protected override void ClearItems()
    {
        this.SynchronizationContext.Send(new SendOrPostCallback((param) => base.ClearItems()), null);
    }

    protected override void InsertItem(int index, T item)
    {
        this.SynchronizationContext.Send(new SendOrPostCallback((param) => base.InsertItem(index, item)), null);
    }

    protected override void RemoveItem(int index)
    {
        this.SynchronizationContext.Send(new SendOrPostCallback((param) => base.RemoveItem(index)), null);
    }

    protected override void SetItem(int index, T item)
    {
        this.SynchronizationContext.Send(new SendOrPostCallback((param) => base.SetItem(index, item)), null);
    }

    protected override void MoveItem(int oldIndex, int newIndex)
    {
        this.SynchronizationContext.Send(new SendOrPostCallback((param) => base.MoveItem(oldIndex, newIndex)), null);
    }
}

我认为这些文章对你很有用:

使用ViewModel模式简化WPF TreeView

自定义WPF TreeView布局

希望对你有所帮助...


谢谢,我已经决定采用MVVM方式来处理它,因为这似乎是一个好的设计方式 - 而且也是尝试新模式的好机会 :) 那个链接非常有帮助,谢谢。 - NZJames
我非常高兴,MVVM 很棒!如果它确实对你有用的话,也希望你考虑接受这个答案。谢谢。 - Raúl Otaño

0
你是一次性创建整个树吗? 你是为每个创建的项触发调用吗?
我会考虑按需加载树。也许当用户扩展节点时,您处理该事件并获取数据。我还会考虑每次调用加载一组项目。

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