在使用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;
        }

在使用ContextMenu.ItemTemplate动态创建的ContextMenu中查找和取消选中所有MenuIte

首先,我建议您避免混合使用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;
  }  
}