如何在Prism / MEF中的ItemsControl中对视图进行排序?

时间:2010-11-23 14:19:15

标签: wpf prism mef

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

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

如何对ItemsControl中的不同视图进行排序?是否有办法按某些财产对它们进行排序?

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

5 个答案:

答案 0 :(得分:9)

这实际上是Prism4的结果。只需将ViewSortHintAttribute应用于您的视图:

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

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

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

答案 1 :(得分:2)

哦,dang,这比我预期的方式更容易:

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

此示例按非常愚蠢的值排序,即函数名称:

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

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

答案 2 :(得分:1)

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

从MVVM的立场来看,这就是我在ViewModel中使用ICollectionView的方式。 _scriptService.Scripts属性被ObservableCollection<T>包裹在ICollectionView中,并返回到View。 _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找到,因为要记住一些性能方面的想法。

答案 3 :(得分:0)

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

答案 4 :(得分:-2)

视图按添加顺序显示:

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

看起来像:

---- region-- | | view3 | | view2 | |查看|