Reputation: 1945
I have a UserControl
which contains a ContentControl
. The ContentControl
contains a ContextMenu
. I want to set the DataContext
of the ContextMenu
to a property in the UserControl
's viewmodel. The property in this case is another viewmodel.
Below is the .xaml for my user control:
<UserControl x:Class="TestProj.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:views="clr-namespace:OnyxWPF.Views"
mc:Ignorable="d">
<UserControl.Resources>
<BooleanToVisibilityConverter x:Key="BoolToVis" />
</UserControl.Resources>
<Grid>
<ContentControl Content="{Binding MainMap}">
<ContentControl.ContextMenu>
<ContextMenu DataContext="{Binding ContextMenuViewModel}" Visibility="{Binding IsPopUpEnabled, Converter={StaticResource BoolToVis}}" >
<MenuItem Header="Pan" Command="{Binding SetPanModeCmd}">
<MenuItem.Icon>
<Image Source="Images/panHand.ico" />
</MenuItem.Icon>
</MenuItem>
</ContentControl.ContextMenu>
</ContentControl>
</Grid>
</UserControl>
Here's the code behind for the user control:
public partial class MainWindow : UserControl
{
public MainWindow()
{
InitializeComponent();
DataContext = new MainViewModel();
}
}
The MainViewModel
- this is the DataContext
for the above UserControl
:
public class MainViewModel
{
public WpfMap MainMap { get; set; } //Content control's context is bound to this
public ContextMenuViewModel ContextMenuViewModel { get; set; } //this should be the context menu's datacontext
public bool IsPopUpEnabled { get; set; } //determines if the contextmenu will appear or not
public MainViewModel()
{
MainMap = new WpfMap();
ContextMenuViewModel = new ContextMenuViewModel();
IsPopUpEnabled = true;
}
}
Finally, here's the viewmodel for my contextmenu:
public class ContextMenuViewModel
{
public RelayCommand SetPanModeCmd { get; set; }
public ContextMenuViewModel()
{
SetPanModeCmd = new RelayCommand(SetPanMode);
}
private void SetPanMode()
{
//stuff
}
}
What I have in the xaml for the ContextMenu
above does not work. I've tried a few different variations using RelativeSource
but with no luck. Snippets of what I've tried below:
<ContextMenu DataContext="{Binding Path=Parent.DataContext.ContextMenuViewModel, RelativeSource={RelativeSource Self}}"
<ContextMenu DataContext="{Binding DataContext.ContextMenuViewModel, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=UserControl}}"
<ContextMenu DataContext="{Binding ContextMenuViewModel, RelativeSource={RelativeSource AncestorType=ContentControl}}"
<ContextMenu DataContext="{Binding DataContext.ContextMenuViewModel, RelativeSource={RelativeSource AncestorType=UserControl}}"
None of the above have worked.
Upvotes: 0
Views: 366
Reputation: 71
Any UIElement from the visual tree inherits parent's DataContext. In that case ContextMenu has MainViewModel as a DataContext after you assigned it to parent ContentControl. So, it means that you can get acces to any of properties of MainViewModel including ContextMenuViewModel. By the way, WPF data binding supports any number of nested properties. And you XAML will look like this:
<UserControl x:Class="TestProj.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:views="clr-namespace:OnyxWPF.Views"
mc:Ignorable="d">
<UserControl.Resources>
<BooleanToVisibilityConverter x:Key="BoolToVis" />
</UserControl.Resources>
<Grid>
<ContentControl Content="{Binding MainMap}">
<ContentControl.ContextMenu>
<ContextMenu Visibility="{Binding IsPopUpEnabled, Converter={StaticResource BoolToVis}}">
<MenuItem Header="Pan"
Command="{Binding ContextMenuViewModel.SetPanModeCmd}">
<MenuItem.Icon>
<Image Source="Images/panHand.ico" />
</MenuItem.Icon>
</MenuItem>
</ContextMenu>
</ContentControl.ContextMenu>
</ContentControl>
</Grid>
</UserControl>
P.S. In order to clarify: Command="{Binding ContextMenuViewModel.SetPanModeCmd}"
- ContextMenuViewModel is a name of MainViewModel's property, not of the Type.
Upvotes: 1