Пример #1
0
        public ItemContainerGenerator(IGeneratorHost host)
        {
            this.host = host;
            this.host.View.CollectionChanged += OnViewCollectionChanged;

            this.generatedContainers = new List <GeneratedItemContainer>();
        }
Пример #2
0
        public static ItemsControl ItemsControlFromItemContainer(DependencyObject container)
        {
            UIElement ui = container as UIElement;

            if (ui == null)
            {
                return(null);
            }

            // ui appeared in items collection
            ItemsControl ic = (ui as FrameworkElement)?.Parent as ItemsControl;

            if (ic != null)
            {
                // this is the right ItemsControl as long as the item
                // is (or is eligible to be) its own container
                IGeneratorHost host = ic as IGeneratorHost;
                if (host.IsItemItsOwnContainer(ui))
                {
                    return(ic);
                }
                else
                {
                    return(null);
                }
            }

            ui = VisualTreeHelper.GetParent(ui) as UIElement;

            return(ItemsControl.GetItemsOwner(ui));
        }
Пример #3
0
        public ItemContainerGenerator(IGeneratorHost host)
        {
            this.host = host;
            this.host.View.CollectionChanged += OnViewCollectionChanged;

            this.generatedContainers = new List<GeneratedItemContainer>();
        }
Пример #4
0
 private ItemContainerGenerator(ItemContainerGenerator parent, IGeneratorHost host, DependencyObject peer, int level)
 {
     _parent = parent;
     _host = host;
     _peer = peer;
     _level = level;
     OnRefresh();
 }
Пример #5
0
        //------------------------------------------------------
        //
        //  Constructors
        //
        //------------------------------------------------------

        /// <summary> Constructor </summary>
        /// <parameter name="host"> the control that owns the items </parameter>
        internal ItemContainerGenerator(IGeneratorHost host)
            : this(null, host, host as DependencyObject, 0)
        {
            // The top-level generator always listens to changes from ItemsCollection.
            // It needs to get these events before anyone else, so that other listeners
            // can call the generator's mapping functions with correct results.
            CollectionChangedEventManager.AddHandler(host.View, OnCollectionChanged);
        }
Пример #6
0
        public ItemsGenerator(IGeneratorHost generatorHost)
        {
            _items        = new List <ItemInfo>();
            GeneratorHost = generatorHost;

            _virtualizedItems = new List <ItemInfo>();
            _realizedItems    = new List <ItemInfo>();
        }
Пример #7
0
        internal void HandleItemsChanged(NotifyCollectionChangedEventArgs e)
        {
            if (this.ItemsHost == null)
            {
                return;
            }

            IGeneratorHost host = (IGeneratorHost)this;

            if (e.Action == NotifyCollectionChangedAction.Reset)
            {
                this.Refresh();
            }
            else if (e.Action == NotifyCollectionChangedAction.Add)
            {
                object           item      = e.NewItems[0];
                DependencyObject container = host.GetContainerForItem(item, null);
                if (container != item)
                {
                    container.SetValue(FrameworkElement.DataContextProperty, item);
                }
                host.PrepareItemContainer(container, item);

                this.ItemContainerGenerator.INTERNAL_RegisterContainer(container, item);

                this.ItemsHost.Children.Insert(e.NewStartingIndex, (UIElement)container);
            }
            else if (e.Action == NotifyCollectionChangedAction.Remove)
            {
                this.ItemContainerGenerator.INTERNAL_TryUnregisterContainer(
                    this.ItemsHost.Children[e.OldStartingIndex],
                    e.OldItems[0]);

                this.ItemsHost.Children.RemoveAt(e.OldStartingIndex);
            }
            else if (e.Action == NotifyCollectionChangedAction.Replace)
            {
                this.ItemContainerGenerator.INTERNAL_TryUnregisterContainer(
                    this.ItemsHost.Children[e.OldStartingIndex],
                    e.OldItems[0]);

                object           item      = e.NewItems[0];
                DependencyObject container = host.GetContainerForItem(item, null);
                if (container != item)
                {
                    container.SetValue(FrameworkElement.DataContextProperty, item);
                }
                host.PrepareItemContainer(container, item);

                this.ItemContainerGenerator.INTERNAL_RegisterContainer(container, item);

                this.ItemsHost.Children[e.OldStartingIndex] = (UIElement)container;
            }
            else
            {
                throw new NotSupportedException(string.Format("Unexpected collection change action '{0}'.", e.Action));
            }
        }
Пример #8
0
        private void OnItemRemoved(object item, int position)
        {
            IGeneratorHost   host      = this;
            DependencyObject container = this.ItemsHost.Children[position];

            this.ItemContainerGenerator.INTERNAL_TryUnregisterContainer(container, item);
            this.ItemsHost.Children.RemoveAt(position);

            host.ClearContainerForItem(container, item);
        }
Пример #9
0
        // Token: 0x060064C8 RID: 25800 RVA: 0x001C435C File Offset: 0x001C255C
        internal static XmlDataProvider XmlDataProviderForElement(DependencyObject d)
        {
            IGeneratorHost    generatorHost     = Helper.GeneratorHostForElement(d);
            ItemCollection    itemCollection    = (generatorHost != null) ? generatorHost.View : null;
            ICollectionView   collectionView    = (itemCollection != null) ? itemCollection.CollectionView : null;
            XmlDataCollection xmlDataCollection = (collectionView != null) ? (collectionView.SourceCollection as XmlDataCollection) : null;

            if (xmlDataCollection == null)
            {
                return(null);
            }
            return(xmlDataCollection.ParentXmlDataProvider);
        }
