问题
I have a Context menu with some options. One of the options is an Observable collection and I am having issues binding my commands in my view model to them. I have seen many different ways to fix this issue, but none have worked because they do not specifically relate to my problem. Here is my code first:
XAML:
<ListView ItemsSource="{Binding ListViewItems}" SelectionMode="Single">
<ListView.ContextMenu>
<ContextMenu DataContext="{Binding Path=PlacementTarget, RelativeSource={RelativeSource Self}}">
<MenuItem Header="Test" Command="{Binding TestCommand}" CommandParameter="{Binding RelativeSource={RelativeSource AncestorType=ContextMenu}, Path=PlacementTarget.SelectedItem}" />
<Separator></Separator>
<MenuItem Header="Status" ItemsSource="{Binding DataContext.ObservableCollectionList}" DisplayMemberPath="Name" Command="{Binding Path=DataContext.UpdateCommand}" CommandParameter="{Binding Path=SelectedItem}"/>
</ContextMenu>
</ListView.ContextMenu>
//listviewstuff here
</ListView>
VM:
public class VM : ViewModelBase
{
public RelayCommand UpdateCommand { get; private set; }
public Action UpdateCommandAction { get; set; }
public ObservableCollection<Status> ObservableCollectionList { get; set; }
public VM()
{
this.UpdateCommand = new RelayCommand(new Action(() => this.UpdateCommandAction.DynamicInvoke())));
}
}
Code-behind for the XAML view:
public partial class View
{
public View()
{
InitializeComponent();
var ViewDataContext = this.DataContext as VM;
ViewDataContext .UpdateCommandAction = UpdateStatus;
}
private void UpdateStatus()
{
MessageBox.Show("test");
}
}
I inserted a break point and it's not even making it to the method call. The debug output is not showing an error for me when I run the program either. What I don't understand is when I add this Command to the regular menu item that is NOT populated by a data bound list, it works fine. I would appreciate a fresh pair of eyes and some insight in to how this works.
回答1:
You need to bind the command to all the child items, now you bind it on the parent which will ignore it because it has child items (opens sub-menu instead).
To bind it on the children you need the ItemContainerStyle
, create a Setter
for the Command
there. You will need to walk up again, probably this: {Binding DataContext.DataContext.UpdateCommand, RelativeSource={RelativeSource AncestorType=MenuItem}}
(not sure about the AncestorLevel
, if it does select itself instead of the parent increase it; double DataContext
because you bound to DataContext.ObservableCollectionList
, assuming that binding to actually work).
Likewise there is no SelectedItem
in a menu, you need another Setter
for CommandParameter
, it will simply bind to the current item, i.e. {Binding}
.
Edit: Code example:
<MenuItem Header="Status"
ItemsSource="{Binding DataContext.ObservableCollectionList}"
DisplayMemberPath="Name">
<MenuItem.ItemContainerStyle>
<Style TargetType="MenuItem">
<Setter Property="Command" Value="{Binding DataContext.DataContext.UpdateCommand,
RelativeSource={RelativeSource AncestorType=MenuItem}}"/>
<Setter Property="CommandParameter" Value="{Binding}"/>
</Style>
</MenuItem.ItemContainerStyle>
</MenuItem>
回答2:
You'll need a List<MenuItem> MenuItems
to bind with ContextMenu ItemSource property as
public class MenuItem
{
public string Header { get; set; }
public ICommand Command { get; set; }
}
XAML: and set itemContainerstyle
<ContextMenu ItemsSource="{Binding MenuItems}" >
<ContextMenu.ItemContainerStyle>
<Style TargetType="{x:Type MenuItem}" >
<Setter Property="Header" Value="{Binding Header}"/>
<Setter Property="Command" Value="{Binding Command}" />
</Style>
</ContextMenu.ItemContainerStyle>
</ContextMenu>
And add as many contextmenu item you want in your ViewModel AS YOU WANT.
来源:https://stackoverflow.com/questions/24875966/databinding-a-command-to-context-menu-with-an-observable-collection