如何访问GroupItem中的控件?

时间:2018-01-06 14:08:50

标签: c# wpf

我使用CollectionView将项目分组如下:

<CollectionViewSource Source="{Binding Competitions}" x:Key="GroupedData">
      <CollectionViewSource.GroupDescriptions>
            <PropertyGroupDescription PropertyName="Item.Country" />
       </CollectionViewSource.GroupDescriptions>
</CollectionViewSource>

完整的XAML结构是这样的:

<ComboBox x:Name="CompetitionCombo"
          ItemsSource="{Binding Source={StaticResource GroupedData}}"
          ItemTemplate="{StaticResource CombinedTemplate}">
           <ComboBox.GroupStyle>
            <GroupStyle ContainerStyle="{StaticResource containerStyle}"
                        HeaderTemplate="{StaticResource GroupHeader}">
            </GroupStyle>
</ComboBox.GroupStyle>

<DataTemplate x:Key="CombinedTemplate">
        <ContentPresenter x:Name="Presenter" 
                          Content="{Binding}"
                          ContentTemplate="{StaticResource NormalItemTemplate}" />
</DataTemplate>

 <DataTemplate x:Key="GroupHeader">
            <DockPanel>
                <Image Source="{Binding Name.ISO, 
                       Converter={StaticResource CountryIdToFlagImageSourceConverter}}"
                       Stretch="None" Width="23" Height="18" RenderOptions.BitmapScalingMode="HighQuality" />
                <TextBlock Text="{Binding Name.Name}" Margin="10,0,0,0" Foreground="Black" FontWeight="Bold"/>
                <CheckBox Margin="5,0,0,0" HorizontalAlignment="Right" IsChecked="True" x:Name="PART_DisplayLeague" 
                          Unchecked="CheckBoxCountry_Unchecked" Checked="CheckBoxCountry_Checked" />
            </DockPanel>
        </DataTemplate>

        <Style TargetType="{x:Type GroupItem}" x:Key="containerStyle">
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="{x:Type GroupItem}">
                        <Expander IsExpanded="False" x:Name="ComboExpander" 
                                  Header="{TemplateBinding Content}"
                                  HeaderTemplate="{StaticResource GroupHeader}" >
                            <ItemsPresenter />
                        </Expander>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>

正如您在GroupHeaderCheckBox中看到的那样,我试图通过以下方式访问此CheckBox

//current value of league.Country = "England";

//Iterate the available groups
foreach(CollectionViewGroup gp in CompetitionCombo.Items.Groups)
{ 
  if(league.Country.Name == (gp.Name as Country).Name)
  {
       //Get the container
       GroupItem container = CompetitionCombo.ItemContainerGenerator.ContainerFromItem(gp) as GroupItem;

      //Get the control
      var control = container.Template.FindName("PART_DisplayLeague", container);

      control.IsChecked = true;
  }
}

我的组正确,但control变量甚至是Null,似乎代码找不到PART_DisplayLeague:与标题中的Country关联的CheckBox容器。

注意:

league是以下内容的简单实现:

public class League
{
    public string Name { get; set; }
    public Country Country { get; set; }
}

public class Country
{
   public string Name { get; set; } 
   public string ISO { get; set; } 
}

我做错了什么?

更新

忘记添加集合实现,特别是Competition

public List<CheckedListItem<League>> Competitions = new List<CheckedListItem<League>>();

用于向集合中添加元素:

Competitions.Add(new CheckedListItem<League>
{
    IsChecked = true,
    Item = new League { Name = "foo" } 
});

可以找到CheckedListItem here

的实现

您可以看到ItemCheckedListItem的一部分。

更新#2

情况的实践例子:

假设Competitions包含以下项目:

Competitions.Add(new CheckedListItem<League>
{
    IsChecked = true,
    Item = new League { Name = "foo", Country = new Country { Name = "Italy"}} 
});

Competitions.Add(new CheckedListItem<League>
{
    IsChecked = true,
    Item = new League { Name = "foo2", Country = new Country { Name = "Italy"}} 

});

Competitions.Add(new CheckedListItem<League>
{
    IsChecked = true,
    Item = new League { Name = "foo", Country = new Country { Name = "England"}} 
});

UI结构将:

[] Italy     <- this is the GroupHeader sort by xaml
    [] foo   <- Items of the container
    [] foo2  
[] England
    [] foo3

现在我要求的是:当我检查foo2和foo时,Italy CheckBox需要被检查,当我取消选中Italy容器中包含的Item时,那么,{ {1}}必须取消选中。

这意味着两件事:

  1. 如果检查了容器中的所有项目,则还需要检查标题复选框。
  2. 如果未检查容器中的近一个项目,则必须取消选中容器中的复选框,因为这意味着不会检查与该国家/地区关联的所有项目。
  3. 我的问题是我无法找到与国家/地区相关联的CheckBox是由Xaml生成的,这就是我无法使用Binding属性的原因如建议的那样。

1 个答案:

答案 0 :(得分:2)

发布有人可以复制粘贴并重现问题的代码,然后人们不仅可以解决您的问题,还可以提出更好的解决方案。

在此期间,您可以通过以下方式找到您的复选框:

