WPF MenuItem.Command привязка к ElementName приводит к ошибке System.Windows.Data: 4: Не удается найти источник для привязки со ссылкой
У меня есть следующий XAML:
<UserControl x:Class="EMS.Controls.Dictionary.TOCControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:vm="clr-namespace:EMS.Controls.Dictionary.Models"
xmlns:diagnostics="clr-namespace:System.Diagnostics;assembly=WindowsBase"
x:Name="root" >
<TreeView
x:Name="TOCTreeView"
Background="White"
Padding="3,5"
ContextMenuOpening="TOCTreeView_ContextMenuOpening"
ItemsSource="{Binding Children}" BorderBrush="{x:Null}" >
<TreeView.ItemTemplate>
<HierarchicalDataTemplate ItemsSource="{Binding Path=Children, Mode=OneTime}">
<Grid >
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<!--<ColumnDefinition Width="Auto"/>-->
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<!--<CheckBox VerticalAlignment="Center" IsChecked="{Binding IsVisible}"/>-->
<ContentPresenter Grid.Column="0" Height="16" Width="20"
Content="{Binding LayerRepresentation}" />
<!--<ContentPresenter Grid.Column="1" >
<ContentPresenter.Content>
Test
</ContentPresenter.Content>
</ContentPresenter>-->
<TextBlock Grid.Column="2" FontWeight="Normal" Text="{Binding Path=Alias, Mode=OneWay}" >
<ToolTipService.ToolTip>
<TextBlock Text="{Binding Description}" TextWrapping="Wrap"/>
</ToolTipService.ToolTip>
</TextBlock>
</Grid>
<HierarchicalDataTemplate.ItemTemplate>
<HierarchicalDataTemplate ItemsSource="{Binding Path=Children, Mode=OneTime}">
<!--<DataTemplate>-->
<Grid >
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<CheckBox VerticalAlignment="Center" IsChecked="{Binding IsVisible}"/>
<ContentPresenter Grid.Column="1"
Content="{Binding LayerRepresentation, Mode=OneWay}" />
<TextBlock Margin="0,1,0,1" Text="{Binding Path=Alias, Mode=OneWay}" Grid.Column="2">
<ToolTipService.ToolTip>
<TextBlock Text="{Binding Description}" TextWrapping="Wrap"/>
</ToolTipService.ToolTip>
</TextBlock>
</Grid>
<!--</DataTemplate>-->
</HierarchicalDataTemplate>
</HierarchicalDataTemplate.ItemTemplate>
</HierarchicalDataTemplate>
</TreeView.ItemTemplate>
<TreeView.ContextMenu>
<ContextMenu>
<MenuItem Name="miRemove" Header="Remove"
Command="{Binding ElementName=root, Path=RemoveItemCmd,
diagnostics:PresentationTraceSources.TraceLevel=High}">
<MenuItem.Icon>
<Image Source="../images/16x16/Delete.png"/>
</MenuItem.Icon>
</MenuItem>
<MenuItem Header="Properties"
Command="{Binding ElementName=root, Path=GetItemPropertiesCmd}"/>
</ContextMenu>
</TreeView.ContextMenu>
</TreeView>
</UserControl>
Код для этого UserControl имеет два свойства ICommand с именами: RemoveItemCmd и GetItemPropertiesCmd. Однако я получаю
System.Windows.Data Error: 4 : Cannot find source for binding with reference 'ElementName=root'. BindingExpression:Path=RemoveItemCmd; DataItem=null; target element is 'MenuItem' (Name='miRemove'); target property is 'Command' (type 'ICommand')
System.Windows.Data Error: 4 : Cannot find source for binding with reference 'ElementName=root'. BindingExpression:Path=GetItemPropertiesCmd; DataItem=null; target element is 'MenuItem' (Name=''); target property is 'Command' (type 'ICommand')
при построении UserControl. Почему это и как я могу решить?
Ответы
Ответ 1
Невозможно связать имя элемента с контекстным меню. Ссылка разбита между контекстным меню и целевым объектом размещения. Вы можете обойти его, используя пару трюков, хотя...
- Используйте RoutedUICommands с привязкой команды к UserControl, тогда привязка не требуется.
-
Используйте привязку места размещения в контекстном меню DataContext. Это позволяет по крайней мере получить контекст данных элемента, контекстное меню которого отображается в контекстном меню.
DataContext = "{Binding RelativeSource = {RelativeSource Mode = Self}, Path = PlacementTarget.DataContext}"
-
(и я думаю, что это то, что вы хотите). Вы можете получить доступ к статическому ресурсу, ElementSpy позволяет вам ссылаться на окна, используя статический ресурс, чтобы затем использовать привязки атрибутов defacto ElementName.
Ответ 2
Лучшее решение здесь ElementName Связывание с MenuItem в ContextMenu
Только одна строка кода:
NameScope.SetNameScope(contextMenu, NameScope.GetNameScope(this));
Ответ 3
С .NET 4.0 вы можете сделать это следующим образом:
<MenuItem Command="{Binding CommandName, Source={x:Reference ElementName}}"/>