WPF: How to change the visibility of my ComboBox I

2019-09-14 19:17发布

I know that this topic is already answered, but i couldn't solve the problem with the solution that i found. So here is my code:

<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 SelectedValue="{Binding Selezione}" SelectedValuePath="Selezionato" Width="100" Height="20" ItemsSource="{Binding RelativeSource={RelativeSource AncestorType={x:Type DataGrid}},Path=DataContext.Selezione}"  SelectionChanged="Test_SelectionChanged">
                                <ComboBox.ItemTemplate>
                                    <DataTemplate >
                                        <TextBlock Text="{Binding Path=Oggetto}"/>
                                    </DataTemplate>
                                </ComboBox.ItemTemplate>
                            </ComboBox>
                        </DataTemplate>
                    </Setter.Value>
                </Setter>
            </Style>
        </DataGrid.ColumnHeaderStyle>
    </DataGrid>

In few words, i have a custom datagrid which is bound to a datatable. The header of each column, is a combobox, whose source is an observable collection of this class:

public class PopolazioneCombo 
{
    public string Oggetto { get; set; }
    private bool selezionato = false;
    public event PropertyChangedEventHandler PropertyChanged;
    protected void OnPropertyChanged(string propName)
    {
        var handler = PropertyChanged;
        if (handler != null)
        {
            handler(this, new PropertyChangedEventArgs(propName));
        }
    }
    public bool Selezionato
    {
        get { return !selezionato; }
        set
        {
            if(selezionato != value)
            {
                selezionato = value;
                OnPropertyChanged("Selezionato");
            }
        }
    }
}

My problem is the following: I need to switch the visibility of each selected item to collapsed in all the comboboxes (since they share the same source). I tried to create a custom SelectionChanged event in which i change the "Selezionato" value and i bound the visibility of the textblock like this:

<TextBlock Text="{Binding Path=Oggetto}" Visibility="{Binding Path=Selezionato, Converter={StaticResource BoolToVis}, UpdateSourceTrigger=PropertyChanged}"/>

The problem with this is that, not only it make my SelectedItem not visible in the combobox, but also the ComoBoxItem are not synchronized, so it's not working at all as intended.

EDIT: this is the collection

 public ObservableCollection<PopolazioneCombo> Selezione
    {
        get
        {
            return selezione;
        }
        set
        {
            if (selezione != value)
            {
                selezione = value;
                OnPropertyChanged("Selezione");
            }
        }
    }

EDIT 2: My requirement is that, if in any of the N combobox an item is selected, then, that item cannot be selected by anyone, until he lose the SelectedItem status. For instance let's assume i have 2 combobox and a collection of 4 Item (x,y,a,b) . If x is selected in ComboBox1, then x can't be selected in none of the 2 ComboBox until the SelectedItem of the ComboBox1 change (from x to y for instance). Now i can even accept the fact that the item in the dropdown is just disabled if it makes the things easier, i just need the fact that it cannot be selected again if he is already selected

1条回答
一纸荒年 Trace。
2楼-- · 2019-09-14 19:30

The requirements:

  1. Multiple combo boxes all display the same set of options.
  2. If an item is selected in a combo box, it may not be selected in any other combo box.

We'll do the hiding and disabling with triggers in an ItemContainerStyle on the comboboxes, driven by the bool Selezionato property of the combo box items. We'd prefer to set Selezionato with a Binding in the style as well, but I found that it was deselecting items at times when I didn't want it to, so I did it in a ComboBox.SelectionChanged handler instead.

<Style 
    x:Key="SingleSelectionComboBoxItem" 
    TargetType="ComboBoxItem" 
    BasedOn="{StaticResource {x:Type ComboBoxItem}}"
    >
    <!-- This unselects sometimes when you don't want it to. -->
    <!--
    <Setter Property="IsSelected" Value="{Binding Selezionato, Mode=OneWayToSource}" />
    -->
    <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>

ComboBoxes. I'm leaving out some of the properties you had. What matters for my addition to your code is ItemContainerStyle and SelectionChanged:

<ComboBox
    ItemsSource="{Binding RelativeSource={RelativeSource AncestorType={x:Type DataGrid}}, Path=DataContext.Selezione}" 
    DisplayMemberPath="Oggetto"
    ItemContainerStyle="{StaticResource SingleSelectionComboBoxItem}"
    SelectionChanged="SingleSelectionComboBox_SelectionChanged"
    />

Code behind:

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

Another thing I noticed along the way:

You had the PopolazioneCombo.Selezionato getter returning !selezionato -- probably a typo, but if not, a bad idea!

public bool Selezionato
{
    get { return selezionato; }
    set
    {
        if (selezionato != value)
        {
            selezionato = value;
            OnPropertyChanged("Selezionato");
        }
    }
}
查看更多
登录 后发表回答