绑定到位于VisualTree中远离MenuItem的ElementName



这是我的应用程序的布局草图:

<UserControl>
<Grid>
<Grid.ColumnDefinitions>...</Grid.ColumnDefinitions>
<Grid.RowDefinitions>...</Grid.RowDefinitions>
<Border>...</Border>
<Grid>...</Grid>
<DataGrid Grid.Column="1" Grid.ColumnSpan="2" Grid.Row="2" AutoGenerateColumns="False"
HorizontalAlignment="Stretch" Name="myDataGrid" VerticalAlignment="Stretch"
ItemsSource="{Binding Path=MyModel.Files}"
SelectedItem="{Binding SelectedFile}"                     
Margin="0,0,10,3" CanUserReorderColumns="False" CanUserResizeRows="False" Style="{StaticResource DataGridStyle_Generic}"
IsReadOnly="True">...</DataGrid.ContextMenu>
</DataGrid>
<Border>...</Border>
<Border BorderBrush="Gray" BorderThickness="1" Grid.Row="4" Grid.Column="1" Grid.ColumnSpan="2" Margin="0,0,10,0">
<Grid Margin="0,0,10,0">
<Grid.ColumnDefinitions>...</Grid.ColumnDefinitions>
<Grid.RowDefinitions>...</Grid.RowDefinitions>
<StackPanel Grid.Row="1" Orientation="Horizontal" Margin="0,0,10,2">
<Button>...</Button>
<Button Margin="0" Name="m_DropDownButton" Padding="0, 4"
HorizontalAlignment="Center" VerticalAlignment="Center"                            
ContextMenuService.IsEnabled="False" Click="m_DropDownButton_Click">
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center" VerticalAlignment="Center">
<Path x:Name="BtnArrow" Margin="4" VerticalAlignment="Center" Width="6" Fill="#FF000000" Stretch="Uniform" HorizontalAlignment="Right" Data="F1 M 301.14,-189.041L 311.57,-189.041L 306.355,-182.942L 301.14,-189.041 Z "/>
</StackPanel>
<Button.ContextMenu>
<ContextMenu>
<MenuItem Header="All files" Command="{Binding AllFilesCommand}" />
<MenuItem Header="Selected files only" 
Command="{Binding SelectedFilesOnlyCommand}"
CommandParameter="{Binding Path=SelectedItems, ElementName=myDataGrid}"/>          
</ContextMenu>
</Button.ContextMenu>
</Button>
</StackPanel>
<StackPanel Grid.Row="0" Orientation="Horizontal" VerticalAlignment="Stretch" Margin="0,0,10,0">...</StackPanel>
</Grid>
</Border>
</Grid>
</UserControl>

我想将myDataGridSelectedItems属性作为myMenuItem的命令中的CommandParameter传递。我怎样才能做到这一点?

注意#1:这两个控件位于Visual Tree的远处,它们的第一个公共父控件是myGrid。找不到任何有效的解决方案,因为我总是在输出窗口中收到"找不到绑定的源"错误消息。

注意#2:DataGrid的SelectedItems属性是只读的,因此不允许将其绑定到ViewModel属性。

注意#3:我希望避免任何代码背后的代码,例如为DataGrid的SelectionChanged事件创建事件处理程序。

我没有尝试Sheridan的方式,值得一读。

无论如何,你也可以尝试以下破解:

<Button Margin="0" Name="m_DropDownButton" Padding="0, 4"
HorizontalAlignment="Center" VerticalAlignment="Center"                            
ContextMenuService.IsEnabled="False" Click="m_DropDownButton_Click"
Tag="{Binding ElementName=myDataGrid}"
>
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center" VerticalAlignment="Center">
<Path x:Name="BtnArrow" Margin="4" VerticalAlignment="Center" Width="6" Fill="#FF000000" Stretch="Uniform" HorizontalAlignment="Right" Data="F1 M 301.14,-189.041L 311.57,-189.041L 306.355,-182.942L 301.14,-189.041 Z "/>
</StackPanel>
<Button.ContextMenu>
<ContextMenu>
<MenuItem Header="All files" Command="{Binding AllFilesCommand}" />
<MenuItem Header="Selected files only" 
Command="{Binding SelectedFilesOnlyCommand}"
CommandParameter="{Binding Path=PlacementTarget.Tag.SelectedItems, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=ContextMenu}}"/>
</ContextMenu>
</Button.ContextMenu>
</Button>

注意按钮上的"Tag"属性和CommandParameter绑定。

后面还有一个小代码,但我相信你也有:

private void m_DropDownButton_Click(object sender, RoutedEventArgs e)
{
var button = (Button)sender;
button.ContextMenu.PlacementTarget = button;
button.ContextMenu.IsOpen = true;
}

让我知道。

您有一个棘手的需求需要满足,但解决方案。这有点长,可能也有点痛苦,因为你还有相当多的工作要做,但就在这里。

因为ContextMenu不是普通视觉树的一部分,所以它无法访问在那里定义的元素或DataContext的成员。要解决这个问题,需要做两(或三)件事。第一件事是向视图模型中添加一个属性,以便将数据绑定到DataGrid.SelectedItems属性。

您必须做的第二件事是创建一种在DataGrid.SelectedItems属性上具有TwoWay Binding的方法,因为"内置"属性是只读的。幸运的是,网上有很多关于这个主题的帖子,涉及到自定义可绑定SelectedItems附加属性的使用。我想你可以自己找到它们。

因此,现在假设您有权访问视图模型中的选定项或代码隐藏,接下来需要将ContextMenu.DataContext属性设置为视图模型的实例。我们可以使用ContextMenu.PlacementTarget性质和一直有用的Tag性质来做到这一点。。。试试这个:

<Button Tag="{Binding DataContext, RelativeSource={RelativeSource AncestorType={x:Type 
Views:YourView}}}">
<Button.ContextMenu>
<ContextMenu DataContext="{Binding PlacementTarget.Tag, RelativeSource={
RelativeSource Self}}">
<MenuItem />
<MenuItem Name="myMenuItem" Command="{Binding DoAction}" 
CommandParameter="{Binding SelectedItems}" />
</ContextMenu>
</Button.ContextMenu>
</Button>

Tag属性中的Binding将看起来绑定到父视图(WindowUserControl)的DataContext属性的内容,假设它的名称为YourView,并且您已经为视图项目或文件夹设置了名为Views的XML命名空间前缀。

接下来,ContextMenu.DataContextTag属性设置为相同的值,因此现在ContextMenu可以访问SelectedItems属性视图模型中的命令。

最新更新