I have a context menu that is tied to a button in a datagrid. I want the context menu items to change based on a list of strings that I have in my view model. When I click the button, nothing shows up.
Here is the xaml I am using, which is in a datagrid:
<Button Grid.Column="1" Content="..." Click="Button_Click">
<Button.ContextMenu>
<ContextMenu ItemsSource="{Binding RelativeSource={RelativeSource Mode=FindAncestor,AncestorType={x:Type UserControl}},Path=DataContext.SelectableDescriptions}">
<TextBlock Text="{Binding}"/>
</ContextMenu>
</Button.ContextMenu>
</Button>
Here's the whole DataGrid xaml:
<DataGrid Grid.Row="1" Grid.ColumnSpan="4" CanUserAddRows="True" AutoGenerateColumns="False" CanUserDeleteRows="True" ItemsSource="{Binding JobPricings, Mode=TwoWay}" SelectedItem="{Binding SelectedJobPricing, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" >
<DataGrid.Columns>
<DataGridTemplateColumn Header="Description" Width="25*" >
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="75*"/>
<ColumnDefinition Width="25*"/>
</Grid.ColumnDefinitions>
<TextBox Grid.Column="0" Text="{Binding Description,Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
<Button Grid.Column="1" Content="..." Click="Button_Click">
<Button.ContextMenu>
<ContextMenu ItemsSource="{Binding RelativeSource={RelativeSource Mode=FindAncestor,AncestorType={x:Type UserControl}},Path=DataContext.SelectableDescriptions}">
<TextBlock Text="{Binding}"/>
</ContextMenu>
</Button.ContextMenu>
</Button>
</Grid>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTextColumn Header="Unit Price" Binding="{Binding UnitPrice, Mode=TwoWay}" Width="25*"/>
<DataGridTextColumn Header="Unit" Binding="{Binding Unit, Mode=TwoWay}" Width="25*"/>
<DataGridTemplateColumn Header="Currency " Width="25*" >
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Grid>
<ComboBox SelectedValue="{Binding CurrencyID, Mode=TwoWay}" SelectedValuePath="ID" DisplayMemberPath="Description" ItemsSource="{Binding RelativeSource={RelativeSource Mode=FindAncestor,AncestorType={x:Type UserControl}},Path=DataContext.Currencies}" ></ComboBox>
</Grid>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
Here is the property that I am binding the context menu to through my view model:
public ObservableCollection<string> SelectableDescriptions
{
get
{
_selectableDescriptions.Add("One");
_selectableDescriptions.Add("Two");
return _selectableDescriptions;
}
set
{
_selectableDescriptions = value;
}
}
Any ideas of why my list won't show up in the context menu?
As John says, ContextMenu is its own independent window, separated from the button's visual tree, and therefore it doesn't automatically inherit the button's DataContext.
However, a ContextMenu does have one link to the object it is placed upon (the button in your case): PlacementTarget. By going to the menu's PlacementTarget you find the button, and when you've found the button you can find its DataContext.
So, in xaml you can manually make the ContextMenu inherit the Button's DataContext by binding its own DataContext to its own PlacementTarget.DataContext, and all other bindings (e.g. for ItemsSource) can be written like normal:
<Button Grid.Column="1" Content="..." Click="Button_Click">
<Button.ContextMenu>
<ContextMenu DataContext="{Binding RelativeSource={RelativeSource Self}, Path=PlacementTarget.DataContext}"
ItemsSource="{Binding Path=SelectableDescriptions}" >
<ContextMenu.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Path=SomePropertyOnItem}" />
</DataTemplate>
</ContextMenu.ItemTemplate>
</ContextMenu>
</Button.ContextMenu>
</Button>
Things like ContextMenu and Popup exist outside the main visual tree and so can't use RelativeSource to walk up to a parent object. In most cases ElementName breaks too. There are various workarounds available depending on the specific situation. I like using inherited attached properties to pass additional data as it doesn't involve changing your VM and stays right in the XAML after you get it set up. Here's a blog post explaining the technique with examples: http://blogs.interknowlogy.com/2011/04/26/binding-to-alternate-datacontexts/
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With