private IControl GetElementFromElementFactory(int index) { // The view generator is the provider of last resort. var itemTemplateFactory = _owner.ItemTemplateShim; if (itemTemplateFactory == null) { // If no ItemTemplate was provided, use a default var factory = FuncDataTemplate.Default; _owner.ItemTemplate = factory; itemTemplateFactory = _owner.ItemTemplateShim; } var data = _owner.ItemsSourceView.GetAt(index); var element = itemTemplateFactory.GetElement(_owner, data); var virtInfo = ItemsRepeater.TryGetVirtualizationInfo(element); if (virtInfo == null) { virtInfo = ItemsRepeater.CreateAndInitializeVirtualizationInfo(element); } // Prepare the element element.DataContext = data; virtInfo.MoveOwnershipToLayoutFromElementFactory( index, /* uniqueId: */ _owner.ItemsSourceView.HasKeyIndexMapping ? _owner.ItemsSourceView.KeyFromIndex(index) : string.Empty); // The view generator is the only provider that prepares the element. var repeater = _owner; // Add the element to the children collection here before raising OnElementPrepared so // that handlers can walk up the tree in case they want to find their IndexPath in the // nested case. var children = repeater.Children; if (element.VisualParent != repeater) { children.Add(element); } repeater.OnElementPrepared(element, index); // Update realized indices _firstRealizedElementIndexHeldByLayout = Math.Min(_firstRealizedElementIndexHeldByLayout, index); _lastRealizedElementIndexHeldByLayout = Math.Max(_lastRealizedElementIndexHeldByLayout, index); return(element); }
// There are several cases handled here with respect to which element gets returned and when DataContext is modified. // // 1. If there is no ItemTemplate: // 1.1 If data is an IControl -> the data is returned // 1.2 If data is not an IControl -> a default DataTemplate is used to fetch element and DataContext is set to data // // 2. If there is an ItemTemplate: // 2.1 If data is not an IControl -> Element is fetched from ElementFactory and DataContext is set to the data // 2.2 If data is an IControl: // 2.2.1 If Element returned by the ElementFactory is the same as the data -> Element (a.k.a. data) is returned as is // 2.2.2 If Element returned by the ElementFactory is not the same as the data // -> Element that is fetched from the ElementFactory is returned and // DataContext is set to the data's DataContext (if it exists), otherwise it is set to the data itself private IControl GetElementFromElementFactory(int index) { // The view generator is the provider of last resort. var data = _owner.ItemsSourceView !.GetAt(index); var providedElementFactory = _owner.ItemTemplateShim; IElementFactory GetElementFactory() { if (providedElementFactory == null) { var factory = FuncDataTemplate.Default; _owner.ItemTemplate = factory; return(_owner.ItemTemplateShim !); } return(providedElementFactory); } IControl GetElement() { if (providedElementFactory == null) { if (data is IControl dataAsElement) { return(dataAsElement); } } var elementFactory = GetElementFactory(); var args = _elementFactoryGetArgs ??= new ElementFactoryGetArgs(); try { args.Data = data; args.Parent = _owner; args.Index = index; return(elementFactory.GetElement(args)); } finally { args.Data = null; args.Parent = null; } } var element = GetElement(); var virtInfo = ItemsRepeater.TryGetVirtualizationInfo(element); if (virtInfo == null) { virtInfo = ItemsRepeater.CreateAndInitializeVirtualizationInfo(element); } // Clear flag virtInfo.MustClearDataContext = false; if (data != element) { // Prepare the element element.DataContext = data; virtInfo.MustClearDataContext = true; } virtInfo.MoveOwnershipToLayoutFromElementFactory( index, /* uniqueId: */ _owner.ItemsSourceView.HasKeyIndexMapping ? _owner.ItemsSourceView.KeyFromIndex(index) : string.Empty); // The view generator is the only provider that prepares the element. var repeater = _owner; // Add the element to the children collection here before raising OnElementPrepared so // that handlers can walk up the tree in case they want to find their IndexPath in the // nested case. var children = repeater.Children; if (element.VisualParent != repeater) { children.Add(element); } repeater.OnElementPrepared(element, virtInfo); // Update realized indices _firstRealizedElementIndexHeldByLayout = Math.Min(_firstRealizedElementIndexHeldByLayout, index); _lastRealizedElementIndexHeldByLayout = Math.Max(_lastRealizedElementIndexHeldByLayout, index); return(element); }