【问题标题】:Custome StackPanel Prism RegionAdapter to support Ordering自定义 StackPanel Prism 区域适配器以支持订购
【发布时间】:2013-07-12 08:41:18
【问题描述】:

我有以下用于 StackPanel 的 RegionAdapter 实现,但我需要对与区域关联的项目进行严格排序,谁能帮忙?

我希望将自己注册到区域的视图能够控制那里的位置,也许是某种索引号

    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;
            }
        };
    }

【问题讨论】:

    标签: silverlight prism silverlight-5.0 prism-4 regionadapter


    【解决方案1】:

    如何解决这个问题很大程度上取决于排序是指 (a) 视图的类型还是 (b) 视图的实例。如果您只想指定例如ViewA 类型的视图应该在ViewB 类型的视图之上,则属于前者。如果您想指定如何对同一视图类型的多个具体实例进行排序,则属于后者。

    A.按类型排序

    On 选项是实现一个自定义属性,例如OrderIndexAttribute,它公开一个整数属性:

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

    使用该属性标记您的视图类:

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

    将视图添加到区域时获取类型的属性:

    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.按实例排序

    让你的视图实现一个接口:

    public interface ISortedView 
    {
       int Index { get; }
    }
    

    在将视图添加到区域时,尝试将插入的视图投射到界面,读取索引,然后执行与上述相同的操作:

    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 }
        }
    

    【讨论】:

      【解决方案2】:

      我发现 Marc 的“A. Sort type wise”案例对我的情况非常有帮助。我需要使用 OrderIndexAttribute 将视图分类到区域中,如果视图实际上没有 OrderIndexAttribute,我仍然可以添加视图。

      正如您将在下面看到的,我通过跟踪列表中的视图索​​引来做到这一点。没有该属性的视图的插入索引默认为零,以便它排序到 StackPanel 的前面(或顶部)。

      这篇原始帖子相当古老,但也许有人会像我一样偶然发现它,并且会发现我的贡献很有帮助。欢迎提出重构建议。 :-)

      public class StackPanelRegionAdapter : RegionAdapterBase<StackPanel>
      {
          private readonly List<int> _indexList;
      
          public StackPanelRegionAdapter(IRegionBehaviorFactory behaviorFactory)
              : base(behaviorFactory)
          {
              _indexList = new List<int>();
          }
      
          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)
                          {
                              var viewType = element.GetType();
      
                              // Get the custom attributes for this view, if any
                              var customAttributes = viewType.GetCustomAttributes(false);
      
                              var viewIndex = 0;  // Default the viewIndex to zero
      
                              // Determine if the view has the OrderIndexAttribute.
                              // If it does have the OrderIndexAttribute, get its sort index.
                              if (HasThisAttribute(customAttributes))
                              {
                                  viewIndex= viewType.GetCustomAttribute<OrderIndexAttribute>().Index;
                              }
                              
                              // Get the insertion index
                              var insertionIndex = GetInsertionIndex(viewIndex);
      
                              regionTarget.Children.Insert(insertionIndex, element);
                          }
                          break;
      
                      case NotifyCollectionChangedAction.Remove:
                          foreach (UIElement elementLoopVariable in e.OldItems)
                          {
                              var element = elementLoopVariable;
                              if (regionTarget.Children.Contains(element))
                              {
                                  regionTarget.Children.Remove(element);
                              }
                          }
                          break;
                  }
              };
          }
      
          private static bool HasThisAttribute(IReadOnlyList<object> customAttributes)
          {
              // Determine if the view has the OrderIndexAttribute
              if (customAttributes.Count == 0) return false;
              for (var i = 0; i < customAttributes.Count; i++)
              {
                  var name = customAttributes[i].GetType().Name;
                  if (name == "OrderIndexAttribute") return true;
              }
      
              return false;
          }
      
          private int GetInsertionIndex(in int viewIndex)
          {
              // Add the viewIndex to the index list if not already there
              if (_indexList.Contains(viewIndex) == false)
              {
                  _indexList.Add(viewIndex);
                  _indexList.Sort();
              }
      
              // Return the list index of the viewIndex
              for (var i = 0; i < _indexList.Count; i++)
              {
                  if (_indexList[i].Equals(viewIndex))
                  {
                      return i;
                  }
              }
      
              return 0;
          }
      
          protected override IRegion CreateRegion()
          {
              return new AllActiveRegion();
          }
      }
      

      【讨论】:

        【解决方案3】:

        Marc 和 R.Evans 的回答帮助我创建了自己的更多通用 RegionAdapter,并进行了以下改进:

        • 使用ViewSortHint 兼容Prism 6
        • Prism 7 / .Net 5 兼容
        • 在多个适配器中使用的助手类
        • 更少的代码

        适配方法:

            protected override void Adapt(IRegion region, StackPanel regionTarget)
            {
                region.Views.CollectionChanged += (s, e) =>
                {
                    if (e.Action == NotifyCollectionChangedAction.Add)
                        foreach (FrameworkElement item in e.NewItems)
                        {
                            regionTarget.Children.Insert(regionTarget.Children.GetInsertionIndex(item), item);
                        }
                    else if (e.Action == NotifyCollectionChangedAction.Remove)
                        foreach (UIElement item in e.OldItems)
                        {
                            if (regionTarget.Children.Contains(item))
                            {
                                regionTarget.Children.Remove(item);
                            }
                        }
                };
            }
        

        助手/扩展:

        internal static int GetInsertionIndex(this IList items, in object newItem)
            {
                // Return the list index of the viewIndex
                foreach (object item in items)
                {
                    var currentIndex = item.GetType().GetCustomAttribute<ViewSortHintAttribute>()?.Hint ?? "0";
                    var intendedIndex = newItem.GetType().GetCustomAttribute<ViewSortHintAttribute>()?.Hint ?? "0";
        
                    if (currentIndex.CompareTo(intendedIndex) >= 0)
                        return items.IndexOf(item);
                }
        
                // if no greater index is found, insert the item at the end
                return items.Count;
            }
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2010-11-07
          • 1970-01-01
          • 2022-01-06
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多