在使用 ContextMenu.ItemTemplate 动态创建的 ContextMenu 中查找并取消选中所有 MenuItem
Finding and unchecking all MenuItems in ContextMenu created dynamically with ContextMenu.ItemTemplate
我在 DataGridTemplateColumn 中有一个 ContextMenu,菜单项是视图的所有生产国家/地区。我正在使用它来过滤掉国家。
代码如下:
<DataGridTemplateColumn SortMemberPath="ProductionCountry" x:Name="prodCountryColumn" Width="Auto" CanUserSort="True">
<DataGridTemplateColumn.Header>
<TextBlock HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
<TextBlock.ContextMenu x:Name="cmProdCountry" >
<ContextMenu Loaded="ContextMenu_Loaded" ItemsSource="{Binding Path=FilterProdCountry}">
<ContextMenu.ItemTemplate>
<DataTemplate>
<MenuItem Name="prodCountryFilter" IsCheckable="True" Checked="toggleFilterOn" Unchecked="toggleFilterOff" Header="{Binding}" ItemsSource="{Binding}">
</MenuItem>
</DataTemplate>
</ContextMenu.ItemTemplate>
</ContextMenu>
</TextBlock.ContextMenu>
Produksjonsland
</TextBlock>
</DataGridTemplateColumn.Header>
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock Padding="5,1,5,1" Text="{Binding Path=ProductionCountry}"/>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
要删除所有过滤,我有一个列表 "Show all"。
菜单项是可检查的,这是我的问题:当菜单项 "Show all" 被选中时,如何找到并取消选中所有菜单项。
在后面的代码中,我使用 getancestor 函数将我带到上下文菜单,但所有项目仅作为字符串列出,因此我无法设置 MenuItem.IsChecked = false;
因此,当我尝试在代码隐藏中查找所有要取消选中的菜单项时,出现异常。
代码如下:
var filterItem = (sender as MenuItem);
var parent = filterItem.FindAncestorTest<TextBlock>();
foreach (var menuitem in parent.Items)
{
(mi as MenuItem).IsChecked = false;
}
首先,我建议您避免混合使用 MVVM 和代码隐藏。您应该选择其中之一并将其用于项目的每个部分。
我个人更喜欢 MVVM,所以我的解决方案是 MVVM 兼容的。我不知道你到目前为止写的所有代码,所以我的回答基于一个简化的例子。
我刚刚为您称为 "filter" 的对象创建了一个模型(每个过滤器都由一个菜单项表示):
public class Filter : NotifyPropertyChangedBase
{
private bool isSelected;
private string description;
public Filter(string description)
{
this.description = description;
}
public string Description
{
get
{
return description;
}
set
{
if (StringComparer.Ordinal.Compare(description, value) != 0)
{
description = value;
OnPropertyChanged("Description");
}
}
}
public bool IsSelected
{
get
{
return isSelected;
}
set
{
if (isSelected != value)
{
isSelected = value;
OnPropertyChanged("IsSelected");
}
}
}
}
其中 NotifyPropertyChangedBase
是一个基础 class,它只是实现了 INotifyPropertyChanged.
现在我的 XAML:
<TextBox Margin="5" HorizontalAlignment="Stretch">
<TextBox.ContextMenu>
<ContextMenu ItemsSource="{Binding Path=FilterProdCountry}">
<ContextMenu.ItemTemplate>
<DataTemplate>
<CheckBox Margin="4" HorizontalAlignment="Left"
VerticalAlignment="Center"
IsChecked="{Binding Path=IsSelected, Mode=TwoWay}"
Content="{Binding Path=Description, Mode=OneWay}" />
</DataTemplate>
</ContextMenu.ItemTemplate>
</ContextMenu>
</TextBox.ContextMenu>
</TextBox>
假设 FilterProdCountry
是属于您的 ViewModel 的 Filter
个对象的集合。那么...您要取消选中 MenuItem 吗?那么,只需检索相关的 Filter
对象,然后将其 IsSelected
属性 设置为 false;例如:
if (vm.FilterProdCountry[0].IsSelected)
{
foreach (Filter filter in vm.FilterProdCountry.Skip(1))
{
filter.IsSelected = false;
}
}
其中 vm
是您的 ViewModel 的实例。
我希望我的回答能给您一些提示,让您了解您的项目方式。
所以首先我想指出 Xaml 中的一个错误,我将 MenuItem 放在 ContextMenu.ItemTemplate 中,这给了我两个 MenuItem 元素。为了获得我想要的所有复选框元素,我包括了在 post: How can I find WPF controls by name or type? 中找到的扩展函数。
并像这样使用 FindAllChildren 函数:
private void toggleFilterOn(object sender, RoutedEventArgs e)
{
var filterItem = (sender as CheckBox);
var parent = filterItem.FindAncestorOfType<ContextMenu>();
var children = parent.FindAllChildren().Where(item => item is CheckBox);
foreach (CheckBox cb in children)
{
cb.IsChecked = false;
}
}
我在 DataGridTemplateColumn 中有一个 ContextMenu,菜单项是视图的所有生产国家/地区。我正在使用它来过滤掉国家。
代码如下:
<DataGridTemplateColumn SortMemberPath="ProductionCountry" x:Name="prodCountryColumn" Width="Auto" CanUserSort="True">
<DataGridTemplateColumn.Header>
<TextBlock HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
<TextBlock.ContextMenu x:Name="cmProdCountry" >
<ContextMenu Loaded="ContextMenu_Loaded" ItemsSource="{Binding Path=FilterProdCountry}">
<ContextMenu.ItemTemplate>
<DataTemplate>
<MenuItem Name="prodCountryFilter" IsCheckable="True" Checked="toggleFilterOn" Unchecked="toggleFilterOff" Header="{Binding}" ItemsSource="{Binding}">
</MenuItem>
</DataTemplate>
</ContextMenu.ItemTemplate>
</ContextMenu>
</TextBlock.ContextMenu>
Produksjonsland
</TextBlock>
</DataGridTemplateColumn.Header>
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock Padding="5,1,5,1" Text="{Binding Path=ProductionCountry}"/>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
要删除所有过滤,我有一个列表 "Show all"。
菜单项是可检查的,这是我的问题:当菜单项 "Show all" 被选中时,如何找到并取消选中所有菜单项。
在后面的代码中,我使用 getancestor 函数将我带到上下文菜单,但所有项目仅作为字符串列出,因此我无法设置 MenuItem.IsChecked = false;
因此,当我尝试在代码隐藏中查找所有要取消选中的菜单项时,出现异常。
代码如下:
var filterItem = (sender as MenuItem);
var parent = filterItem.FindAncestorTest<TextBlock>();
foreach (var menuitem in parent.Items)
{
(mi as MenuItem).IsChecked = false;
}
首先,我建议您避免混合使用 MVVM 和代码隐藏。您应该选择其中之一并将其用于项目的每个部分。
我个人更喜欢 MVVM,所以我的解决方案是 MVVM 兼容的。我不知道你到目前为止写的所有代码,所以我的回答基于一个简化的例子。
我刚刚为您称为 "filter" 的对象创建了一个模型(每个过滤器都由一个菜单项表示):
public class Filter : NotifyPropertyChangedBase
{
private bool isSelected;
private string description;
public Filter(string description)
{
this.description = description;
}
public string Description
{
get
{
return description;
}
set
{
if (StringComparer.Ordinal.Compare(description, value) != 0)
{
description = value;
OnPropertyChanged("Description");
}
}
}
public bool IsSelected
{
get
{
return isSelected;
}
set
{
if (isSelected != value)
{
isSelected = value;
OnPropertyChanged("IsSelected");
}
}
}
}
其中 NotifyPropertyChangedBase
是一个基础 class,它只是实现了 INotifyPropertyChanged.
现在我的 XAML:
<TextBox Margin="5" HorizontalAlignment="Stretch">
<TextBox.ContextMenu>
<ContextMenu ItemsSource="{Binding Path=FilterProdCountry}">
<ContextMenu.ItemTemplate>
<DataTemplate>
<CheckBox Margin="4" HorizontalAlignment="Left"
VerticalAlignment="Center"
IsChecked="{Binding Path=IsSelected, Mode=TwoWay}"
Content="{Binding Path=Description, Mode=OneWay}" />
</DataTemplate>
</ContextMenu.ItemTemplate>
</ContextMenu>
</TextBox.ContextMenu>
</TextBox>
假设 FilterProdCountry
是属于您的 ViewModel 的 Filter
个对象的集合。那么...您要取消选中 MenuItem 吗?那么,只需检索相关的 Filter
对象,然后将其 IsSelected
属性 设置为 false;例如:
if (vm.FilterProdCountry[0].IsSelected)
{
foreach (Filter filter in vm.FilterProdCountry.Skip(1))
{
filter.IsSelected = false;
}
}
其中 vm
是您的 ViewModel 的实例。
我希望我的回答能给您一些提示,让您了解您的项目方式。
所以首先我想指出 Xaml 中的一个错误,我将 MenuItem 放在 ContextMenu.ItemTemplate 中,这给了我两个 MenuItem 元素。为了获得我想要的所有复选框元素,我包括了在 post: How can I find WPF controls by name or type? 中找到的扩展函数。 并像这样使用 FindAllChildren 函数:
private void toggleFilterOn(object sender, RoutedEventArgs e)
{
var filterItem = (sender as CheckBox);
var parent = filterItem.FindAncestorOfType<ContextMenu>();
var children = parent.FindAllChildren().Where(item => item is CheckBox);
foreach (CheckBox cb in children)
{
cb.IsChecked = false;
}
}