如果我有一个用于添加新项目的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中。
答案 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);
};
}
}
.