Skip to content

Custom Region Adapters

Damian edited this page Mar 29, 2024 · 2 revisions

Region Adapters

GridRegionAdapter

using Avalonia.Controls;
using Prism.Regions;

namespace SuessLabs.PrismAvalonia.RegionAdapters;

[System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]
public class GridRegionAdapter : RegionAdapterBase<Grid>
{
    public GridRegionAdapter(IRegionBehaviorFactory regionBehaviorFactory)
      : base(regionBehaviorFactory)
    {
    }

    protected override void Adapt(IRegion region, Grid regionTarget)
    {
        region.Views.CollectionChanged += (sender, e) =>
        {
            if (e.Action == System.Collections.Specialized.NotifyCollectionChangedAction.Add)
            {
                foreach (Control item in e.NewItems)
                {
                    if (e.NewItems != null)
                        regionTarget.Children.Add(item);
                }
            }

            if (e.Action == System.Collections.Specialized.NotifyCollectionChangedAction.Remove)
            {
                foreach (Control item in e.OldItems)
                {
                    if (e.OldItems != null)
                        regionTarget.Children.Remove(item);
                }
            }
        };
    }

    protected override IRegion CreateRegion() => new SingleActiveRegion() { };
}

ItemsControlRegionAdapter

    /// <summary>
    /// Adapter that creates a new <see cref="AllActiveRegion"/> and binds all the views to the
    /// adapted <see cref="ItemsControl"/>.
    /// </summary>
    public class ItemsControlRegionAdapter : RegionAdapterBase<ItemsControl>
    {
        #region Public Constructors

        /// <summary>
        /// Initializes a new instance of <see cref="ItemsControlRegionAdapter"/>.
        /// </summary>
        /// <param name="regionBehaviorFactory">
        /// The factory used to create the region behaviors to attach to the created regions.
        /// </param>
        public ItemsControlRegionAdapter(IRegionBehaviorFactory regionBehaviorFactory)
            : base(regionBehaviorFactory)
        {
        }

        #endregion Public Constructors

        #region Protected Methods

        /// <summary>
        /// Adapts an <see cref="ItemsControl"/> to an <see cref="IRegion"/>.
        /// </summary>
        /// <param name="region">The new region being used.</param>
        /// <param name="regionTarget">The object to adapt.</param>
        protected override void Adapt(IRegion region, ItemsControl regionTarget)
        {
            // If the region or control is null, throw an exception
            if (region == null)
                throw new ArgumentNullException(nameof(region));
            if (regionTarget == null)
                throw new ArgumentNullException(nameof(regionTarget));

            // If the control has child items, move them to the region in advance of binding the control
            // to the region.
            if (regionTarget.ItemCount > 0)
            {
                foreach (object? childItem in regionTarget.Items)
                {
                    region.Add(childItem);
                }
            }

            // Avalonia v11-Preview5 needs IRegion to implement IList. Enforcing it to return
            // AvaloniaList<object> fixes this. Avalonia v11-Preview8 ItemsControl.Items is readonly
            // (#10827). regionTarget.Items = region.Views as
            // Avalonia.Collections.AvaloniaList<object>; var views = region.Views as
            // Avalonia.Collections.AvaloniaList<object>; regionTarget.ItemsSource = region.Views as Avalonia.Collections.AvaloniaList<object>;

            // Detect when an item has been added/removed to the ItemsControl's backing region. Copy
            // all items to a new collection and bind to the region's ItemsSource
            region.Views.CollectionChanged += (s, e) =>
            {
                var enumerator = region.Views.GetEnumerator();
                List<object> items = new();
                while (enumerator.MoveNext())
                {
                    items.Add(enumerator.Current);
                }
                regionTarget.ItemsSource = items;
            };
        }

        /// <summary>
        /// Creates a new instance of <see cref="AllActiveRegion"/>.
        /// </summary>
        /// <returns>A new instance of <see cref="AllActiveRegion"/>.</returns>
        protected override IRegion CreateRegion()
        {
            return new AllActiveRegion();
        }

        #endregion Protected Methods
    }

StackPanelRegionAdapter

using Avalonia.Controls;
using Prism.Regions;

namespace SuessLabs.PrismAvalonia.RegionAdapters;

[System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]
public class StackPanelRegionAdapter : RegionAdapterBase<StackPanel>
{
    public StackPanelRegionAdapter(IRegionBehaviorFactory regionBehaviorFactory)
      : base(regionBehaviorFactory)
    {
    }

    protected override void Adapt(IRegion region, StackPanel regionTarget)
    {
        region.Views.CollectionChanged += (sender, e) =>
        {
            if (e.Action == System.Collections.Specialized.NotifyCollectionChangedAction.Add)
            {
                foreach (Control item in e.NewItems)
                {
                    if (e.NewItems != null)
                        regionTarget.Children.Add(item);
                }
            }

            if (e.Action == System.Collections.Specialized.NotifyCollectionChangedAction.Remove)
            {
                foreach (Control item in e.OldItems)
                {
                    if (e.OldItems != null)
                        regionTarget.Children.Remove(item);
                }
            }
        };
    }

    protected override IRegion CreateRegion() => new SingleActiveRegion() { };
}