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

发布于 2024-08-17 14:51:29 字数 259 浏览 5 评论 0原文

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

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

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

其他可行的选择是对绑定到 ItemControl 的区域视图集合进行排序,问题是 ViewCollection 非常有限,因此对其进行排序非常困难。

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

谢谢 爱丽儿

I am creating sort of a "Navigation panel" (which is actually an ItemControl) for SL and using Regions to allow each module to add his link to the panel.

Problem is that modules loading is inconsistent and thus order of links in the panel can change according to modules loading order.

Restricting the modules order is out of the question.

Other feasible option is the order the region's Views Collection that is binded to the ItemControl, the problem is that ViewCollection is very limited, so ordering it is pretty hard.

Did I miss an option, do you have an idea?

Thanks
Ariel

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

不醒的梦 2024-08-24 14:51:29

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

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

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

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

In Prism4 you just apply the ViewSortHintAttribute to your views:

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

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

The default sort comparer on the regions will pick up this attribute and sort the views accordingly. You can put any string into the attribute but I tend to use medium sized numbers that allow me to easily put a new view in between existing ones.

美男兮 2024-08-24 14:51:29

参考山姆的答案,你首先必须建立你的比较器。下面的一个也能够提出没有专门希望定位的视图。要将此比较器附加到必须排序的区域,您可以使用棱镜手册中介绍的方法:

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

Refering to Sam's answer you first have to build your comparer. The following one is also capable of views that do not have a dedicated wish to be positioned at. To attach this comparer to the region that has to be sorted you can use a way intruduced by the prism manual:

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( ) );
        }
    }
}
我ぃ本無心為│何有愛 2024-08-24 14:51:29

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

此示例按一个非常愚蠢的值(函数名称)排序:

private static int CompareViews(object x, object y)
{
  return String.Compare(x.ToString(), y.ToString());
}

this._regionManager.Regions["MyRegion"].SortComparison = CompareViews;

当然,在设置 SortComparison 之前,区域管理器需要知道该区域。到目前为止,我发现实现此目的的唯一解决方法是推迟使用调度程序设置比较函数:

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

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

At least in prism V4 there you can tell the region manager how to sort the views in a specific region. You just need to provide a compare function to the region.

This example sorts by a very stupid value, the function name:

private static int CompareViews(object x, object y)
{
  return String.Compare(x.ToString(), y.ToString());
}

this._regionManager.Regions["MyRegion"].SortComparison = CompareViews;

Of course the region needs to be known to the region manager before you can set the SortComparison. So far the only workaround I found to achieve this was to defer to set the comparison function using the 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;
  }));
}

Of course you should use some more useful information than the class name for the sorting order, but this should be easy to solve.

鹤舞 2024-08-24 14:51:29

这没有内置到 Prism 区域中,但它很容易实现。

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

希望这有帮助。

This is not built into Prism regions, however it's easily implementable.

Damian Schenkelman has posted an extension method he created for adding a region to an index that seems to work pretty well.
http://blogs.southworks.net/dschenkelman/2009/03/14/how-to-add-a-view-to-a-region-in-a-particular-index-with-prism-v2/

Hope this helps.

爱本泡沫多脆弱 2024-08-24 14:51:29

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

尽管它仍然是一个有效的解决方案,但阅读 Prism 讨论中的 这篇 帖子让我想到了一种方法仅在加载区域时但在添加任何视图之前执行此操作。

1 - 订阅 Regions 集合的 CollectionChanged

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

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

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

然后委托 Regions_CollectionChanged 将执行每当更新 Regions 集合并将更改我所需区域的 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 委托

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

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

希望这对某人有帮助!

I found that Sam's solution worked, but discovered that it executes the sort when all views have been added to the region, thus sorting the views twice.

Although it is still a valid solution, reading this post in Prism discussion made me think about a way of implementing this just when the region has been loaded, but before any views have been added yet.

1 - Subscribe to the CollectionChanged of Regions collection

I placed this in the Shell ViewModel code which is the one associated to the View that contains the region I want to sort. Whenever the IRegionManager import has been resolved I subscribe to the CollectionChanged event of its Regions collection:

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

2 - Change the SortComparison of the region in the event delegate

Then the delegate Regions_CollectionChanged will execute whenever the Regions collection is updated and will change the SortComparison of my desired region:

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 - Define the CompareNavigatorViews delegate

In my case, I just sort the views by the title of the assembly where they are contained, you can implement your own compare method here. Remember that the objects you'll receive here are the Views and not the 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);
        }
}

Just in case somebody asks, the AssemblyInfo class is an utility class I made. To get the title of an assembly you could use this function:

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

Hope this helps someone!

我恋#小黄人 2024-08-24 14:51:29

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

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

我将就此写一篇博文并更新此占位符。

Well as the lack of answers counting. I have not found a solution with Prism.

Instead I've used MEF to solve this.

I will write a blog post on it and update this place holder.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文