我最近开始在silverlight中使用MVVM模式,我不确定我是否正确使用它。
GUI
我目前有一个拥有股票市场行业组合框的MainView。当用户选择扇区(例如ENERGY)并单击“添加”按钮时,该扇区的股票列表将显示在列表框中。在列表框中每个股票的旁边是一个删除按钮,允许您从列表框中删除单个股票。
我已经实现了以下ViewModel。 (下面只是代码的指示)
public class MainViewModel
{
public SectorViewModel CurrentSector
{
get;
set;
}
public string SelectedSector
{
get;
set;
}
public void AddSectorClickedCommand()
{
CurrentSector = new SectorViewModel(SelectedSector);
}
}
public class SectorViewModel
{
public ObservableCollection<StockViewModel> Stocks = new ObservableCollection<StockViewModel>();
public SectorViewModel(string sector)
{
List<Stocks> stocklist = StockProvider.GetStocks(sector);
for each (var s in stocklist)
{
StockViewModel svm = new StockViewModel(s);
svm.Remove+= { //Remove svm from Stocks collection logic
Stocks.add(svm);
}
}
}
我的问题是;在whcih viewmodel中,最好为列表框中每行的Remove按钮添加代码实现吗? “删除”按钮应从SectorViewModel.Stocks集合中删除StockViewModel。
我目前已将RemoveClicked方法添加到StockViewModel(如上所示)。此代码将事件激发回SectorViewModel,SectorViewModel的RemoveStock方法从Stock集合中删除StockViewModel。
有没有更好的方法来实现此删除功能?我是MVVM的新手,我不确定这是否是开发此功能的最佳方法,因为SectorViewModel需要注册到StockViewModel的事件。
答案 0 :(得分:0)
我个人不喜欢事件,因为你应该取消订阅,也可以在不合适的地方使用。
我会使用构造函数参数来处理remove命令,如下所示:
public class StockViewModel
{
public StockViewModel(Stock stock, Action<StockViewModel> removeCommandAction)
{
//...
this.RemoveCommand = new DelegateCommand(() => removeCommandAction(this));
}
}
public class SectorViewModel
{
public SectorViewModel()
{
//...
StockViewModel svm = new StockViewModel(s, this.RemoveStock);
Stocks.add(svm);
}
private void RemoveStock(StockViewModel stock)
{
//...
}
}
另一种方法是使用某种EventAggregator模式,例如MVVM light Toolkit中的Messenger
类。但我认为这对于这么简单的任务来说太过分了:
public StockViewModel(Stock stock, IMessenger messenger)
{
//...
this.RemoveCommand = new DelegateCommand(() =>
messenger.Send(new NotificationMessage<StockViewModel>(this, RemoveItemNotification)));
}
public SectorViewModel(IMessenger messenger)
{
//...
messenger.Register<NotificationMessage<StockViewModel>>(this, msg =>
{
if (msg.Notification == StockViewModel.RemoveItemNotification)
{
this.RemoveStock(msg.Content);
}
}
}
我还听说Silverlight 5支持绑定到相对源。 所以有第三种方法。我不确定这个例子是否有效,但至少它应该:
<Button Content="Remove"
Command="{Binding DataContext.RemoveCommand RelativeSource={RelativeSource AncestorType=ListBox}}"
CommandParameter="{Binding}" />
public class SectorViewModel
{
public SectorViewModel()
{
this.RemoveCommand = new DelegateCommand(obj => this.RemoveStock((StockViewModel)obj));
}
public ICommand RemoveCommand { get; set; }
}
顺便说一句,最后一个例子是最受欢迎的,并且在WPF应用程序中使用,因为WPF始终具有RelativeSource绑定。