Команда привязки MVVM к элементу контекстного меню - PullRequest
17 голосов
/ 03 апреля 2012

Я пытаюсь привязать команду к элементу меню в WPF. Я использую тот же метод, который работал для всех других моих командных привязок, но я не могу понять, почему он здесь не работает.

В настоящее время я связываю свои команды следующим образом:

Command = "{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type UserControl}}, Path=DataContext.MyCommand}"

Здесь все идет не так (это внутри UserControl)

<Button Height="40" Margin="0,2,0,0" CommandParameter="{Binding Name}" 
                        Command = "{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type UserControl}}, Path=DataContext.ConnectCommand}">

     <Button.ContextMenu>
         <ContextMenu>
             <MenuItem Header="Remove" CommandParameter="{Binding Name}"
                                      Command="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type UserControl}}, Path=DataContext.RemoveCommand}"/>
         </ContextMenu>
     </Button.ContextMenu>
     ...

Первая команда связывания работает так, как должна, но вторая отказывается что-либо делать. Я попытался изменить уровень предка и назвать свой элемент управления для доступа к нему через ElementName вместо RelativeSource, но все еще без изменений. Он продолжает говорить "Не удается найти источник для привязки со ссылкой ..."

Чего мне не хватает?

Ответы [ 4 ]

26 голосов
/ 03 апреля 2012

(Изменить) Поскольку вы упомянули, что это в шаблоне ItemsControl, все по-другому:

1) Получите класс BindingProxy из этого блога (и прочитайте блог, так как это интересная информация): Как привязать данные, когда DataContext не наследуется .

В основном элементы ItemsControl (или ContextMenu) не являются частью визуального или логического дерева и поэтому не могут найти DataContext вашегоUserControl.Я приношу свои извинения за то, что не написал больше об этом здесь, но автор проделал хорошую работу, объясняя это шаг за шагом, поэтому я никак не мог дать полное объяснение всего за несколько строк.

2) Сделайте что-нибудькак это: (вам, возможно, придется немного адаптировать его, чтобы заставить его работать под вашим контролем):

a.Это даст вам доступ к UserControl DataContext с использованием StaticResource:

<UserControl.Resources>
<BindingProxy
  x:Key="DataContextProxy"
  Data="{Binding}" />
</UserControl.Resources>

b.При этом используется DataContextProxy, определенный в (a):

<Button.ContextMenu>
 <ContextMenu>
     <MenuItem Header="Remove" CommandParameter="{Binding Name}"
         Command="{Binding Path=Data.RemoveCommand, Source={StaticResource DataContextProxy}}"/>
 </ContextMenu>

Это работает для нас в таких вещах, как деревья и сетки данных.

11 голосов
/ 03 апреля 2012

ContextMenu находится в другом логическом дереве, поэтому RelativeSource не работает.Но контекстное меню наследует DataContext от своего «контейнера», в данном случае это Button.В общем случае этого достаточно, но в вашем случае вам нужны два «контекста данных» - элемента ItemsControl и самого ItemsControl.Я думаю, что у вас нет другого выбора, кроме как объединить ваши модели представлений в одну, реализовать собственный класс, который будет использоваться в качестве контекста данных элемента ItemsControl, и содержать как «Имя», так и «Удалить команду», или модель представления вашего элемента может определить «прокси» RemoveCommand, чтобудет вызывать родительскую команду внутри

РЕДАКТИРОВАТЬ: я немного изменил код Бабуина, он должен работать следующим образом:

<Button Height="40" Margin="0,2,0,0" CommandParameter="{Binding Name}" 
    Tag="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type UserControl}}}"
    Command = "{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type UserControl}}, Path=DataContext.ConnectCommand}">
            <Button.ContextMenu>
                <ContextMenu>
                    <MenuItem Header="Remove" 
                   CommandParameter="{Binding Name}"
                   Command="{Binding Path=PlacementTarget.Tag.DataContext.RemoveCommand, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=ContextMenu}}"/>
                </ContextMenu>
            </Button.ContextMenu>
5 голосов
/ 30 декабря 2013

Кошдим на месте, работает как шарм !!Спасибо Кошдим

Я изменил его код, чтобы он поместился в моем контекстном меню

    <DataGrid 
        AutoGenerateColumns="False" 
        HeadersVisibility="Column"
        Name="dgLosses"
        SelectedItem="{Binding SelectedItem, Mode= TwoWay}"
        AllowDrop="True"
        ItemsSource="{Binding Losses}"
        Tag="{Binding DataContext,RelativeSource={RelativeSource Mode=FindAncestor,AncestorType=Window}}">


        <DataGrid.ContextMenu >
            <ContextMenu >
                <MenuItem Header="Move to Top     "   Command="{Binding PlacementTarget.Tag.MoveToTopCommand,RelativeSource={RelativeSource Mode=FindAncestor,AncestorType=ContextMenu}}" ></MenuItem>
                <MenuItem Header="Move to Period 1"   Command="{Binding PlacementTarget.Tag.MoveToPeriod1Command,RelativeSource={RelativeSource Mode=FindAncestor,AncestorType=ContextMenu}}" ></MenuItem>
                <MenuItem Header="Move to Period 2"   Command="{Binding PlacementTarget.Tag.MoveToPeriod2Command,RelativeSource={RelativeSource Mode=FindAncestor,AncestorType=ContextMenu}}" ></MenuItem>
                <MenuItem Header="Move to Period 3"   Command="{Binding PlacementTarget.Tag.MoveToPeriod3Command,RelativeSource={RelativeSource Mode=FindAncestor,AncestorType=ContextMenu}}" ></MenuItem>                    
            </ContextMenu>
        </DataGrid.ContextMenu>
3 голосов
/ 03 апреля 2012

Это сложная проблема, конечно, вы найдете быстрый обходной путь, но вот решение без магии:

<Button Height="40" Margin="0,2,0,0" CommandParameter="{Binding Name}" 
        Tag={Binding}
        Command = "{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type UserControl}}, Path=DataContext.ConnectCommand}">    
     <Button.ContextMenu>
         <ContextMenu>
             <MenuItem Header="Remove" 
                       CommandParameter="{Binding Path=PlacementTarget.Tag.Name, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=ContextMenu}}"
                       Command="{Binding Path=PlacementTarget.Tag.RemoveCommand, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=ContextMenu}}"/>
         </ContextMenu>
     </Button.ContextMenu>
...

Это сводится к использованию Tag из PlacementTarget(Button здесь).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...