using System; using Avalonia.Collections; using Avalonia.Controls.Presenters; using Avalonia.Controls.Templates; using Avalonia.Data; using Avalonia.LogicalTree; namespace Avalonia.Controls.Primitives { /// /// Represents a with a related header. /// public class HeaderedSelectingItemsControl : SelectingItemsControl, IContentPresenterHost { private IDisposable? _itemsBinding; private ItemsControl? _prepareItemContainerOnAttach; /// /// Defines the property. /// public static readonly StyledProperty HeaderProperty = HeaderedContentControl.HeaderProperty.AddOwner(); /// /// Defines the property. /// public static readonly StyledProperty HeaderTemplateProperty = HeaderedItemsControl.HeaderTemplateProperty.AddOwner(); /// /// Initializes static members of the class. /// static HeaderedSelectingItemsControl() { HeaderProperty.Changed.AddClassHandler((x, e) => x.HeaderChanged(e)); } /// /// Gets or sets the content of the control's header. /// public object? Header { get { return GetValue(HeaderProperty); } set { SetValue(HeaderProperty, value); } } /// /// Gets or sets the data template used to display the header content of the control. /// public IDataTemplate? HeaderTemplate { get => GetValue(HeaderTemplateProperty); set => SetValue(HeaderTemplateProperty, value); } /// /// Gets the header presenter from the control's template. /// public IContentPresenter? HeaderPresenter { get; private set; } /// IAvaloniaList IContentPresenterHost.LogicalChildren => LogicalChildren; /// bool IContentPresenterHost.RegisterContentPresenter(IContentPresenter presenter) { return RegisterContentPresenter(presenter); } protected override void OnAttachedToLogicalTree(LogicalTreeAttachmentEventArgs e) { base.OnAttachedToLogicalTree(e); if (_prepareItemContainerOnAttach is not null) { PrepareItemContainer(_prepareItemContainerOnAttach); _prepareItemContainerOnAttach = null; } } /// /// Called when an is registered with the control. /// /// The presenter. protected virtual bool RegisterContentPresenter(IContentPresenter presenter) { if (presenter.Name == "PART_HeaderPresenter") { HeaderPresenter = presenter; return true; } return false; } internal void PrepareItemContainer(ItemsControl parent) { _itemsBinding?.Dispose(); _itemsBinding = null; var item = Header; if (item is null) { _prepareItemContainerOnAttach = null; return; } var headerTemplate = HeaderTemplate ?? parent.ItemTemplate; if (headerTemplate is null) { if (((ILogical)this).IsAttachedToLogicalTree) headerTemplate = this.FindDataTemplate(item); else _prepareItemContainerOnAttach = parent; } if (headerTemplate is ITreeDataTemplate treeTemplate && treeTemplate.Match(item) && treeTemplate.ItemsSelector(item) is { } itemsBinding) { _itemsBinding = BindingOperations.Apply(this, ItemsSourceProperty, itemsBinding, null); } } private void HeaderChanged(AvaloniaPropertyChangedEventArgs e) { if (e.OldValue is ILogical oldChild) { LogicalChildren.Remove(oldChild); } if (e.NewValue is ILogical newChild) { LogicalChildren.Add(newChild); } } } }