var control = FindVisualChildren<CheckBox>(container);

Here you can find the method FindVisualChildren

编辑:一个完整​​的工作示例

public class League
{
    public string Name { get; set; }
    public Country Country { get; set; }
}

public class Country
{
    public string Name { get; set; }
    public string ISO { get; set; }
}
public class CheckedListItem<T> 
{
    private bool isChecked;
    private T item;

    public CheckedListItem() { }

    public CheckedListItem(T item, bool isChecked = false)
    {
        this.item = item;
        this.isChecked = isChecked;
    }

    public T Item
    {
        get { return item; }
        set
        {
            item = value;

        }
    }

    public bool IsChecked
    {
        get { return isChecked; }
        set
        {
            isChecked = value;

        }
    }
}
 public partial class MainWindow : Window 
{
    public ObservableCollection<CheckedListItem<League>> Competitions { get; set; }
    public MainWindow()
    {
        InitializeComponent();


        Competitions = new ObservableCollection<CheckedListItem<League>> { (new CheckedListItem<League>
        {
            IsChecked = true,
            Item = new League { Name = "foo", Country = new Country { Name = "Italy" } }
        }),
        (new CheckedListItem<League>
        {
            IsChecked = true,
            Item = new League { Name = "foo2", Country = new Country { Name = "Italy" } }

        }),
        (new CheckedListItem<League>
        {
            IsChecked = true,
            Item = new League { Name = "foo", Country = new Country { Name = "England" } }
        }) };

        this.DataContext = this;
    }

    public void CheckBoxCountry_Checked(object sender, EventArgs args)
    {
        foreach (CollectionViewGroup gp in CompetitionCombo.Items.Groups)
        {

                //Get the container
                GroupItem container = CompetitionCombo.ItemContainerGenerator.ContainerFromItem(gp) as GroupItem;

            //Get the control
            var control = FindVisualChildren<CheckBox>(container);



        }
    }

    public IEnumerable<T> FindVisualChildren<T>(DependencyObject depObj) where T : DependencyObject
    {
        if (depObj != null)
        {
            for (int i = 0; i < VisualTreeHelper.GetChildrenCount(depObj); i++)
            {
                DependencyObject child = VisualTreeHelper.GetChild(depObj, i);

                if (child != null && child is T)
                    yield return (T)child;

                foreach (T childOfChild in FindVisualChildren<T>(child))
                    yield return childOfChild;
            }
        }
    }
}

的.xaml

<Window x:Class="WpfApp2.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:WpfApp2"
        mc:Ignorable="d"
        Title="MainWindow" Height="350" Width="525">
    <Grid>
        <Grid.Resources>
            <CollectionViewSource Source="{Binding Competitions}" x:Key="GroupedData">
                <CollectionViewSource.GroupDescriptions>
                    <PropertyGroupDescription PropertyName="Item.Country" />
                </CollectionViewSource.GroupDescriptions>
            </CollectionViewSource>

            <DataTemplate x:Key="NormalItemTemplate">
                <DockPanel>
                    <TextBlock Text="sdf" Margin="10,0,0,0" Foreground="Black" FontWeight="Bold"/>
                </DockPanel>
            </DataTemplate>
            <DataTemplate x:Key="CombinedTemplate">
                <ContentPresenter x:Name="Presenter" 
                          Content="{Binding}"
                                   ContentTemplate="{StaticResource NormalItemTemplate}"
                           />
            </DataTemplate>
            <DataTemplate x:Key="GroupHeader">
                <DockPanel>


                    <TextBlock Text="{Binding Name.Name}" Margin="10,0,0,0" Foreground="Black" FontWeight="Bold"/>
                    <CheckBox Margin="5,0,0,0" HorizontalAlignment="Right" IsChecked="True" x:Name="PART_DisplayLeague" 
                           Checked="CheckBoxCountry_Checked" />
                </DockPanel>
            </DataTemplate>

            <Style TargetType="{x:Type GroupItem}" x:Key="containerStyle">
                <Setter Property="Template">
                    <Setter.Value>
                        <ControlTemplate TargetType="{x:Type GroupItem}">
                            <Expander IsExpanded="False" x:Name="ComboExpander" 
                                  Header="{TemplateBinding Content}"
                                  HeaderTemplate="{StaticResource GroupHeader}" >
                                <ItemsPresenter />
                            </Expander>
                        </ControlTemplate>
                    </Setter.Value>
                </Setter>
            </Style>
        </Grid.Resources>
        <ComboBox x:Name="CompetitionCombo"
          ItemsSource="{Binding Source={StaticResource GroupedData}}"
          ItemTemplate="{StaticResource CombinedTemplate}">
            <ComboBox.GroupStyle>
                <GroupStyle ContainerStyle="{StaticResource containerStyle}"
                        HeaderTemplate="{StaticResource GroupHeader}">
                </GroupStyle>
            </ComboBox.GroupStyle>
        </ComboBox>
    </Grid>
</Window>

我添加了NormalItemTemplate,因为您没有提供模板。

当您选中UI中的复选框时,您将在mainwindow.cs中调用CheckBoxCountry_Checked方法,该方法将在所有3个组合框中找到该复选框。