/// <summary> /// Gets the actual item template size, using a non-databound materialized /// view of the template. /// </summary> /// <param name="dataTemplate">A data template</param> /// <returns>The actual size of the template</returns> private CGSize GetTemplateSize(DataTemplate dataTemplate, NSString elementKind) { //TODO: this should take an available breadth CGSize size; // Cache the sizes to avoid creating new templates everytime. if (!_templateCache.TryGetValue(dataTemplate ?? _nullDataTemplateKey, out size)) { var container = CreateContainerForElementKind(elementKind); // Force a null DataContext so the parent's value does not flow // through when temporarily adding the container to Owner.XamlParent container.SetValue(FrameworkElement.DataContextProperty, null); Style style = null; if (elementKind == NativeListViewBase.ListViewItemElementKind) { style = Owner.ItemContainerStyle; } else if (elementKind == NativeListViewBase.ListViewSectionHeaderElementKind) { style = Owner.GroupStyle?.HeaderContainerStyle; } if (style != null) { container.Style = style; } container.ContentTemplate = dataTemplate; try { // Attach templated container to visual tree while measuring. This works around the bug that default Style is not // applied until view is loaded. Owner.XamlParent.AddSubview(BlockLayout); BlockLayout.AddSubview(container); // Measure with PositiveInfinity rather than MaxValue, since some views handle this better. size = Owner.NativeLayout.Layouter.MeasureChild(container, new Size(double.PositiveInfinity, double.PositiveInfinity)); if ((size.Height > nfloat.MaxValue / 2 || size.Width > nfloat.MaxValue / 2) && this.Log().IsEnabled(LogLevel.Warning) ) { this.Log().LogWarning($"Infinite item size reported, this can crash {nameof(UICollectionView)}."); } } finally { Owner.XamlParent.RemoveChild(BlockLayout); BlockLayout.RemoveChild(container); // Reset the DataContext for reuse. container.ClearValue(FrameworkElement.DataContextProperty); } _templateCache[dataTemplate ?? _nullDataTemplateKey] = size; } return(size); }
/// <summary> /// Gets the actual item template size, using a non-databound materialized /// view of the template. /// </summary> /// <param name="dataTemplate">A data template</param> /// <returns>The actual size of the template</returns> private CGSize GetTemplateSize(DataTemplate dataTemplate, NSString elementKind) { //TODO: this should take an available breadth CGSize size; // Cache the sizes to avoid creating new templates everytime. if (!_templateCache.TryGetValue(dataTemplate ?? _nullDataTemplateKey, out size)) { var container = CreateContainerForElementKind(elementKind); Style style = null; if (elementKind == NativeListViewBase.ListViewItemElementKind) { style = Owner.ItemContainerStyle; } else if (elementKind == NativeListViewBase.ListViewSectionHeaderElementKind) { style = Owner.GroupStyle?.HeaderContainerStyle; } if (style != null) { container.Style = style; } container.ContentTemplate = dataTemplate; try { // Attach templated container to visual tree while measuring. This works around the bug that default Style is not // applied until view is loaded. Owner.XamlParent.AddSubview(BlockLayout); BlockLayout.AddSubview(container); size = Owner.NativeLayout.Layouter.MeasureChild(container, new Size(double.MaxValue, double.MaxValue)); if ((size.Height > nfloat.MaxValue / 2 || size.Width > nfloat.MaxValue / 2) && this.Log().IsEnabled(LogLevel.Warning) ) { this.Log().LogWarning($"Infinite item size reported, this can crash {nameof(UICollectionView)}."); } } finally { Owner.XamlParent.RemoveChild(BlockLayout); BlockLayout.RemoveChild(container); } _templateCache[dataTemplate ?? _nullDataTemplateKey] = size; } return(size); }