在使用ContextMenu.ItemTemplate动态创建的ContextMenu中查找和取消选中所有MenuIte
本文关键字:ContextMenu 取消 MenuIte 查找 ItemTemplate 动态 创建 | 更新日期: 2023-09-27 18:21:36
我在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"被选中时,我如何找到并取消选中所有菜单项。
在代码隐藏中,我使用了一个get祖先函数,该函数将我带到ContextMenu,但所有项目都只列为字符串,因此我无法设置MenuItem.IsChecked=false;
所以当我试图在codebehind中找到所有要取消选中的菜单项时,我得到了异常。
这是代码:
var filterItem = (sender as MenuItem);
var parent = filterItem.FindAncestorTest<TextBlock>();
foreach (var menuitem in parent.Items)
{
(mi as MenuItem).IsChecked = false;
}
首先,我建议您避免混合使用MVVM和代码隐藏。你应该选择其中一个,并在项目的每一部分使用它。
就我个人而言,我更喜欢MVVM,所以我的解决方案符合MVVM。直到现在我还不知道你写的所有代码,所以我的答案基于一个简化的例子。
我刚刚为您称之为"过滤器"的对象创建了一个模型(每个过滤器都由一个菜单项表示):
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
是仅实现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元素。为了获得我想要的所有复选框元素,我在这篇文章中包含了Extetion函数:如何按名称或类型找到WPF控件?。使用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;
}
}