Silverlight的Prism:如何在区域内以特定顺序维护视图

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

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

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

其他可行的选项是将区域的Views Collection绑定到ItemControl的顺序,问题是ViewCollection非常有限,因此对它进行排序非常困难。

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

谢谢阿里尔

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

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

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

请参阅Sam的回答,首先要建立比较器。 以下一个也能够提供没有专门希望定位的视图。 要将此比较器附加到必须排序的区域,您可以使用棱镜手册介绍的方式:

 public partial class MainView : UserControl { public MainView( ) { InitializeComponent( ); ObservableObject observableRegion = RegionManager.GetObservableRegion( ContentHost ); observableRegion.PropertyChanged += ( sender, args ) => { IRegion region = ( (ObservableObject)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.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( ) ); } } } 

至少在棱镜V4中,您可以告诉区域经理如何对特定区域中的视图进行排序。 您只需要为该地区提供比较function。

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

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

当然,您应该使用比排序顺序的类名更有用的信息,但这应该很容易解决。

这不是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/

希望这可以帮助。

我发现Sam的解决方案有效,但发现当所有视图都添加到区域时它会执行排序,从而对视图进行两次排序。

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

1 – 订阅RegionsChanged of Regions集合

我将它放在Shell ViewModel代码中,该代码与包含我想要排序的区域的View相关联。 每当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委托

在我的例子中,我只是通过包含它们的程序集的标题对视图进行排序,您可以在这里实现自己的比较方法。 请记住,您在此处收到的对象是视图而不是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; } } 

希望这有助于某人!

好吧,因为缺乏答案计数。 我还没有找到Prism的解决方案。

相反,我用MEF来解决这个问题。

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