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

时间:2010-01-11 12:28:13

标签: c# silverlight silverlight-4.0 prism

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

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

限制模块订单是不可能的。

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

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

由于 爱丽儿

6 个答案:

答案 0 :(得分:7)

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

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

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

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

答案 1 :(得分:3)

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

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

答案 2 :(得分:2)

至少在棱镜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;
  }));
}

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

答案 3 :(得分:1)

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

希望这有帮助。

答案 4 :(得分:1)

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

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

1 - 订阅RegionsChanged of Regions集合

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

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

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

然后,只要Region集合更新,代理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;
    }
}

希望这有助于某人!

答案 5 :(得分:0)

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

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

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