Search code examples
silverlightprismsilverlight-5.0prism-4regionadapter

Custome StackPanel Prism RegionAdapter to support Ordering


I have the following implementation of RegionAdapter for a StackPanel but I need strict ordering of items I associate with a region can anyone help?

I want Views that Register themselves to the Region to be able to control there position maybe an index number of some sort

    protected override void Adapt(IRegion region, StackPanel regionTarget)
    {
        region.Views.CollectionChanged += (sender, e) =>
        {
            switch (e.Action)
            {
                case NotifyCollectionChangedAction.Add:
                    foreach (FrameworkElement element in e.NewItems)
                    {
                        regionTarget.Children.Add(element);
                    }

                    break;

                case NotifyCollectionChangedAction.Remove:
                    foreach (UIElement elementLoopVariable in e.OldItems)
                    {
                        var element = elementLoopVariable;
                        if (regionTarget.Children.Contains(element))
                        {
                            regionTarget.Children.Remove(element);
                        }
                    }

                    break;
            }
        };
    }

Solution

  • How to tackle this greatly depends on whether the sorting refers to (a) the type of the view or (b) to the instance of the view. The former would be the case if you only wanted to specify that for example Views of type ViewA should be above Views of type ViewB. The latter is the case if you want to specify how several concrete instances of the same view type are sorted.

    A. Sort type wise

    On option is to implement a custom attribute, something like OrderIndexAttribute, which exposes an integer property:

    [AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]
    public OrderIndexAttribute : Attribute
    {
        public int Index { get; }
    
        public OrderIndexAttribute(int index)
        {
            Index = index;
        }
    }
    

    Mark your view class with that attribute:

    [OrderIndex(2)]
    public ViewA : UserControl
    {...}
    

    Get the attribute of the type when adding the view to the region:

    case NotifyCollectionChangedAction.Add:
        foreach (FrameworkElement element in e.NewItems)
        {
            // Get index for view
            var viewType = element.GetType();
            var viewIndex= viewType.GetCustomAttribute<OrderIndexAttribute>().Index;
            // This method needs to iterate through the views in the region and determine
            // where a view with the specified index needs to be inserted
            var insertionIndex = GetInsertionIndex(viewIndex);
            regionTarget.Children.Insert(insertionIndex, element);
        }
        break;
    

    B. Sort instance wise

    Make your views implement an interface:

    public interface ISortedView 
    {
       int Index { get; }
    }
    

    On adding the view to the region, try casting the inserted view to the interface, read the index and then do the same as above:

    case NotifyCollectionChangedAction.Add:
        foreach (FrameworkElement element in e.NewItems)
        {
            // Get index for view
            var sortedView = element as ISortedView;
            if (sortedView != null)
            {
                var viewIndex = sortedView.Index;
                // This method needs to iterate through the views in the region and determine
                // where a view with the specified index needs to be inserted
                var insertionIndex = GetInsertionIndex(viewIndex);
                regionTarget.Children.Insert(insertionIndex, sortedView);
            }
            else
            { // Add at the end of the StackPanel or reject adding the view to the region }
        }