【问题标题】:Where do I put the logic for my ICommand?我将 ICommand 的逻辑放在哪里?
【发布时间】:2012-01-22 14:31:39
【问题描述】:

我最近开始在 silverlight 中使用 MVVM 模式,但我不确定我是否正确使用它。

图形界面

我目前有一个包含股市板块组合框的 MainView。当用户选择一个部门(例如能源)并单击添加按钮时,该部门的股票列表将显示在列表框中。列表框中每只股票的旁边都有一个删除按钮,可让您从列表框中删除单个股票。

我已经实现了以下 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);

        }
     }
}

我的问题是;在哪个视图模型中最好为列表框中每一行的删除按钮添加代码实现? Remove 按钮应该从 SectorViewModel.Stocks 集合中删除 StockViewModel。

我目前已将 RemoveClicked 方法添加到 StockViewModel(如上所示)。此代码将一个事件返回给 SectorViewModel,并且 SectorViewModel 的 RemoveStock 方法从 Stock 集合中删除 StockViewModel。

有没有更好的方法来实现这个删除功能?我是 MVVM 新手,不确定这是否是开发此功能的最佳方法,因为 SectorViewModel 需要注册到 StockViewModel 的事件。

【问题讨论】:

标签: silverlight mvvm


【解决方案1】:

我个人不喜欢事件,因为您应该取消订阅它们,而且它们也可以在不合适的地方使用。

我会使用构造函数参数来处理删除命令,如下所示:

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

【讨论】:

    猜你喜欢
    • 2016-03-08
    • 1970-01-01
    • 2014-03-16
    • 2018-06-14
    • 2013-07-26
    • 1970-01-01
    • 2011-09-08
    • 2015-01-22
    • 1970-01-01
    相关资源
    最近更新 更多