我在哪里为我的ICommand提供逻辑?

时间:2011-12-17 12:32:26

标签: silverlight mvvm

我最近开始在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的事件。

1 个答案:

答案 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绑定。