Привязка DataContext ContextMenu к свойству в DataContext контейнера - PullRequest
0 голосов
/ 04 мая 2019

У меня есть UserControl, который содержит ContentControl.ContentControl содержит ContextMenu.Я хочу установить DataContext из ContextMenu для свойства в UserControl viewmodel.Свойство в этом случае - другая модель представления.

Ниже .xaml для моего пользовательского элемента управления:

<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>

Вот код для пользовательского элемента управления:

public partial class MainWindow : UserControl
{
    public MainWindow()
    {
        InitializeComponent();
        DataContext = new MainViewModel();
    }
}

MainViewModel - это DataContext для вышеуказанного 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;
    }
}

Наконец, вот модель представления для моего контекстного меню:

public class ContextMenuViewModel
{
    public RelayCommand SetPanModeCmd { get; set; }

    public ContextMenuViewModel()
    {
        SetPanModeCmd = new RelayCommand(SetPanMode);
    }

    private void SetPanMode()
    {
        //stuff
    }
}

Что у меня естьв xaml для ContextMenu выше не работает.Я пробовал несколько разных вариантов, используя RelativeSource, но безуспешно.Фрагменты того, что я пробовал ниже:

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

Ничего из вышеперечисленного не сработало.

1 Ответ

1 голос
/ 04 мая 2019

Любой UIElement из визуального дерева наследует DataContext родителя. В этом случае ContextMenu имеет MainViewModel в качестве DataContext после того, как вы присвоили его родительскому ContentControl. Таким образом, это означает, что вы можете получить доступ к любому из свойств MainViewModel, включая ContextMenuViewModel. Кстати, привязка данных WPF поддерживает любое количество вложенных свойств. И ваш XAML будет выглядеть так:

    <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. Чтобы уточнить: Command="{Binding ContextMenuViewModel.SetPanModeCmd}" - ContextMenuViewModel - это имя свойства MainViewModel, а не типа.

...