public ItemContainerGenerator(IGeneratorHost host) { this.host = host; this.host.View.CollectionChanged += OnViewCollectionChanged; this.generatedContainers = new List <GeneratedItemContainer>(); }
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)); }
public ItemContainerGenerator(IGeneratorHost host) { this.host = host; this.host.View.CollectionChanged += OnViewCollectionChanged; this.generatedContainers = new List<GeneratedItemContainer>(); }
private ItemContainerGenerator(ItemContainerGenerator parent, IGeneratorHost host, DependencyObject peer, int level) { _parent = parent; _host = host; _peer = peer; _level = level; OnRefresh(); }
//------------------------------------------------------ // // 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); }
public ItemsGenerator(IGeneratorHost generatorHost) { _items = new List <ItemInfo>(); GeneratorHost = generatorHost; _virtualizedItems = new List <ItemInfo>(); _realizedItems = new List <ItemInfo>(); }
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)); } }
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); }
// 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); }
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); } }
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); }
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); } }
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); } }