我正在为 SL 创建一种“导航面板”(实际上是一个 ItemControl),并使用区域来允许每个模块将他的链接添加到面板。
问题是模块加载不一致,因此面板中的链接顺序可能会根据模块加载顺序而改变。
限制模块顺序是不可能的。
其他可行的选项是绑定到 ItemControl 的区域的 Views Collection 的顺序,问题是 ViewCollection 非常有限,因此很难排序。
我错过了一个选项,你有什么想法吗?
谢谢爱丽儿
我正在为 SL 创建一种“导航面板”(实际上是一个 ItemControl),并使用区域来允许每个模块将他的链接添加到面板。
问题是模块加载不一致,因此面板中的链接顺序可能会根据模块加载顺序而改变。
限制模块顺序是不可能的。
其他可行的选项是绑定到 ItemControl 的区域的 Views Collection 的顺序,问题是 ViewCollection 非常有限,因此很难排序。
我错过了一个选项,你有什么想法吗?
谢谢爱丽儿
在 Prism4 中,您只需将 ViewSortHintAttribute 应用于您的视图:
[ViewSortHint("100")]
class FirstView : UserControl { }
[ViewSortHint("200")]
class SecondView : UserControl { }
区域上的默认排序比较器将获取此属性并相应地对视图进行排序。您可以将任何字符串放入属性中,但我倾向于使用中等大小的数字,这样我就可以轻松地在现有视图之间放置一个新视图。
参考 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( ) );
}
}
}
至少在 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;
}));
}
当然,您应该使用一些比类名更有用的信息来进行排序,但这应该很容易解决。
这不是内置在 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 - 订阅 Regions 集合的 CollectionChanged
我将它放在 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 委托
在我的例子中,我只是按包含它们的程序集的标题对视图进行排序,您可以在此处实现自己的比较方法。请记住,您将在此处收到的对象是 Views 而不是 ViewModels。
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 来解决这个问题。
我会在上面写一篇博文并更新这个占位符。