【问题标题】:Understanding how to use ICollectionView in MVVM with Entity Framework data了解如何在 MVVM 中将 ICollectionView 与实体框架数据一起使用
【发布时间】:2014-01-17 23:39:23
【问题描述】:

我目前有一个简单的应用程序,由两个同步的 ListBox 组成,这些 ListBox 绑定到 ObservableCollections,它们包装了两个不同的实体框架类。

当 listBox1 中的 Part 项目被选中时,它会将 SelectedItem 的导航键信息传递给 listBox2,listBox2 会显示 Vendors 实体的相应子集。

目前,我的 ViewModel (MainViewModel.cs) 看起来像:

public MainViewModel()
{
    _context = new DBEntities();
    _partsCollection = new ObservableCollection<Part>(_context.Parts);
    _vendorsCollection = new ObservableCollection<Vendor>(_context.Vendors);
}

public ObservableCollection<Part> PartsCollection
{
     get { return _partsCollection; }
     set
     {
          OnPropertyChanged("PartsCollection");
          _partsCollection = value;
     }
}


public Observable<Part> SelectedPart
{
     get { return _selectedPart; }
     set
     {
          OnPropertyChanged("SelectedPart");
          _selectedPart = value;
     }
}

public ObservableCollection<Vendor> VendorsCollection
{
     get { return _vendorsCollection; }
     set
     {
          OnPropertyChanged("VendorsCollection");
          _vendorsCollection = value;
     }
}

我的视图(MainView)看起来像:

    <UserControl.Resources>
    <local:MainViewModel x:Key="MainViewModelDataSource" />
    </UserControl.Resources>

    <Grid x:Name="LayoutRoot" DataContext="{Binding Source={StaticResource MainViewModelDataSource}}">
           <ListBox ItemsSource="{Binding PartsCollection, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"  Margin="43,87,377,57" Name="listBox1"
             SelectedItem="{Binding SelectedPart, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
             IsSynchronizedWithCurrentItem="True" >
        <ListBox.ItemTemplate>
            <DataTemplate>
                <TextBlock FontSize="13" Foreground="Black" Padding="3" Text="{Binding shapeName}" />
            </DataTemplate>
        </ListBox.ItemTemplate>
    </ListBox>

    <ListBox IsSynchronizedWithCurrentItem="True" 
             ItemsSource="{Binding ElementName=listbox2,  Path=SelectedItem.Vendors, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged, NotifyOnSourceUpdated=True}" Margin="345,87,75,57" 
             >
        <ListBox.ItemTemplate>
            <DataTemplate>
                <TextBlock FontSize="13" Foreground="Black" Padding="3" Text="{Binding mateStyle}" />
            </DataTemplate>
        </ListBox.ItemTemplate>
    </ListBox> 

这很好用。但是,我想将 listBox2 绑定到我的视图模型的属性以更新 VendorsCollection。我想在我的视图模型上使用“SelectedPart”属性,目前甚至没有使用。

EF 的全部意义在于将它的所有功能用作 ORM,而不是在我的视图模型中再次构建额外的 ORM 来发送更改通知。从我所见,设置ICollectionView 是一种相当迂回的方法,但我无法弄清楚绑定。

我不确定下一步是什么,以便我可以提出PropertyChanged 通知并更新我的供应商ObservableCollection,将listBox2 xaml 绑定到我的视图模型的集合属性。

