将事件处理程序分配给以自定义样式定义的 ContextMenu 项
Assign event handler to ContextMenu item defined in custom style
我创建了带有预定义菜单项的上下文菜单样式:
<Style TargetType="{x:Type ContextMenu}" x:Key="DataGridColumnFilterContextMenu">
<Setter Property="ContextMenu.Template">
<Setter.Value>
<ControlTemplate>
<Border BorderBrush="#868686"
BorderThickness="1"
Background="#FAFAFA">
<Grid MaxHeight="500">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<StackPanel>
<MenuItem Header="Filtrēt" StaysOpenOnClick="True" Name="DynSearch">
<MenuItem.Icon>
<Image RenderOptions.BitmapScalingMode="NearestNeighbor"
RenderOptions.EdgeMode="Aliased"
Source="/Furniture;component/Resources/search4.png" />
</MenuItem.Icon>
</MenuItem>
<Separator Margin="20 5 20 0" Height="2" Width="Auto" />
<MenuItem Margin="5 5 0 0" StaysOpenOnClick="True" >
<MenuItem.Template>
<ControlTemplate >
<CheckBox Padding="15 0 0 0" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" >Iezīmēt/Atzīmēt visus</CheckBox>
</ControlTemplate>
</MenuItem.Template>
<MenuItem.Icon>
<Image RenderOptions.BitmapScalingMode="NearestNeighbor"
RenderOptions.EdgeMode="Aliased"
Source="/Furniture;component/Resources/search4.png" />
</MenuItem.Icon>
</MenuItem>
<Separator Margin="20 5 20 0" Height="2" Width="Auto" />
<RadioButton Margin="5 5 0 0" Padding="15 0 0 0" GroupName="Sorting" Content="Augoša secībā" IsChecked="True"/>
<RadioButton Margin="5 5 0 0" Padding="15 0 0 0" GroupName="Sorting" Content="Dilstoša secībā" />
<Separator Margin="20 5 20 5" Height="2" Width="Auto" />
</StackPanel>
<ScrollViewer Grid.Row="1"
Margin="1,0,1,0"
CanContentScroll="True"
VerticalScrollBarVisibility="Auto"
Grid.ColumnSpan="2">
<ItemsPresenter KeyboardNavigation.DirectionalNavigation="Cycle" />
</ScrollViewer>
</Grid>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
现在我将样式分配给新的 ContextMenu,并想将 Click 事件处理程序分配给在 header "Filtrēt" 样式中定义的 MenuItem。我试过这样做:
ContextMenu cm = new ContextMenu();
cm.Style = Application.Current.Resources["DataGridColumnFilterContextMenu"] as Style;
var controlList = ((((cm.Template.LoadContent() as Border).Child as Grid).Children)[0] as StackPanel).Children;
MenuItem filterItem = (controlList[0] as MenuItem);
filterItem.Click += MiFiltre_Click;
而当我点击 debugger 时,它并没有进入 MiFiltre_Click 方法。我尝试了不同的事件,例如 MouseDown 和 PreviewMouseDown。我也尝试绑定 ICommand,但这也没有用。
然后我搜索了这个问题并意识到 cm.Template.LoadContent() 实际上可能会创建我的 ContextMenu 模板的新实例,我正试图将我的事件处理程序绑定到不同的控件实例。然后我尝试使用 VisualTreeHelper 和 LogicalTreeHelper 获取 ContextMenu 节点控件,但这也没有用。
所以这里有问题:
- 如何实现Click事件处理器绑定?
- 如果第一题太
很难,那么如何定义 ContextMenu 子项的当前实例
自定义样式?
我假设此菜单样式是在名为 "MyResources.xaml" 的资源字典中定义的。
在同一项目文件夹中创建一个Class文件,并将其命名为"MyResources.xaml.cs"。
像这样使其成为部分 class:
namespace WhateverNamespace
{
public partial class MyResources
{
private void FilterMenuItem_Click(object sender, RoutedEventArgs e)
{
MenuItem mi = (MenuItem)sender;
// Below, PlacementTarget is the control the user right-clicked on.
// Use that directly if you want that instead of its viewmodel.
// This works with the conventional ContextMenu defined below.
//ViewModel viewModel = ((FrameworkElement)((ContextMenu)mi.Parent).PlacementTarget).DataContext as ViewModel;
// This works with your template design. The only difference is
// TemplatedParent instead of Parent.
ViewModel viewModel =
((FrameworkElement)((ContextMenu)mi.TemplatedParent).PlacementTarget)
.DataContext as ViewModel;
MessageBox.Show("FilterMenuItem_Click");
}
}
}
给资源字典一个x:Class
属性:
<ResourceDictionary
x:Class="WhateverNamespace.MyResources"
连接处理程序:
<MenuItem
Click="FilterMenuItem_Click"
Header="Filtrēt"
StaysOpenOnClick="True"
Name="DynSearch">
顺便说一下,您不需要乱用样式和模板来创建 ContextMenu
资源:
<ContextMenu x:Key="DataGridColumnFilterContextMenu">
<MenuItem
Click="FilterMenuItem_Click"
Header="Filtrēt"
StaysOpenOnClick="True"
Name="DynSearch">
<MenuItem.Icon>
<Image
RenderOptions.BitmapScalingMode="NearestNeighbor"
RenderOptions.EdgeMode="Aliased"
Source="/Furniture;component/Resources/search4.png"
/>
</MenuItem.Icon>
</MenuItem>
<Separator />
<MenuItem StaysOpenOnClick="True">
<MenuItem.Header>
<CheckBox>Iezīmēt/Atzīmēt visus</CheckBox>
</MenuItem.Header>
<MenuItem.Icon>
<Image
RenderOptions.BitmapScalingMode="NearestNeighbor"
RenderOptions.EdgeMode="Aliased"
Source="/Furniture;component/Resources/search4.png"
/>
</MenuItem.Icon>
</MenuItem>
<Separator />
<MenuItem>
<MenuItem.Header>
<RadioButton GroupName="Sorting" Content="Augoša secībā" IsChecked="True"/>
</MenuItem.Header>
</MenuItem>
<MenuItem>
<MenuItem.Header>
<RadioButton GroupName="Sorting" Content="Dilstoša secībā" IsChecked="True"/>
</MenuItem.Header>
</MenuItem>
</ContextMenu>
我创建了带有预定义菜单项的上下文菜单样式:
<Style TargetType="{x:Type ContextMenu}" x:Key="DataGridColumnFilterContextMenu">
<Setter Property="ContextMenu.Template">
<Setter.Value>
<ControlTemplate>
<Border BorderBrush="#868686"
BorderThickness="1"
Background="#FAFAFA">
<Grid MaxHeight="500">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<StackPanel>
<MenuItem Header="Filtrēt" StaysOpenOnClick="True" Name="DynSearch">
<MenuItem.Icon>
<Image RenderOptions.BitmapScalingMode="NearestNeighbor"
RenderOptions.EdgeMode="Aliased"
Source="/Furniture;component/Resources/search4.png" />
</MenuItem.Icon>
</MenuItem>
<Separator Margin="20 5 20 0" Height="2" Width="Auto" />
<MenuItem Margin="5 5 0 0" StaysOpenOnClick="True" >
<MenuItem.Template>
<ControlTemplate >
<CheckBox Padding="15 0 0 0" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" >Iezīmēt/Atzīmēt visus</CheckBox>
</ControlTemplate>
</MenuItem.Template>
<MenuItem.Icon>
<Image RenderOptions.BitmapScalingMode="NearestNeighbor"
RenderOptions.EdgeMode="Aliased"
Source="/Furniture;component/Resources/search4.png" />
</MenuItem.Icon>
</MenuItem>
<Separator Margin="20 5 20 0" Height="2" Width="Auto" />
<RadioButton Margin="5 5 0 0" Padding="15 0 0 0" GroupName="Sorting" Content="Augoša secībā" IsChecked="True"/>
<RadioButton Margin="5 5 0 0" Padding="15 0 0 0" GroupName="Sorting" Content="Dilstoša secībā" />
<Separator Margin="20 5 20 5" Height="2" Width="Auto" />
</StackPanel>
<ScrollViewer Grid.Row="1"
Margin="1,0,1,0"
CanContentScroll="True"
VerticalScrollBarVisibility="Auto"
Grid.ColumnSpan="2">
<ItemsPresenter KeyboardNavigation.DirectionalNavigation="Cycle" />
</ScrollViewer>
</Grid>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
现在我将样式分配给新的 ContextMenu,并想将 Click 事件处理程序分配给在 header "Filtrēt" 样式中定义的 MenuItem。我试过这样做:
ContextMenu cm = new ContextMenu();
cm.Style = Application.Current.Resources["DataGridColumnFilterContextMenu"] as Style;
var controlList = ((((cm.Template.LoadContent() as Border).Child as Grid).Children)[0] as StackPanel).Children;
MenuItem filterItem = (controlList[0] as MenuItem);
filterItem.Click += MiFiltre_Click;
而当我点击 debugger 时,它并没有进入 MiFiltre_Click 方法。我尝试了不同的事件,例如 MouseDown 和 PreviewMouseDown。我也尝试绑定 ICommand,但这也没有用。
然后我搜索了这个问题并意识到 cm.Template.LoadContent() 实际上可能会创建我的 ContextMenu 模板的新实例,我正试图将我的事件处理程序绑定到不同的控件实例。然后我尝试使用 VisualTreeHelper 和 LogicalTreeHelper 获取 ContextMenu 节点控件,但这也没有用。
所以这里有问题:
- 如何实现Click事件处理器绑定?
- 如果第一题太 很难,那么如何定义 ContextMenu 子项的当前实例 自定义样式?
我假设此菜单样式是在名为 "MyResources.xaml" 的资源字典中定义的。
在同一项目文件夹中创建一个Class文件,并将其命名为"MyResources.xaml.cs"。
像这样使其成为部分 class:
namespace WhateverNamespace { public partial class MyResources { private void FilterMenuItem_Click(object sender, RoutedEventArgs e) { MenuItem mi = (MenuItem)sender; // Below, PlacementTarget is the control the user right-clicked on. // Use that directly if you want that instead of its viewmodel. // This works with the conventional ContextMenu defined below. //ViewModel viewModel = ((FrameworkElement)((ContextMenu)mi.Parent).PlacementTarget).DataContext as ViewModel; // This works with your template design. The only difference is // TemplatedParent instead of Parent. ViewModel viewModel = ((FrameworkElement)((ContextMenu)mi.TemplatedParent).PlacementTarget) .DataContext as ViewModel; MessageBox.Show("FilterMenuItem_Click"); } } }
给资源字典一个
x:Class
属性:<ResourceDictionary x:Class="WhateverNamespace.MyResources"
连接处理程序:
<MenuItem Click="FilterMenuItem_Click" Header="Filtrēt" StaysOpenOnClick="True" Name="DynSearch">
顺便说一下,您不需要乱用样式和模板来创建 ContextMenu
资源:
<ContextMenu x:Key="DataGridColumnFilterContextMenu">
<MenuItem
Click="FilterMenuItem_Click"
Header="Filtrēt"
StaysOpenOnClick="True"
Name="DynSearch">
<MenuItem.Icon>
<Image
RenderOptions.BitmapScalingMode="NearestNeighbor"
RenderOptions.EdgeMode="Aliased"
Source="/Furniture;component/Resources/search4.png"
/>
</MenuItem.Icon>
</MenuItem>
<Separator />
<MenuItem StaysOpenOnClick="True">
<MenuItem.Header>
<CheckBox>Iezīmēt/Atzīmēt visus</CheckBox>
</MenuItem.Header>
<MenuItem.Icon>
<Image
RenderOptions.BitmapScalingMode="NearestNeighbor"
RenderOptions.EdgeMode="Aliased"
Source="/Furniture;component/Resources/search4.png"
/>
</MenuItem.Icon>
</MenuItem>
<Separator />
<MenuItem>
<MenuItem.Header>
<RadioButton GroupName="Sorting" Content="Augoša secībā" IsChecked="True"/>
</MenuItem.Header>
</MenuItem>
<MenuItem>
<MenuItem.Header>
<RadioButton GroupName="Sorting" Content="Dilstoša secībā" IsChecked="True"/>
</MenuItem.Header>
</MenuItem>
</ContextMenu>