0

I have a ContextMenu inside DataGridTemplateColumn, the menuitems are all the production countries for the view. I am using this to filter away countries.

Here is code:

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

To remove all filtering I have a listing that sais "Show all".

The menuitems are checkable and here is my question: How can I find and uncheck all menuitems when the menuitem "Show all" is checked.

In code behind I use an getancestor function that gets me to the ContextMenu but all the items are only listed as strings so I can't set the MenuItem.IsChecked = false;

So when I try to find all menuitems for unchecking in codebehind i get exception.

Here is code:

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

2 Answers2

0

First of all I would like to suggest you to avoid using a mix of MVVM and code-behind. You should choose one of them and use it in every part of your project.

Personally I prefer MVVM, so my solution is MVVM compliant. I do not know all the code that you wrote until now, so I base my answer on a simplified example.

I just created a model for the object that you call "filter" (each filter is represented by a single menu item):

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");
            }
        }
    }
}

where NotifyPropertyChangedBase is a base class which just implements INotifyPropertyChanged.

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

Let's suppose that FilterProdCountry is a collection of Filter objects, which belongs to your ViewModel. So... do you want to uncheck a MenuItem? Well, just retrive the related Filter object and then set its IsSelected property to false; for example:

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

where vm is the instance of your ViewModel.

I hope my answer can give you an hint about the way you go for your project.

Il Vic
  • 5,576
  • 4
  • 26
  • 37
  • Thank you very much for taking the time to answer my question. Reason for a mix of the two is a combination of the customers complex demands for the views and that im fairly new to wpf. I found a solution doing it the way I had allready start on that i will post as answer when I find the time. But for future projects I think I might be doing this your way :) – Stian Kristiansen Nov 13 '15 at 13:23
0

So first of all I would like to point out an error in my Xaml where i put MenuItem inside ContextMenu.ItemTemplate which gave me two MenuItem elements. And to get all the checkbox elements that i wanted I included the Extention functions found in this post: How can I find WPF controls by name or type?. And use the FindAllChildren function like this:

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;
  }  
}
Community
  • 1
  • 1