Пример #10
0
        internal void Refresh(bool reuseContainers)
        {
            IGeneratorHost host = this;

            DependencyObject[] oldContainers = new DependencyObject[Math.Max(this.ItemsHost.Children.Count, this.Items.CountInternal)];

            // First we need to get the containers and their associated item,
            // or they will be lost before being able to clear them.
            int containersCount = this.ItemsHost.Children.Count;

            object[] oldItems = new object[containersCount];
            for (int i = 0; i < containersCount; ++i)
            {
                DependencyObject container = this.ItemsHost.InternalChildren[i];
                oldContainers[i] = container;
                oldItems[i]      = this.ItemContainerGenerator.ItemFromContainer(container);
            }

            if (!reuseContainers)
            {
                this.ItemsHost.InternalChildren.Clear();
                this.ItemContainerGenerator.INTERNAL_Clear();

                for (int i = 0; i < containersCount; ++i)
                {
                    host.ClearContainerForItem(oldContainers[i], oldItems[i]);
                }
            }

            int count = this.Items.CountInternal;

            for (int i = 0; i < count; ++i)
            {
                object           item = this.Items[i];
                DependencyObject recycledContainer = reuseContainers ? oldContainers[i] : null;
                DependencyObject container         = host.GetContainerForItem(item, recycledContainer);

                if (!reuseContainers)
                {
                    this.ItemContainerGenerator.INTERNAL_RegisterContainer(container, item);
                    if (container != item)
                    {
                        container.SetValue(FrameworkElement.DataContextProperty, item);
                    }
                    this.ItemsHost.Children.Add((UIElement)container);
                }

                host.PrepareItemContainer(container, item);
            }
        }
Пример #11
0
        private void OnItemAdded(object item, int position)
        {
            IGeneratorHost   host      = this;
            DependencyObject container = host.GetContainerForItem(item, null);

            this.ItemContainerGenerator.INTERNAL_RegisterContainer(container, item);
            if (container != item)
            {
                container.SetValue(DataContextProperty, item);
            }

            this.ItemsHost.Children.Insert(position, (UIElement)container);

            host.PrepareItemContainer(container, item);
        }
Пример #12
0
        internal void Refresh()
        {
            IGeneratorHost host = (IGeneratorHost)this;

            this.ItemsHost.Children.Clear();
            this.ItemContainerGenerator.INTERNAL_Clear();
            foreach (var item in this.Items)
            {
                DependencyObject container = host.GetContainerForItem(item, null);
                if (container != item)
                {
                    container.SetValue(FrameworkElement.DataContextProperty, item);
                }
                host.PrepareItemContainer(container, item);

                this.ItemContainerGenerator.INTERNAL_RegisterContainer(container, item);

                this.ItemsHost.Children.Add((UIElement)container);
            }
        }
Пример #13
0
        internal static void UnlinkContainerFromItem(DependencyObject container, object item, IGeneratorHost host)
        {
            // When a container is removed from the tree, its future takes one of
            // two forms:
            //      a) [normal mode] the container becomes eligible for GC
            //      b) [recycling mode] the container joins the recycled list, and
            //          possibly re-enters the tree at some point, usually with a
            //          different item.
            //
            // As Dev10 bug 452669 and some "subtle issues" that arose in the
            // container recycling work illustrate, it's important that the container
            // and its subtree sever their connection to the data item.  Otherwise
            // you can get aliasing - a dead container reacting to the same item as a live
            // container.  Even without aliasing, it's a perf waste for a dead container
            // to continue reacting to its former data item.
            //
            // On the other hand, it's a perf waste to spend too much effort cleaning
            // up the container and its subtree, since they will often just get GC'd
            // in the near future.
            //
            // WPF initially did a full cleanup of the container, removing all properties
            // that were set in PrepareContainerForItem.  This avoided aliasing, but
            // was deemed too expensive, especially for scrolling.  For Windows OS Bug
            // 1445288, all this cleanup work was removed.  This sped up scrolling, but
            // introduced the problems cited in Dev10 452669 and the recycling "subtle
            // issues".  A compromise is needed.
            //
            // The compromise is tell the container to attach to a sentinel item
            // BindingExpressionBase.DisconnectedItem.  We allow this to propagate into the
            // conainer's subtree through properties like DataContext and
            // ContentControl.Content that are normally set by PrepareItemForContainer.
            // A Binding that sees the sentinel as the data item will disconnect its
            // event listeners from the former data item, but will not change its
            // own value or invalidate its target property.  This avoids the cost
            // of re-measuring most of the subtree.

            container.ClearValue(ItemForItemContainerProperty);

            // TreeView virtualization requires that we call ClearContainer before setting
            // the DataContext to "Disconnected".  This gives the TreeViewItems a chance
            // to save "Item values" in the look-aside table, before that table is
            // discarded.   (See Dev10 628778)
            host.ClearContainerForItem(container, item);

            if (container != item)
            {
                DependencyProperty dp = FrameworkElement.DataContextProperty;

                #if DEBUG
                // Some ancient code at this point handled the case when DataContext
                // was set via an Expression (presumably a binding).  I don't think
                // this actually happens any more.  Just in case...
                EntryIndex entryIndex = container.LookupEntry(dp.GlobalIndex);
                Debug.Assert(!container.HasExpression(entryIndex, dp), "DataContext set by expression (unexpectedly)");
                #endif

                container.SetValue(dp, BindingExpressionBase.DisconnectedItem);
            }
        }