带有Command和CommandParameter

时间:2018-12-26 18:48:36

标签: wpf mvvm mvvm-light

我有一个WPF应用程序,其中窗口具有主/子关系。当用户从ListView中选择一个买方时,DataGrid将与他们已购买的相关商品绑定在一起。在GridView中,左侧有一个按钮,您可以为此单个项目付款。但是,我想根据商品的状态来禁用/启用该按钮,无论现有的付款是否与之关联。使用Galasoft MVVM Light,可以在整个应用程序中使用RelayCommand。我有“付款”按钮,但只有在单击(选定行)后才能使用。以此方式绑定到命令时,此方法工作正常:

<DataGrid ..
  ItemsSource="{Binding Items}" 
  SelectedItem="{Binding SelectedItem}"
  IsSynchronizedWithCurrentItem="True"
  .. >
    <DataGrid.Columns>
      <DataGridTemplateColumn>
        <DataGridTemplateColumn.CellTemplate>
          <DataTemplate>
          <Button ...
           Command="{Binding Path=DataContext.PayItemCommand, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}}" 
           CommandParameter="{Binding SelectedItem, Mode=OneWay, ElementName=itemsPurchasedGrid}"
          >Pay</Button>
          ...

// in ctor
PayItemCommand = new RelayCommand<Item>(PayItem, IsItemUnPaid);

// in body
private void PayItem(Item item)
{
    PaymentMode = PaymentMode.Item;
    Messenger.Default.Send<BuyerViewModel>(this, "LaunchPayWindow");
}

// CanExecute impl
private bool IsItemUnPaid(Item item)
{
   // code to determine if item is already paid
}

因此,当我单击按钮时,它将正确地将SelectedItem传递给RelayCommand委托。但是,CanExecute实现:IsItemUnPaid(Item item)从未获得该项目,因为(尚未)选择它。我尝试过:IsSynchronizedWithCurrentItem =“ True”,它总是传递第一个项目,但不会传递任何其他项目。当绑定到DataGrid以禁用/启用该项目时,是否可以获取该项目的句柄?我确定绑定期间在代码隐藏中有难看的方法,但是是否有一种MVVM方法来检查当前项目并切换该按钮?非常感谢!

P.S。我写了一个简单的转换器,可以工作,但这真的是最好的方法吗?

public class PayItemConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        if (!(value is Item item))
            return true;

        // if you find any payments for this item...
        var payments = (item.Payments != null && item.Payments.Any(p => p.ItemId.HasValue && p.ItemId.Value == item.Id))
            ? item.Payments.Where(p => p.ItemId.HasValue && p.ItemId.Value == item.Id).ToArray()
            : null;

        // if you find payments for this item, are the sum of the payments less than the total of the item TotalAmount, it is said to be unpaid
        return (payments != null && payments.Length > 0)
            ? payments.Sum(p => p.Amount) < item.TotalAmount
            : true;                      
    }

1 个答案:

答案 0 :(得分:0)

不,转换器不是实现此目的的最佳方法。 MVVM的重点是在视图和视图逻辑之间保持良好的关注点分离。转换器绝对位于视图层中。一旦发现自己将应用程序类型的逻辑添加到转换器中,通常就表明您的视图模型没有将数据强制转换为易于被视图使用的格式。

这里的问题是您的Items属性似乎是模型数据,可能来自数据库或其他内容。它需要的是视图模型的集合,每个项目一个,它公开了项目的属性(甚至整个项目本身),并且还包含视图所需逻辑的额外字段,即:

public bool PayButtonEnabled {get; private set;}
相关问题