1

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

ΩmegaMan
  • 29,542
  • 12
  • 100
  • 122
TheGeneral
  • 79,002
  • 9
  • 103
  • 141
  • The XAML designer often lies to me about errors. I usually verify my bindings by viewing the output window at runtime. In regards to your command binding, I have also had issues with command bindings not triggering. As a result, I grudgingly just write code-behind to handle click-events and make a note for refactoring opportunities later as time permits. – Scott Nimrod Sep 11 '14 at 02:11
  • Try initializing your relay command with its corresponding delegate assignment within the view-model constructor instead. – Scott Nimrod Sep 11 '14 at 02:15
  • Thanks for your comments, yeah i feel im being lied to in regards to problem 1 – TheGeneral Sep 11 '14 at 02:18

3 Answers3

4

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}" />
ΩmegaMan
  • 29,542
  • 12
  • 100
  • 122
pushpraj
  • 13,458
  • 3
  • 33
  • 50
1

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

Community
  • 1
  • 1
nakiya
  • 14,063
  • 21
  • 79
  • 118
-1
 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);
  }

}

Scott Nimrod
  • 11,206
  • 11
  • 54
  • 118