简体   繁体   中英

How to bind a WPF ListView with contextMenu to viewModel

I'm trying to bind a listview to List<OrderPaymentVm> OrderPayments with a right click contextmenu to get the PaymentTransactionId .

I have the following property in my forms view model

  public List<OrderPaymentVm> OrderPayments
  {
     get
     {
        return _orderPayments;
     }

     private set
     {
        _orderPayments = value;
        RaisePropertyChanged(() => OrderPayments);
     }
  }

The ViewModel

   public class OrderPaymentVm : ViewModelBase
   {

      private RelayCommand _copyPaymentTransactionId;
      public DateTime PaymentTime { get; set; }
      public PaymentType PaymentType { get; set; }
      public string Explanation { get; set; }
      public string PaymentTransactionId { get; set; }
      public decimal Amount { get; set; }
      public RelayCommand CopyPaymentTransactionId
      {
         get { return _copyPaymentTransactionId ?? (_copyPaymentTransactionId = new RelayCommand(ExecuteCopyPaymentTransactionId)); }
      }

      private void ExecuteCopyPaymentTransactionId()
      {
         Clipboard.SetText(string.IsNullOrWhiteSpace(PaymentTransactionId) ? string.Empty : PaymentTransactionId);
      }

   }

I have the following xaml

<ListView Grid.Row="1" ItemsSource="{Binding OrderPayments}" HorizontalAlignment="Stretch" Margin="0,0,0,1">
      <ListView.ContextMenu>
         <ContextMenu>
            <MenuItem Header="Copy Transaction Id"
                  Command="{Binding CopyPaymentTransactionId}"
                  CommandParameter="{Binding RelativeSource={RelativeSource AncestorType=ContextMenu}, Path=PlacementTarget.SelectedItem}" />
         </ContextMenu>
      </ListView.ContextMenu>
      <ListView.View>
         <GridView>
            <GridViewColumn HeaderContainerStyle="{StaticResource HeaderLeftAlign}" Header="Transaction Id" Width="150" DisplayMemberBinding="{Binding PaymentTransactionId}" />
            <GridViewColumn HeaderContainerStyle="{StaticResource HeaderLeftAlign}" Header="Time" Width="150" DisplayMemberBinding="{Binding PaymentTime}" />
            <GridViewColumn HeaderContainerStyle="{StaticResource HeaderLeftAlign}" Header="Payment Type" Width="100" DisplayMemberBinding="{Binding PaymentType}" />
            <GridViewColumn HeaderContainerStyle="{StaticResource HeaderLeftAlign}" Header="Amount" Width="80" DisplayMemberBinding="{Binding Amount, StringFormat='{}{0:C}'}" />
            <GridViewColumn HeaderContainerStyle="{StaticResource HeaderLeftAlign}" Header="Explanation" Width="280" DisplayMemberBinding="{Binding Explanation}" />
         </GridView>
      </ListView.View>
</ListView>

Problem 1 the xaml designer says there is a problem with the GridViewColumn bindings, it underlines them and says it cannot resolve property, however it compiles and works fine

Problem 2 The ConextMenu Command is not hitting the viewmodel command RelayCommand CopyPaymentTransactionId

Im sure these are simple issues however im spinning my wheels, does any one have any suggestions?

Thanks

here is solution for the 2nd problem. as the context menu is hosted in a popup, which does not inherit the data context from it's parent as it is a separate root element. so you may not simply bind to the parent element's view model.

here is example to bind the command in a context menu

Command="{Binding PlacementTarget.SelectedItem.CopyPaymentTransactionId,
                  RelativeSource={RelativeSource AncestorType=ContextMenu}}"

similar to command parameter, you need to specify the source for the command binding.

to simplify you may also write the same as

<MenuItem Header="Copy Transaction Id"
          DataContext="{Binding PlacementTarget.SelectedItem, 
                                RelativeSource={RelativeSource AncestorType=ContextMenu}}"
          Command="{Binding CopyPaymentTransactionId}"
          CommandParameter="{Binding}" />

Problem 1: This is because the designer does not know what the type of objects are in the GridView . You know this, so you can do something like this:

<Window ... blah blah blah
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d"
    blah blah...

And in ListView :

<ListView blah blah
    d:DataContext="{d:DesignInstance whatevernamespace:WhateverVMYouUse}...

Usually explicitly creating DesignInstance data contexts like this give you better auto complete and removes the superfluous errors that show up in designer.

Problem 2: Pushpraj beat me to it. also see this question

 public class OrderPaymentVm : ViewModelBase
 {

  public OrderPaymentVm ()
  {
     CopyPaymentTransactionId = new RelayCommand(ExecuteCopyPaymentTransactionId));
  }

.
.
.

  public RelayCommand CopyPaymentTransactionId
  {
     get; set;
  }

  private void ExecuteCopyPaymentTransactionId()
  {
     Clipboard.SetText(string.IsNullOrWhiteSpace(PaymentTransactionId) ? string.Empty : PaymentTransactionId);
  }

}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM