延迟ItemsControl项目的可见性

时间:2014-10-26 01:10:07

标签: wpf visibility itemscontrol deferred

我有一个场景,我想在ItemsControl中呈现很多项目。由于项目的布局方式(使用画布),我无法使用标准的虚拟化面板,因此控件加载需要很长时间。

我不想一次性承担所有物品的装载时间,而是想知道如何批量装载物品?

因此,例如,如果我使用ListBox,并将其itemsSource设置为某个大型列表,我怎么能分批创建10个项目的ListBoxItems,推迟剩余的以在下一个Dispatcher事件上运行(背景或AppIdle)?

通过让ItemsSource成为随每个新批次增长的Observable集合,可以很容易地从ViewModel解决这个问题,但我想在View级别添加它。

我也不希望使用ItemContainers Visibility属性实现它,因为很可能已经在使用它。

1 个答案:

答案 0 :(得分:0)

这一切都取决于数据的来源。但我可以告诉你从视图加载只是一个糟糕的计划。

  1. 将您的ItemsSource设置为ViewModel中的ObservableCollection。
  2. 从后台线程更新ObservableCollection,以免影响您的UI。
  3. 确保在更新时不要重新实例化实例,而是清除并重新填充您的集合。
  4. 我相信WPF现在允许对ObservableCollection进行跨线程更新。如果没有,您可以随时使用像Caliburn这样的库 BindableCollection

    您也可以创建自己的this article

    代码:

    /// <summary>
    /// Initializes a new instance of the 
    /// <see cref="ObservableCollectionEx{T}"/> class.
    /// </summary> 
    public class ObservableCollectionEx<T> : ObservableCollection<T>
    {
        #region Constructors
    
        /// <summary>
        /// Initializes a new instance of the
        /// <see cref="ObservableCollectionEx{T}" /> class.
        /// </summary>
        public ObservableCollectionEx()
        {
        }
    
        ///
        /// Initializes a new instance of the
        ///  class.
        ///
        ///The collection.
        public ObservableCollectionEx(IEnumerable<T> collection) : this()
        {
            this.AddRange(collection);
        }
    
        #endregion
    
        #region Events
    
        /// <summary>
        /// Source: New Things I Learned
        /// Title: Have worker thread update ObservableCollection that is bound to a ListCollectionView
        /// http://geekswithblogs.net/NewThingsILearned/archive/2008/01/16/have-worker-thread-update-observablecollection-that-is-bound-to-a.aspx
        /// Note: Improved for clarity and the following of proper coding standards.
        /// </summary>
        /// <param name="e"></param>
        protected override void OnCollectionChanged(NotifyCollectionChangedEventArgs e)
        {
            // Use BlockReentrancy
            using (BlockReentrancy())
            {
                var eventHandler = CollectionChanged;
                if (eventHandler == null) return;
    
                // Only proceed if handler exists.
                Delegate[] delegates = eventHandler.GetInvocationList();
    
                // Walk through invocation list.
                foreach (var @delegate in delegates)
                {
                    var handler = (NotifyCollectionChangedEventHandler)@delegate;
                    var currentDispatcher = handler.Target as DispatcherObject;
    
                    // If the subscriber is a DispatcherObject and different thread.
                    if ((currentDispatcher != null) &amp;&amp; (!currentDispatcher.CheckAccess()))
                    {
                        // Invoke handler in the target dispatcher's thread.
                        currentDispatcher.Dispatcher.Invoke(
                            DispatcherPriority.DataBind, handler, this, e);
                    }
    
                    else
                    {
                        // Execute as-is
                        handler(this, e);
                    }
                }
            }
        }
    
        /// <summary>
        /// Overridden NotifyCollectionChangedEventHandler event.
        /// </summary>
        public override event NotifyCollectionChangedEventHandler CollectionChanged;
    
        #endregion
    }