如何通知ViewModel它的collectionSource是否已从WPF MVVM中的另一个viewModel更改(添加,更新或删除)?

时间:2017-08-29 15:24:59

标签: wpf mvvm

如果我有一个用于添加新项目的viewmodel和另一个用于显示所有或已过滤项目的viewmodel(第二个viewmodel的视图必须始终反映集合源中的任何更改),是否应将更改从viewmodel传递到viewmodel直接,或viewmodel到存储库到第二个viewmodel?

我尝试了以下

public class DataAccess //my repository
{
    public DataAccess()
    {
        var ctx = new MyDbContext();
    }
    public void AddNewItem(Item item)
    {
        ctx.items.Add(item);
        ctx.SaveChanges();
    }
    public ObservableCollection<Item> GetAllItems()
    {
        return new ObservableCollection<Item>(ctx.items.ToList());
    }

这是我的第一个ViewModel

public class ItemsViewModel : ObservableObject
{
    public ItemsViewModel()
    {
        DataAccess dt = new DataAccess();
        AllItems = new ObservableCollection<Item>(dt.GetAllItems());
    }
    //AllItems is bound to datagrid
    private ObservableCollection<Item> _allItems;
    public ObservableCollection<Item> AllItems
    {
        get {return _allItems;}
        set {_allItems = value; RaisePropertyChanged();}
    }
    //command to load the form for adding new item then the method below
    //I passed AllItems into the constructor
    //I think I can also pass AllItems using Messenger, but I haven't tried it yet
    void LoadNewItemForm()
    {
        NewItemView view = new NewItemView(){DataContext = new NewItemViewModel(AllItems)};
        view.ShowDialog();
    }

这是第二个视图模型

public class AddNewItemViewModel : ObservableObject
{
    public AddNewItemViewModel(ObservableCollection<Item> allItems)
    {
        DataAccess dt = new DataAccess();
        _allItems = allItems;
    }
    private ObservableCollection<Item> _allItems;
    public ObservableCollection<Item> AllItems
    {
        get {return _allItems;}
        set {_allItems = value; RaisePropertyChanged();}
    }
    //Here's the AddNewItem method
    public void SaveNewItem()
    {
        Item newitem = new Item(){ ..... };
        dt.AddNewItem(item);

        //Now is this change in AllItems here supposed to reflect in the allItems passed via constructor (will this reflect in the first ViewModel)
        AllItems.Add(newitem);
    }

我已尝试在存储库(AllItems)中创建DataAccess class属性,以便此AllItems属性将在{{1}的调用中返回它也在我将调用GetAllItems()AllItems.Add(something)的存储库中。尽管如此,更改并未反映在第一个viewModel中。

1 个答案:

答案 0 :(得分:1)

Here's an example of using events to inform the view models when the data changes.

The data layer:

Del

The event args:

foreach ($folder in (dir $target -Directory -Recurse | 
    where {-not $_.GetFiles("*", "AllDirectories")} |
    Select Fullname | 
    Out-GridView -PassThru -Title "Select Folders For Deletion and Click OK"
)) {
    del $folder -Recurse -WhatIf
}

The first view model:

.top, .bottom {
  width:98%;
  padding:1%;
  background-color: red;
  clear:both;
}
.cols {
  width:31%;
  padding:1%;
  float:left;
  background-color:blue;
  border: 1px solid #FFF;
}

This helps separate concerns because the public class DataAccess { private readonly MyDbContext ctx = new MyDbContext(); public event EventHandler<DataChangedEventArgs> ItemsChanged; public void AddNewItem(Item item) { ctx.Items.Add(item); ctx.SaveChanges(); RaiseItemsChanged(new DataChangedEventArgs(DataAction.Added, item)); } public List<Item> GetAllItems() { return ctx.Items.ToList(); } public void RaiseItemsChanged(DataChangedEventArgs eventArgs) { ItemsChanged?.Invoke(this, eventArgs); } } can now add an item without worrying about updating public enum DataAction { Added, Deleted } public class DataChangedEventArgs { public DataAction DataAction { get; set; } public Item Item { get; set; } public DataChangedEventArgs(DataAction dataAction, Item item) { DataAction = dataAction; Item = item; } } . You could also take a lazier approach and handle any event by clearing and repopulating the public class ItemsViewModel { private readonly DataAccess dataAccess = new DataAccess(); public ObservableCollection<Item> AllItems { get; set; } public ItemsViewModel() { AllItems = new ObservableCollection<Item>(dataAccess.GetAllItems()); dataAccess.ItemsChanged += (sender, eventArgs) => { if (eventArgs.DataAction == DataAction.Added) AllItems.Add(eventArgs.Item); else AllItems.Remove(eventArgs.Item); }; } } .