【问题标题】:How to sort views in an ItemsControl in Prism / MEF?如何在 Prism / MEF 的 ItemsControl 中对视图进行排序?
【发布时间】:2010-11-23 14:19:14
【问题描述】:

我使用 prism v4 和 MEF 来加载我的模块。我的模块包含少数视图 (MVVM),它们由 MEF 自动加载到 ItemsControl/NavigationRegion。

这很好用,所有项目都显示在 ItemControl 中。但我不喜欢它们显示的顺序。一个模块可能包含多个项目,因此仅更改模块加载顺序是不够的。

如何对 ItemsControl 中的不同视图进行排序?有没有办法按某些属性对它们进行排序?

由于 StockTraderRI 示例中的属性,我使用 prism V4、MEF 和探索。

【问题讨论】:

标签: wpf prism mef


【解决方案1】:

这实际上已融入 Prism4。只需将 ViewSortHintAttribute 应用于您的视图:

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

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

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

【讨论】:

  • RegionManager 上的另一个附加属性对我来说更有意义。属性是编译时常量,不能在 XAML 中指定,这对某些不需要代码隐藏的视图很有帮助。例如,菜单区域将承载菜单项。通常,您只需创建一个 MenuItem 并将其添加到该区域,但如果您想指定排序顺序,则不能!
  • 根据我上面的评论,我自己解决了这个问题,方法是定义一个Sort.Order 附加属性(类型int),然后是一个使用它的SortingRegionBehavior。最后,我的引导程序将此行为注册为默认行为,因此所有区域都会得到它。到目前为止,我发现的唯一限制是不会反映事后对 Sort.Order 属性的更改,但我很确定如果需要的话,我可以在我的区域行为中添加对它的支持。
【解决方案2】:

天哪,这方式比我预期的要容易:

您可以告诉区域经理如何对特定区域中的视图进行排序。您只需要为区域提供比较功能即可。

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

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

当然,我们应该使用一些比类名更有用的信息来进行排序,但这应该很容易解决(我将只为所有可能添加到该区域的视图添加一个接口,这些视图提供一个值排序依据)。

【讨论】:

  • 我刚刚向stackoverflow.com/questions/2041765/… 添加了一个答案,在这种情况下也很有趣。
  • 我遇到了一种情况,我有相同类型的视图(并且无法使用 ViewSortHint)。最终,我确实让这个 SortCoparison 代表工作了。我发现必须在添加需要排序的视图之前设置 delgate。否则,视图将按添加顺序显示。
【解决方案3】:

我很确定您正在寻找CollectionViewSource。 Bea 在链接中提供了一些有关如何使用它的信息。

从 MVVM 立场来看,这就是我在 ViewModel 中使用 ICollectionView 的方式。 _scriptService.Scripts 属性是一个 ObservableCollection<T> 被包裹在一个返回给视图的 ICollectionView 中。 _view.Filter 用于过滤 ICollection 中的项目,从而更改视图。类似于输入“acc”并查看列表中所有以“acc”开头的项目。

    public class ScriptRepositoryViewModel : AViewModel
    {
        private readonly IUnityContainer _container;
        private readonly IScriptService _scriptService;
        private readonly IEventAggregator _eventAggregator;

        private ICollectionView _view;

        public ScriptRepositoryViewModel(IUnityContainer container, IScriptService scriptService, IEventAggregator eventAggregator)
        {
            _container = container;
            _scriptService = scriptService;
            _eventAggregator = eventAggregator;
        }

        public ICollectionView Scripts
        {
            get 
            {
                if (_view == null)
                {
                    _view = CollectionViewSource.GetDefaultView(_scriptService.Scripts);
                    _view.Filter = Filter;
                }

                return _view;
            }
        }
     }

下面是负责过滤的代码,它通过 Prism 中的 DelegateCommand 进入,它驻留在同一个 ViewModel 中。

#region SearchCommand
public DelegateCommand<object> SearchCommand { get; private set; }

private String _search = String.Empty;
private void Search(object commandArg)
{
    _search = commandArg as String;
    _view.Refresh();
}

public bool Filter(object arg)
{
    bool usingPrefix;

    IScript script = arg as IScript;
    if (script.FileType == ConvertPrefixToFileType(_search, out usingPrefix))
    {
        if (_search.Length == 2)
            return true;
        else
            return CheckProperties(script, usingPrefix);
    }
    else
    {
        if (usingPrefix)
            return false;
        else
            return CheckProperties(script, usingPrefix);
    }
}

有了基本功能并利用ICollectionView,您可以按如下方式应用排序......

_view.SortDescriptions.Add(new SortDescription("PropertyName", direction));

更多关于排序行为的信息可以在here找到,因为有一些性能方面的想法需要牢记。

【讨论】:

  • 那么,我将如何在 prism/MVVM 中使用它?
  • @Sam Bea 在上面的链接中介绍了它。使用 CollectionViewSource 本身不适用于 Prism,但它确实符合 MVVM 模式。发布了一个关于我如何使用它的示例。
  • Aaron,看起来很棒,我会检查它并在我完成后立即标记为答案,谢谢!!
  • 我尝试了您的解决方案,但我不明白如何从区域管理器获取 CollectionView(我正在尝试对 mef 加载的区域内容进行排序)。
  • 归根结底是他们在屏幕上显示的顺序问题吗?如果是这种情况,那么您引用的 ItemsControl 需要绑定到返回 ICollectionView 的东西。
【解决方案4】:

您可以使用metadata 或属性。这取决于您是否可以控制界面...

【讨论】:

  • 我宁愿寻找如何排序,而不是按什么。如果我得到任何如何进行排序的示例,我将不用担心找到要用于排序的属性或元数据。
  • 啊哈,我对WPF知之甚少,所以我帮不上忙!
【解决方案5】:

视图按添加顺序显示:

RegionManager.RegisterViewWithRegion("ListRegion", typeof(ListView));
RegionManager.RegisterViewWithRegion("ListRegion", typeof(ListView2));
RegionManager.RegisterViewWithRegion("ListRegion", typeof(ListView3));

看起来像:

----地区--| |视图3 | |视图2 | |查看 |


【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-07-25
    • 1970-01-01
    • 2013-02-23
    • 2023-02-02
    • 1970-01-01
    • 1970-01-01
    • 2010-11-15
    相关资源
    最近更新 更多