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

时间:2015-11-12 14:06:58

标签: c# wpf datagrid contextmenu menuitem

我在DataGridTemplateColumn中有一个ContextMenu,menuitems是视图的所有生产国家。我用它来过滤掉国家。

这是代码:

<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>

要删除所有过滤,我有一个名为“全部显示”的商家信息。

菜单项是可检查的,这是我的问题:当菜单项“全部显示”被选中时,如何查找和取消选中所有菜单项。

在后面的代码中,我使用getancestor函数将我带到ContextMenu,但所有项目仅列为字符串,因此我无法设置MenuItem.IsChecked = false;

因此,当我尝试在代码隐藏中找到所有菜单项以取消选中时,我得到了异常。

这是代码:

 var filterItem = (sender as MenuItem);
 var parent = filterItem.FindAncestorTest<TextBlock>();
 foreach (var menuitem in parent.Items) 
        {
            (mi as MenuItem).IsChecked = false;
        }

2 个答案:

答案 0 :(得分:0)

首先,我想建议你避免使用混合的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>

我们假设FilterProdCountryFilter个对象的集合,属于您的ViewModel。那么......你想取消选中一个MenuItem吗?好吧,只需检索相关的Filter对象,然后将其IsSelected属性设置为false;例如:

if (vm.FilterProdCountry[0].IsSelected)
{
    foreach (Filter filter in vm.FilterProdCountry.Skip(1))
    {
        filter.IsSelected = false;
    }
}

其中vm是ViewModel的实例。

我希望我的回答可以为你提供一个关于你的项目方式的提示。

答案 1 :(得分:0)

首先,我想在我的Xaml中指出一个错误,我将MenuItem放在ContextMenu.ItemTemplate中,它给了我两个MenuItem元素。为了获得我想要的所有复选框元素,我在此帖子中包含了Extention函数: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;
  }  
}