Saruman Saruman - 14 days ago 10
C# Question

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

Answer

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}" />