public ViewManager(ItemsRepeater owner) { // ItemsRepeater is not fully constructed yet. Don't interact with it. m_owner = owner; m_resetPool = new UniqueIdElementPool(owner); m_lastFocusedElement = owner; m_phaser = new Phaser(owner); m_ElementFactoryGetArgs = new ElementFactoryGetArgs(); m_ElementFactoryRecycleArgs = new ElementFactoryRecycleArgs(); }
protected override UIElement GetElementCore(ElementFactoryGetArgs args) { if (m_templates is null || m_templates.Count == 0) { throw new InvalidOperationException("Templates property cannot be null or empty."); } var winrtOwner = args.Parent; var templateKey = m_templates.Count == 1 ? m_templates.First().Key : OnSelectTemplateKeyCore(args.Data, winrtOwner); if (string.IsNullOrEmpty(templateKey)) { // Note: We could allow null/whitespace, which would work as long as // the recycle pool is not shared. in order to make this work in all cases // currently we validate that a valid template key is provided. throw new InvalidOperationException("Template key cannot be empty or null."); } // Get an element from the Recycle Pool or create one var element = m_recyclePool.TryGetElement(templateKey, winrtOwner) as FrameworkElement; if (element is null) { // No need to call HasKey if there is only one template. if (m_templates.Count > 1 && !m_templates.ContainsKey(templateKey)) { string message = "No templates of key " + templateKey + " were found in the templates collection."; throw new InvalidOperationException(message); } var dataTemplate = m_templates[templateKey]; element = dataTemplate.LoadContent() as FrameworkElement; // Associate ReuseKey with element RecyclePool.SetReuseKey(element, templateKey); } return(element); }
protected override UIElement GetElementCore(Microsoft.UI.Xaml.Controls.ElementFactoryGetArgs args) { if (args.Data == null) { return(null); } Type dataType = args.Data.GetType(); if (dataType == typeof(int)) { return(new Button() { Content = args.Data, Tag = args.Data, Style = (Style)App.Current.Resources["NumberPanelButtonStyle"], }); } else { (args.Data as FrameworkElement).MinWidth = (double)App.Current.Resources["NumberPanelButtonWidth"]; return((UIElement)args.Data); } }
protected override UIElement GetElementCore(ElementFactoryGetArgs args) { object GetContent(IElementFactoryShim itemTemplateWrapper) { if (itemTemplateWrapper != null) { return(itemTemplateWrapper.GetElement(args)); } return(args.Data); } var newContent = GetContent(m_itemTemplateWrapper); // Element is already a RadioButton, so we just return it. var radioButton = newContent as RadioButton; if (radioButton != null) { return(radioButton); } // Element is not a RadioButton. We'll wrap it in a RadioButton now. var newRadioButton = new RadioButton(); newRadioButton.Content = args.Data; // If a user provided item template exists, we pass the template down to the ContentPresenter of the RadioButton. var itemTemplateWrapper = m_itemTemplateWrapper as ItemTemplateWrapper; if (itemTemplateWrapper != null) { newRadioButton.ContentTemplate = itemTemplateWrapper.Template; } return(newRadioButton); }
// 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 a UIElement . the data is returned // 1.2 If data is not a UIElement . 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 a FrameworkElement . Element is fetched from ElementFactory and DataContext is set to the data** // 2.2 If data is a FrameworkElement: // 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** // // **data context is set only if no x:Bind was used. ie. No data template component on the root. UIElement GetElementFromElementFactory(int index) { // The view generator is the provider of last resort. var data = m_owner.ItemsSourceView.GetAt(index); UIElement GetElement() { var elementFactory = m_owner.ItemTemplateShim; if (elementFactory == null) { if (data is UIElement dataAsElement) { return(dataAsElement); } else { // If no ItemTemplate was provided, use a default //var factory = XamlReader.Load("<DataTemplate xmlns='http://schemas.microsoft.com/winfx/2006/xaml/presentation'><TextBlock Text='{Binding}'/></DataTemplate>") as DataTemplate; var factory = new DataTemplate(() => { var tb = new TextBlock(); tb.SetBinding(TextBlock.TextProperty, new Binding()); return(tb); }); m_owner.ItemTemplate = factory; elementFactory = m_owner.ItemTemplateShim; } } if (m_ElementFactoryGetArgs == null) { m_ElementFactoryGetArgs = new ElementFactoryGetArgs(); } var args = m_ElementFactoryGetArgs; using var scopeGuard = Disposable.Create(() => { args.Data = null; args.Parent = null; }); args.Data = data; args.Parent = m_owner; args.Index = index; return(elementFactory.GetElement(args)); }; var element = GetElement(); var virtInfo = ItemsRepeater.TryGetVirtualizationInfo(element); if (virtInfo == null) { virtInfo = ItemsRepeater.CreateAndInitializeVirtualizationInfo(element); REPEATER_TRACE_PERF("ElementCreated"); } else { // View obtained from ElementFactory already has a VirtualizationInfo attached to it // which means that the element has been recycled and not created from scratch. REPEATER_TRACE_PERF("ElementRecycled"); } if (data != element) { // Prepare the element // If we are phasing, run phase 0 before setting DataContext. If phase 0 is not // run before setting DataContext, when setting DataContext all the phases will be // run in the OnDataContextChanged handler in code generated by the xaml compiler (code-gen). var extension = CachedVisualTreeHelpers.GetDataTemplateComponent(element); if (extension != null) { // Clear out old data. extension.Recycle(); int nextPhase = VirtualizationInfo.PhaseReachedEnd; // Run Phase 0 extension.ProcessBindings(data, index, 0 /* currentPhase */, out nextPhase); // Setup phasing information, so that Phaser can pick up any pending phases left. // Update phase on virtInfo. Set data and templateComponent only if x:Phase was used. virtInfo.UpdatePhasingInfo(nextPhase, nextPhase > 0 ? data : null, nextPhase > 0 ? extension : null); } else if (element is FrameworkElement elementAsFE) { // Set data context only if no x:Bind was used. ie. No data template component on the root. // If the passed in data is a UIElement and is different from the element returned by // the template factory then we need to propagate the DataContext. // Otherwise just set the DataContext on the element as the data. var elementDataContext = data; if (data is FrameworkElement dataAsElement) { var dataDataContext = dataAsElement.DataContext; if (dataDataContext != null) { elementDataContext = dataDataContext; } } elementAsFE.DataContext = elementDataContext; } else { MUX_ASSERT(false, "Element returned by factory is not a FrameworkElement!"); } } virtInfo.MoveOwnershipToLayoutFromElementFactory( index, /* uniqueId: */ m_owner.ItemsSourceView.HasKeyIndexMapping ? m_owner.ItemsSourceView.KeyFromIndex(index) : null); // The view generator is the only provider that prepares the element. var repeater = m_owner; #if IS_UNO //TODO: Uno specific - remove when #4689 is fixed repeater.OnUnoBeforeElementPrepared(element, index); #endif // 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 (CachedVisualTreeHelpers.GetParent(element) != repeater) { children.Add(element); } repeater.AnimationManager.OnElementPrepared(element); repeater.OnElementPrepared(element, index); if (data != element) { m_phaser.PhaseElement(element, virtInfo); } // Update realized indices m_firstRealizedElementIndexHeldByLayout = Math.Min(m_firstRealizedElementIndexHeldByLayout, index); m_lastRealizedElementIndexHeldByLayout = Math.Max(m_lastRealizedElementIndexHeldByLayout, index); return(element); }
// Retrieve the element that will be displayed for a specific data item. // If the resolved element is not derived from NavigationViewItemBase, wrap in a NavigationViewItem before returning. protected override UIElement GetElementCore(ElementFactoryGetArgs args) { object GetNewContent(IElementFactoryShim itemTemplateWrapper, NavigationViewItemBase settingsItem) { // Do not template SettingsItem if (settingsItem != null && settingsItem == args.Data) { return(args.Data); } if (itemTemplateWrapper != null) { return(itemTemplateWrapper.GetElement(args)); } return(args.Data); } var newContent = GetNewContent(m_itemTemplateWrapper, m_settingsItem); // Element is already of expected type, just return it if (newContent is NavigationViewItemBase newItem) { return(newItem); } #if !HAS_UNO_WINUI // Accidentally adding a OS XAML NavigationViewItem to WinUI's NavigationView can cause unnecessary confusion for developers // due to unexpected rendering, potentially without an easy way to understand what went wrong here. To help out developers, // we are explicitly checking for this scenario here and throw a helpful error message so that they can quickly fix their app. if (newContent is Windows.UI.Xaml.Controls.NavigationViewItemBase) { throw new InvalidOperationException("A NavigationView instance contains a Windows.UI.Xaml.Controls.NavigationViewItem. This control requires that its NavigationViewItems be of type Microsoft.UI.Xaml.Controls.NavigationViewItem."); } #endif // Get or create a wrapping container for the data NavigationViewItem GetNavigationViewItem() { if (navigationViewItemPool.Count > 0) { var nvi = navigationViewItemPool[navigationViewItemPool.Count - 1]; navigationViewItemPool.RemoveAt(navigationViewItemPool.Count - 1); return(nvi); } return(new NavigationViewItem()); } var nvi = GetNavigationViewItem(); var nviImpl = nvi; nviImpl.CreatedByNavigationViewItemsFactory = true; // If a user provided item template exists, just pass the template and data down to the ContentPresenter of the NavigationViewItem if (m_itemTemplateWrapper != null) { if (m_itemTemplateWrapper is ItemTemplateWrapper itemTemplateWrapper) { // Recycle newContent var tempArgs = new ElementFactoryRecycleArgs(); tempArgs.Element = newContent as UIElement; m_itemTemplateWrapper.RecycleElement(tempArgs); nviImpl.Content = args.Data; nviImpl.ContentTemplate = itemTemplateWrapper.Template; nviImpl.ContentTemplateSelector = itemTemplateWrapper.TemplateSelector; return(nviImpl); } } nviImpl.Content = newContent; return(nviImpl); }
protected virtual UIElement GetElementCore(ElementFactoryGetArgs args) => throw new NotImplementedException();
public UIElement GetElement(ElementFactoryGetArgs args) => GetElementCore(args);