Reputation: 693
Well, I have a WPF project and I'm using Visual Studio 2010. I'm using C# and XAML, and I'm using the MVVM pattern.
The problem I have must be simple but I just can't see why it's not working.
Alright, so I have a project with a ListBox. In that ListBox are many ChatNodes; each represented visually. The visual element for a ChatNode is here:
<ControlTemplate x:Key="NodeVisualTemplate">
<Grid>
<Border BorderThickness="2" Margin="2" CornerRadius="5,5,5,5" BorderBrush="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ListBox}}, Path=DataContext.SelectionMode, Converter={StaticResource SelectionModeToColourConverter}}" ContextMenu="{StaticResource ChatNodeMenu}">
<StackPanel Opacity="{Binding IsInvisibleNode, Converter={StaticResource ResourceKey=VisibleToOpacityConverter}}">
<TextBlock Text="Test" Background="AntiqueWhite"/>
<TextBlock Text="{Binding Path=NodeText}" Background="Aqua"/>
<StackPanel Orientation="Horizontal">
<TextBox Text="Type here" MinWidth="50"/>
<Image Source="{StaticResource ImgFolder}" Margin="0,0,5,0" Width="32" Height="32"/>
</StackPanel>
</StackPanel>
</Border>
</Grid>
</ControlTemplate>
I draw your attention to the BorderBrush for the Border. I will show that again here:
BorderBrush="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ListBox}}, Path=DataContext.SelectionMode, Converter={StaticResource SelectionModeToColourConverter}}"
This code sits inside a ListBoxItem and is able to find the parent ListBox and then access a property of it. This works fine. The property is in a view model called ChatNodeListViewModel and looks like this:
private int _selectionMode = 0;
public int SelectionMode
{
get { return _selectionMode; }
set
{
if (_selectionMode != value)
{
_selectionMode = value;
RaisePropertyChanged("SelectionMode");
}
}
}
I mention it specifically because another thing which is almost identical is not working, even though this BorderBrush code is working.
So, on to the not working part.
In that same ControlTemplate above, we see a ContextMenu, called 'ChatNodeMenu'. This is as follows:
<ContextMenu x:Key="ChatNodeMenu" >
<MenuItem Header="Remove" Command="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ListBox}}, Path=DataContext.RemoveChatNodeCommand}" />
</ContextMenu>
It has the same binding, only this time it is for a Command called 'RemoveChatNodeCommand'. The menu does appear on a right click on a ChatNode, but the command does not run. I have actually used almost identical code in other parts of my project so I assume it's correct... but clearly there is an error somewhere.
So where is this command? It is in the view model called 'ChatNodeListViewModel' and I will present it here:
void RemoveChatNodeExecute()
{
MessageBox.Show("Remove chat node");
return;
}
bool CanRemoveChatNode()
{
return true;
}
public ICommand RemoveChatNodeCommand { get { return new RelayCommand(RemoveChatNodeExecute, CanRemoveChatNode); } }
I have also used this in many places throughout my code and it's worked every time but this one.
So, either there's a fault in the code or perhaps a simple mistake. I've checked the name of the command and re-copied it several times. I've checked the other parts of my code where I've used the same code, but I can't see anything wrong. I've cleaned and rebuilt my project just in case.
If anyone can venture a guess, I would be very happy with that.
Upvotes: 2
Views: 938
Reputation: 1
I have same issue related to conextmenu not able to work on command. could you help me to find solution.
<GridViewColumn>
<GridViewColumn.CellTemplate>
<DataTemplate>
<Button Content="test2">
<Button.ContextMenu>
<ContextMenu>
<MenuItem Header="rr2" Command="{Binding DataContext.NextCommand, RelativeSource={RelativeSource AncestorType={x:Type ListView}}}" CommandParameter="{Binding}" ></MenuItem>
</ContextMenu>
</Button.ContextMenu>
</Button>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
Upvotes: 0
Reputation: 169190
The ListBox
is not a visual ancestor of a ContextMenu
but you could set the Tag
property of the Border
to the ListBox
and then bind to the PlacementTarget
of the ContextMenu
:
<Border ... Tag="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ListBox}}" ContextMenu="{StaticResource ChatNodeMenu}">
<MenuItem Header="Remove" Command="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ContextMenu}}, Path=PlacementTarget.Tag.DataContext.RemoveChatNodeCommand}" />
Upvotes: 2