我们在使用WPF中的ListView之类的列表控件的时候,里面的ListViewItem的DataContext是列表中的项目,跟ListView控件的DataContext不一样。
有时候(比如权限相关的控制等)我们如果希望ContextMenu的菜单项的IsEnable等属性能跟列表项目之外的实例的属性绑定,则需要单独指定这个属性绑定的不一样的DataContext,同时又不改动整个ContextMenu的DataContext,这里举一例,需要.NET 4.0及以上。
例子中有一个UserControl,我把它命名为_this
,同时指定它的DataContext为_this
。其内有一个ListView,
<UserControl x:Class="Design_Library.ControlDesigns"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:Design_Library"
mc:Ignorable="d"
x:Name="_this"
DataContext="{Binding ElementName=_this}"
......此处省略N多字......
<UserControl.Resources>
<!--#region ContextMenu for Design -->
<ContextMenu x:Key="DesignCtxMenu">
<MenuItem Header="_Edit" IsEnabled="{Binding HasDesignEditingPermission, Source={x:Reference _this}}" Click="btnEditDsgn_Click"/>
<MenuItem Header="_Delete" IsEnabled="{Binding HasDesignRemovingPermission, Source={x:Reference _this}}" Click="btnDeleteDsgn_Click"/>
</ContextMenu>
<!--#endregion-->
</UserControl.Resources>
......此处省略N多字......
<ListView x:Name="lvDesigns" ItemsSource="{Binding Path=Designs}" SelectedItem="{Binding Path=SelectedDesign}" SelectionMode="Single" d:ItemsSource="{d:SampleData ItemCount=5}">
<ListView.ItemContainerStyle>
<Style TargetType="{x:Type ListViewItem}">
<!--<EventSetter Event="PreviewMouseLeftButtonDown" Handler="OnListViewItem_PreviewMouseLeftButtonDown" />-->
<EventSetter Event="MouseDoubleClick" Handler="ListViewItem_MouseDoubleClick"/>
<Setter Property="HorizontalContentAlignment" Value="Stretch" />
</Style>
</ListView.ItemContainerStyle>
<ListView.ItemTemplate>
<DataTemplate>
<Grid x:Name="panelDesign" ToolTip="{Binding Path=UICode}" Background="{Binding Path=DisabilityIndicator}">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="100"/>
<ColumnDefinition Width="3"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Image x:Name="imgDesign" Source="{Binding Path=Thumbnail}" Width="100" Height="100" ></Image>
<StackPanel Grid.Column="2">
<TextBlock FontWeight="UltraBold" Foreground="White" Background="DarkGoldenrod" Margin="0,5,0,0" Text="{Binding Path=UICode}"/>
<TextBlock FontWeight="Bold" Foreground="White" Background="DarkGoldenrod" Margin="0,0,0,5" Text="{Binding Path=Collection.UICode}" />
<TextBlock Text="{Binding Path=Designer.UIDisplay, StringFormat=Designer: {0}}" ToolTip="{Binding Path=Designer.UICombinedDisplay}" />
<TextBlock x:Name="txtDesignDate" Text="{Binding Path=UIDesignDate, StringFormat={}{0:d}}" />
<TextBlock Text="{Binding Path=UIDescription}" Height="{Binding ElementName=txtDesignDate, Path=ActualHeight}" Width="{Binding ElementName=txtDesignDate , Path=ActualWidth}" ToolTip="{Binding Path=UIDescription}" TextTrimming="CharacterEllipsis" TextWrapping="NoWrap" />
</StackPanel>
<Grid.ContextMenu>
<StaticResource ResourceKey ="DesignCtxMenu"/>
</Grid.ContextMenu>
</Grid>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
重点如下:
- 第8行和第9行定义了这个UserControl的数据上下文是它本身
x:Name="_this"
DataContext="{Binding ElementName=_this}"
注意定义数据上下文的时候还能用下面的方式,这里不适用,因为这种方式需要一个明确的x:Name
DataContext="{Binding RelativeSource={RelativeSource Self}}"
- 弹出菜单的资源的定义
<UserControl.Resources>
<!--#region ContextMenu for Design -->
<ContextMenu x:Key="DesignCtxMenu">
<MenuItem Header="_Edit" IsEnabled="{Binding HasDesignEditingPermission, Source={x:Reference _this}}" Click="btnEditDsgn_Click"/>
<MenuItem Header="_Delete" IsEnabled="{Binding HasDesignRemovingPermission, Source={x:Reference _this}}" Click="btnDeleteDsgn_Click"/>
</ContextMenu>
<!--#endregion-->
- 在ListView的数据模板里引用弹出菜单资源,这里不能直接把弹出菜单定义在这里,一定要用静态资源的方式,不然编辑器会提示找不到
_this
的定义,但不影响运行时,也就是说错误提示只在编辑器里提示,不影响最终程序的运行。
<Grid.ContextMenu>
<StaticResource ResourceKey ="DesignCtxMenu"/>
</Grid.ContextMenu>