在ViewModel中使用CollectionViewSource的正确方法

Dav*_*d S 43 c# wpf datagrid mvvm collectionviewsource

我使用Drag和Drop将Data Source对象(一个DB模型)绑定到DataGrid(基本上遵循WPF实体框架数据绑定中的这个示例).

这个实现一切正常.

XAML

<Window.Resources>    
<CollectionViewSource x:Key="categoryViewSource"  
    d:DesignSource="{d:DesignInstance {x:Type local:Category}, CreateList=True}"/>
</Window.Resources>
<Grid DataContext="{StaticResource categoryViewSource}">
..
Run Code Online (Sandbox Code Playgroud)

代码背后

private void Window_Loaded(object sender, RoutedEventArgs e)
{
   System.Windows.Data.CollectionViewSource categoryViewSource =
      ((System.Windows.Data.CollectionViewSource)(this.FindResource("categoryViewSource")));

  _context.Categories.Load();
  categoryViewSource.Source = _context.Categories.Local;        
}
Run Code Online (Sandbox Code Playgroud)

视图模型

public MainWindow()
{
    InitializeComponent();
    this.DataContext = new MyViewModel();
}
Run Code Online (Sandbox Code Playgroud)

但是,当我尝试在ViewModel中使用相同的代码时,它不起作用(FindResource不可用),此外,我不认为这是正确的方法(即x:Key在MVVM中使用).

我真的很感激任何帮助点我是什么来实现的正确途径CollectionViewSource,并DataBindingDataGrid.

akj*_*shi 57

你有两个选择可以CollectionViewSource正确使用MVVM -

  1. 透露你的ObservableCollection一些物品(Categories在你的情况下)ViewModelCollectionViewSource 在XAML中创建如下 -

    <CollectionViewSource Source="{Binding Path=Categories}">
        <CollectionViewSource.SortDescriptions>
           <scm:SortDescription PropertyName="CategoryName" />
        </CollectionViewSource.SortDescriptions>
    </CollectionViewSource>
    
    Run Code Online (Sandbox Code Playgroud)

    SCM: xmlns:scm="clr-namespace:System.ComponentModel;assembly=Wind??owsBase"

    看到这个 - Filtering使用CollectionViewSource从XAML收集

  2. ICollectionView直接从您的创建和公开ViewModel

    请参阅此 - 如何在WPF中导航,分组,排序和筛选数据

以下示例显示如何创建集合视图并将其绑定到 ListBox

查看XAML:

<Window 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:scm="clr-namespace:System.ComponentModel;assembly=WindowsBase"
    x:Class="CustomerView">
    <ListBox ItemsSource={Binding Customers} />
</Window>
Run Code Online (Sandbox Code Playgroud)

查看Codebehind:

public class CustomerView : Window
{
   public CustomerView()
   {
       DataContext = new CustomerViewModel();
   }
}
Run Code Online (Sandbox Code Playgroud)

视图模型:

public class CustomerViewModel
{
    private readonly ICollectionView customerView;

    public ICollectionView Customers
    {
        get { return customerView; }
    }

    public CustomerViewModel()
    {
        IList<Customer> customers = GetCustomers();
        customerView = CollectionViewSource.GetDefaultView( customers );
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 仅供参考,`scm:`这是`xmlns:scm ="clr-namespace:System.ComponentModel; assembly = WindowsBase"` (9认同)

gak*_*era 10

我发现CollectionViewSource在我的ViewModel中有一个并将ListBox(在我的情况下)绑定到CollectionViewSource.Viewwhile设置为CollectionViewSource.Source我想要使​​用的列表是很方便的.

像这样:

视图模型:

    public DesignTimeVM()  //I'm using this as a Design Time VM 
    {
        Items = new List<Foo>();
        Items.Add(new Foo() { FooProp= "1", FooPrep= 20.0 });
        Items.Add(new Foo() { FooProp= "2", FooPrep= 30.0 });

        FooViewSource = new CollectionViewSource();
        FooViewSource.Source = Items;

        SelectedFoo = Items.First();

        //More code as needed
    }
Run Code Online (Sandbox Code Playgroud)

XAML:

<ListBox ItemsSource="{Binding FooViewSource.View}" SelectedItem="{Binding SelectedFoo}"/>
Run Code Online (Sandbox Code Playgroud)

这意味着我可以根据需要在VM中做好事(来自https://blogs.msdn.microsoft.com/matt/2008/08/28/collectionview-deferrefresh-my-new-best-friend/):

        using (FooViewSource.DeferRefresh())
        {
            //Remove an old Item
            //add New Item
            //sort list anew, etc. 
        }
Run Code Online (Sandbox Code Playgroud)

我想这也是可能的,当使用ICollectionView对象时,但博客链接中的演示代码似乎是一些代码隐藏的东西,直接引用列表框,我试图避免.

BTW在你问之前,这里是你如何使用设计时VM:WPF设计时间视图模型