【问题讨论】:

    标签: c# wpf mvvm entity-framework-4 observablecollection


    【解决方案1】:

    我也在使用 MVVM 和实体框架,但使用代码优先方法。我厌倦了所有 MVVM 的“纯粹性”,其中 ViewModel 应该引发更改通知事件,所以我在我的所有模型类上实现了 INPC,我从未如此快乐过!在 ViewModel 中复制所有模型属性只是为了通知更改,这简直太疯狂了。

    我看到您正在使用 DBEntities,所以我不确定您将如何在模型对象中实现更改通知,但我强烈建议您这样做。我会让你的生活更轻松。

    顺便说一句,请务必在将支持字段设置为新值之后引发 OnPropertyChanged 事件,如下所示:

     set
     {
          _selectedPart = value; //first you change the private backing field
          OnPropertyChanged("SelectedPart"); //then you notify that it has changed, so everything gets the new value
     }
    

    关于绑定,您在此处使用 ViewModel 的 SelectedPart 属性:

    SelectedItem="{Binding SelectedPart, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
    IsSynchronizedWithCurrentItem="True"
    

    您将 listbox1 中的选定项目绑定到 SelectedPart 属性,并且通过将 IsSynchronizedWithCurrentItem 设置为 true,每次您在 UI 中选择某些内容时,ViewModel 中的属性都会更新(如果您设置UI 将接收更新的代码中的 SelectedPart)。

    因此,要绑定到第二个列表框中的 SelectedPart 的供应商,只需执行以下操作:

    ItemsSource="{绑定 SelectedPart.Vendors, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged, NotifyOnSourceUpdated=True}"

    在这种情况下,您不需要创建 VendorsCollection,因为您可以通过 SelectedPart.Vendors 访问相同的元素(或者您可以将 VendorsCollection 设置为具有好听名称的包装器以返回 SelectedPart.Vendor,只需确保检查 SelectedPart 是否为空)。

    关于 ICollectionView,要知道它只是 ObservableCollection(或类似的)的包装,以便绑定到从 Selector 继承的 FrameworkElements(如 ListBox)(即它们具有 SelectedItem 属性)。

    当您绑定到 ObservableCollection 时,WPF 会在后台创建一个 ICollectionView,因此您会获得 SelectedItem。您可以创建自己的 ICollectionView,使用 ObservableCollection 提供它,然后绑定到 XAML 中的 ICollectionView,就像使用 ObservableCollection 一样。如果您决定这样做,我建议您使用 ListCollectionView,您可以使用它过滤和创建组(用于树视图)。

    最后一句话:记住 ObservableCollection(以及所有 ICollectionViews)只会引发 CollectionChanged 事件(即,当您在集合中添加/删除项目时)。如果您更改属于集合的元素的属性,即使它实现 INotifyPropertyChanged,它们也不会引发任何事情。如果您想了解这一点,您必须创建一个自定义集合,例如 here 之一(众多)。

    希望这是有用的,问候!

    【讨论】:

    • 哇,谢谢@Hannish。多亏了你,我无法告诉你我的星期一过得怎么样。我感谢您的所有意见,并完全同意您的 MVVM 方法。使用我的实体框架模型,我将实现一个单一的存储库,以从 ObservableCollections 中发送 INPC/将我的 EF objectSets 包装在 ObservableCollections 中(保存在我的模型文件夹中)。我最终将我的供应商对象集包装在 ObservableCollection 中,并从 PartsCollection 设置器发送了供应商属性更改通知。
    • 还利用了您的评论“检查 SelectedPart 是否为空”,感谢您,我现在终于可以轻松地让我的代码像梦一样工作了。我不能感谢你。如果你有博客,请链接给我。
    • 非常感谢,我很高兴听到这个消息。我没有博客或其他类似的东西,实际上我不是专业的 IT,只是想学习和帮助。
    • @Hannish MVVM 在您的模型类中引发 INPC 并没有错......包装一个类并公开它是一种外观模式而不是 MVVM,很多人都弄错了(浪费时间在 VM 中复制模型中已经存在的东西)和 Prism MVVM 教程甚至说这是正确的做法......请参阅此处的“模型类”:msdn.microsoft.com/en-us/library/gg405484%28v=pandp.40%29.aspx
    【解决方案2】:

    要立即使用 PropertyChanged,只需将 ObservableCollection 传递到 BindingList 中。

    EntityFramework 在其 System.Data.Entity 命名空间中有一个 ToBindingList 扩展可以帮助您。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2010-10-23
      • 2014-09-23
      • 2017-03-23
      • 2011-10-08
      • 2021-03-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多