WPF:如何重新创建ItemContainer?

时间:2017-06-14 08:44:21

标签: wpf combobox itemcontainerstyle itemcontainergenerator

按照我之前的问题How to change ComboBox item visibility,由于问题略有改变,我决定开一个新帖来解决问题。对于那些不想阅读上一篇文章中所有评论的人,情况就是这样。

我有一个在运行时生成的DataGrid。此数据网格的每一列在标题内都有一个组合框。所有这些组合框都具有相同的Source,即可观察的类项集合。每个项目都显示我在组合框的ItemContainerStyle中使用的属性,以确定每个ComBoBoxItem是否应该是可见的。

现在,据我所知,WPF以这种方式工作:如果一个视图包含像combobox或treeview这样的控件,那么它们的项目(即ComboBoxItem,TreeViewItem ...)将不会被生成,直到它没有必要(对于例如,组合框的下拉打开时)。如果我应用ItemContainerStyle,这将告诉目标应该如何创建其项目。问题是,在生成此项目的那一刻,我需要应用于样式的每个更改都不会被保存。

这是我的代码:

    <DataGrid HeadersVisibility="Column" Name="griglia" Grid.Row="2" ItemsSource="{Binding Path=Test}" AutoGenerateColumns="True" IsReadOnly="True" ScrollViewer.CanContentScroll="True" ScrollViewer.VerticalScrollBarVisibility="Visible" ScrollViewer.HorizontalScrollBarVisibility="Visible">
        <DataGrid.ColumnHeaderStyle>
            <Style TargetType="{x:Type DataGridColumnHeader}">
                <Setter Property="ContentTemplate" >
                    <Setter.Value>
                        <DataTemplate DataType="DataGridColumnHeader"  >
                            <ComboBox ItemContainerStyle="{StaticResource SingleSelectionComboBoxItem}" DisplayMemberPath="Oggetto" Width="100" Height="20" ItemsSource="{Binding RelativeSource={RelativeSource AncestorType={x:Type DataGrid}},Path=DataContext.Selezione, UpdateSourceTrigger=LostFocus}"  SelectionChanged="SingleSelectionComboBox_SelectionChanged">
                            </ComboBox>
                        </DataTemplate>
                    </Setter.Value>
                </Setter>
            </Style>
        </DataGrid.ColumnHeaderStyle>
    </DataGrid>

ItemContainerStyle:

     <Style x:Key="SingleSelectionComboBoxItem" TargetType="ComboBoxItem" BasedOn="{StaticResource {x:Type ComboBoxItem}}">
        <Style.Triggers>
            <DataTrigger Binding="{Binding Selezionato}" Value="True">
                <!-- Hide it -->
                <Setter Property="Visibility" Value="Collapsed" />
                <!-- Also prevent user from selecting it via arrows or mousewheel -->
                <Setter Property="IsEnabled" Value="False" />
            </DataTrigger>
        </Style.Triggers>
    </Style>

的SelectionChanged:

private void SingleSelectionComboBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
    {
        foreach (var item in e.RemovedItems.OfType<PopolazioneCombo>())
        {
            item.Selezionato = false;
        }

        foreach (var item in e.AddedItems.OfType<PopolazioneCombo>())
        {
            item.Selezionato = true;
        }
    }

我的要求是,如果在任何N个组合框中选择了一个项目,那么任何人都无法选择该项目,直到他失去了SelectedItem状态。例如,假设我有2个组合框和4个项目(x,y,a,b)的集合。如果在ComboBox1中选择了x,则在ComboBox1的SelectedItem发生更改(例如从x到y)之前,不能在2个ComboBox中选择x。现在我甚至可以接受下拉菜单中的项目只是禁用它的事实,如果它使事情变得更容易,我只需要这样一个事实,即如果他已被选中则无法再次选择。

问题是此解决方案适用于每个具有ItemContainerGenerator.Status = NotStarted的ComboBox(这意味着仍未创建ComboBoxItem)。如果我打开组合框的下拉列表,那么它的ComboBox项目将保留它们的样式,无论我做什么(导致ItemContainerGenerator.Status = ContainersGenerated),而我没有打开的组合框记录了可见性的变化。项目。

我正在寻找重新创建这些项目的解决方案,以便应用可见性更改的新样式

1 个答案:

答案 0 :(得分:0)

经过对互联网的幸运研究(即我找到了正确的关键词组合)后,我找到了这个很棒的方法,所以这里有更新的解决方案:

private void ComboBox_DropDownOpened(object sender, EventArgs e)
    {
        ComboBox c = sender as ComboBox;
        c.Items.Refresh();
    }

在xaml中添加此事件,使其成为:

<ComboBox DropDownOpened="ComboBox_DropDownOpened" ItemContainerStyle="{StaticResource SingleSelectionComboBoxItem}" DisplayMemberPath="Oggetto" Width="100" Height="20" ItemsSource="{Binding RelativeSource={RelativeSource AncestorType={x:Type DataGrid}},Path=DataContext.Selezione, UpdateSourceTrigger=LostFocus}"  SelectionChanged="SingleSelectionComboBox_SelectionChanged"/>

神奇的是,组合框显示了正确的变化。现在我不是背后代码的忠实粉丝,所以如果有办法在我的Collection中添加属性,或者通过xaml它会更好