【问题标题】:WPF: how to recreate ItemContainer?WPF:如何重新创建 ItemContainer?
【发布时间】:2017-11-16 07:27:05
【问题描述】:

在我之前的问题How to change ComboBox item visibility 之后,由于问题略有改变,我决定开一个新帖子来解决它。对于那些不想阅读上一篇文章中所有 cmets 的人,这里是情况。

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

现在,据我所知,WPF 以这种方式工作:如果视图包含组合框或树视图之类的控件,那么它们的项目(即 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 个 Item (x,y,a,b) 的集合。如果在 ComboBox1 中选择了 x,则在 ComboBox1 的 SelectedItem 更改(例如从 x 到 y)之前,无法在 2 个 ComboBox 中选择 x。现在我什至可以接受这样一个事实,即下拉菜单中的项目只是被禁用,如果它使事情变得更容易,我只需要这样一个事实,即如果他已经被选中,它就不能再次被选中。

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

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

【问题讨论】:

  • 让我们忘记DataGrid 和所有其他问题的噪音......我建议您创建一个MCVE,其中包含3 个组合框和组合框项目源中的4 个项目。我有一些解决问题的想法,但我没有时间自己创建 MCVE,我需要一个来测试我的解决方案;)
  • 我找到了解决方案。我发布了它,但如果我能找到更好的方法来做到这一点,我会很好。不幸的是,我现在在工作,没有时间创建 MCVE
  • Selezionato 是否与INotifyPropertyChanged 正确实现?如果没有,您可以先更改此方面,而不是创建 MCVE。我不着急,所以除非你很着急,否则请慢慢来 MCVE ;)
  • @grek40 我刚刚发现我实现了事件,但没有实现 INotifyPropertyChanged 类。我觉得自己很笨
  • 嗯,这是有道理的......如果值实际上没有改变,你的c.Items.Refresh() 将不起作用,因为它起作用了,唯一缺少的是自动更新的更改通知,而不是显式刷新。

标签: wpf combobox itemcontainerstyle itemcontainergenerator


【解决方案1】:

在互联网上进行了一次幸运的研究(即我找到了正确的关键字组合),我发现了这个绝妙的方法,所以这里是更新的解决方案:

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

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-10-23
    • 2013-06-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多