【问题标题】:Prism for Silverlight: How to maintain views in a specific order inside a regionSilverlight 的 Prism:如何在区域内以特定顺序维护视图
【发布时间】:2011-01-03 17:56:49
【问题描述】:

我正在为 SL 创建一种“导航面板”(实际上是一个 ItemControl),并使用区域来允许每个模块将其链接添加到面板。

问题是模块加载不一致,因此面板中的链接顺序可能会根据模块加载顺序而改变。

限制模块顺序是不可能的。

其他可行的选项是绑定到ItemControl的区域的Views Collection的顺序,问题是ViewCollection非常有限,所以很难排序。

我错过了一个选项,你有什么想法吗?

谢谢 爱丽儿

【问题讨论】:

    标签: c# silverlight silverlight-4.0 prism


    【解决方案1】:

    我发现 Sam 的解决方案有效,但发现它在所有视图都已添加到该区域时执行排序,因此对视图进行了两次排序。

    虽然它仍然是一个有效的解决方案,但阅读 Prism 讨论中的 this 帖子让我想到了一种在加载区域时、但在添加任何视图之前实现它的方法。

    1 - 订阅 RegionChanged 集合

    我将它放在 Shell ViewModel 代码中,该代码与包含我要排序的区域的视图相关联。每当解决 IRegionManager 导入时,我都会订阅其 Regions 集合的 CollectionChanged 事件:

    this._regionManager.Regions.CollectionChanged +=
            new NotifyCollectionChangedEventHandler(Regions_CollectionChanged);
    

    2 - 更改事件委托中区域的 SortComparison

    然后,每当 Regions 集合更新时,代理 Regions_CollectionChanged 就会执行,并将更改我所需区域的 SortComparison

    void Regions_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
    {
        if (e.Action == NotifyCollectionChangedAction.Add)
        {
            foreach (var o in e.NewItems)
            {
                IRegion region = o as IRegion;
                if (region != null && region.Name == RegionNames.NavigationRegion)
                {
                    region.SortComparison = CompareNavigatorViews;
                }
            }
        }
    }
    

    3 - 定义 CompareNavigatorViews 委托

    在我的例子中,我只是按包含它们的程序集的标题对视图进行排序,您可以在此处实现自己的比较方法。请记住,您将在此处收到的对象是 View,而不是 ViewModel。

    private static int CompareNavigatorViews(object x, object y)
    {
        if (x == null)
            if (y == null)
                return 0;
            else
                return -1;
        else
            if (y == null)
                return 1;
            else
            {
                AssemblyInfo xAssemblyInfo = new AssemblyInfo(Assembly.GetAssembly(x.GetType()));
                AssemblyInfo yAssemblyInfo = new AssemblyInfo(Assembly.GetAssembly(y.GetType()));
    
                return String.Compare(xAssemblyInfo.Title, yAssemblyInfo.Title);
            }
    }
    

    以防万一有人问,AssemblyInfo 类是我制作的实用程序类。要获取程序集的标题,您可以使用此函数:

    string GetAssemblyTitle(Assembly assembly)
    {
        object[] attributes = assembly.GetCustomAttributes(typeof(AssemblyTitleAttribute), false);
        if (attributes.Length == 1)
        {
            return (attributes[0] as AssemblyTitleAttribute).Title;
        }
        else
        {
            // Return the assembly name if there is no title
            return this.GetType().Assembly.GetName().Name;
        }
    }
    

    希望这对某人有所帮助!

    【讨论】:

      【解决方案2】:

      在 Prism4 中,您只需将 ViewSortHintAttribute 应用于您的视图:

      [ViewSortHint("100")]
      class FirstView : UserControl { }
      
      [ViewSortHint("200")]
      class SecondView : UserControl { }
      

      区域上的默认排序比较器将选择此属性并对视图进行相应的排序。您可以将任何字符串放入属性中,但我倾向于使用中等大小的数字,这样我可以轻松地在现有视图之间放置一个新视图。

      【讨论】:

      • 重要提示,此处使用数字不可靠。因为区域排序实现是对字符串进行排序。使用这样的数字在 WPF 中可以得到很好的结果,但在 Silverlight 中,直到我使用了“a”和“b”并且它才起作用。
      • 只要数字的长度相同,就可以使用数字。 “100”和“050”会正确排序,而“100”和“50”则不会。
      【解决方案3】:

      参考 Sam 的回答,您首先必须构建您的比较器。下一个也能够查看没有专门希望定位的视图。要将此比较器附加到必须排序的区域,您可以使用 prism 手册中介绍的方法:

      public partial class MainView : UserControl
      {
          public MainView( ) 
          {
              InitializeComponent( );
      
              ObservableObject<IRegion> observableRegion = RegionManager.GetObservableRegion( ContentHost );
      
              observableRegion.PropertyChanged += ( sender, args ) =>
              {
                  IRegion region = ( (ObservableObject<IRegion>)sender ).Value;
                  region.SortComparison = CompareViews;
              };
          }
      
          private static int CompareViews( object x, object y )
          {
              IPositionView positionX = x as IPositionView;
              IPositionView positionY = y as IPositionView;
              if ( positionX != null && positionY != null )
              {
                  //Position is a freely choosable integer
                  return Comparer<int>.Default.Compare( positionX.Position, positionY.Position );
              }
              else if ( positionX != null )
              {
                  //x is a PositionView, so we favour it here
                  return -1;
              }
              else if ( positionY != null )
              {
                  //y is a PositionView, so we favour it here
                  return 1;
              }
              else
              {
                  //both are no PositionViews, so we use string comparison here
                  return String.Compare( x.ToString( ), y.ToString( ) );
              }
          }
      }
      

      【讨论】:

        【解决方案4】:

        至少在 prism V4 中,您可以告诉区域管理器如何对特定区域中的视图进行排序。您只需要为区域提供比较功能即可。

        这个例子按一个非常愚蠢的值排序,函数名:

        private static int CompareViews(object x, object y)
        {
          return String.Compare(x.ToString(), y.ToString());
        }
        
        this._regionManager.Regions["MyRegion"].SortComparison = CompareViews;
        

        当然,在设置 SortComparison 之前,区域经理需要知道该区域。到目前为止,我发现实现此目的的唯一解决方法是推迟使用 Dispatcher 设置比较功能:

        private readonly IRegionManager _regionManager;
        
        [ImportingConstructor]
        public ShellViewModel(IRegionManager regionManager)
        {
          this._regionManager = regionManager;
          Dispatcher dp = Dispatcher.CurrentDispatcher;
          dp.BeginInvoke(DispatcherPriority.ApplicationIdle, new ThreadStart(delegate
          {
            if (this._regionManager.Regions.ContainsRegionWithName("MyRegion"))
              this._regionManager.Regions["MyRegion"].SortComparison = CompareViews;
          }));
        }
        

        当然你应该使用一些比类名更有用的信息来进行排序,但这应该很容易解决。

        【讨论】:

          【解决方案5】:

          以及缺少答案计数。我还没有找到 Prism 的解决方案。

          我使用 MEF 来解决这个问题。

          我会在上面写一篇博文并更新这个占位符。

          【讨论】:

          • 您现在可以随意更新这个“占位符”。你已经两年多了。 :-P
          【解决方案6】:

          这不是 Prism 区域内置的,但它很容易实现。

          Damian Schenkelman 发布了一个他创建的扩展方法,用于将区域添加到索引中,该方法似乎运行良好。 http://blogs.southworks.net/dschenkelman/2009/03/14/how-to-add-a-view-to-a-region-in-a-particular-index-with-prism-v2/

          希望这会有所帮助。

          【讨论】:

          • 不,这不是解决方案。假设您在 ModuleA 中的索引 0 处添加 viewA,在 ModuleB 中的索引 1 处添加 viewB。如果偶然 ModuleB 将首先加载,它将尝试将其添加到索引 1,并且会失败。
          • @ArielBH:该示例很容易修改为使用字符串索引(这是我个人所做的)。希望这会有所帮助。
          • @ArielBH:我想是的。你得给我一点时间从残骸中提取相关的部分。
          • @Alex 对不起,我不明白你的意思。
          • @AndersonImes,ArielBH 问你是否应该分享你修改过的代码,你说你会这样做,但我在任何地方都找不到;这些 cmets 或您的答案中没有指向任何修改代码的链接。
          猜你喜欢
          • 2011-01-13
          • 1970-01-01
          • 1970-01-01
          • 2011-07-01
          • 2011-05-21
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2016-07-29
          相关资源
          最近更新 更多