Damgot
Damgot

Reputation: 428

WPF Hide an Item of a Combobox ItemSource

In my WPF View, I have a DataGrid which Display Data from a Database. One column is a combobox that is bound to a string in Database.

This is the list of available string :

public List<string> AvailableTypeImpression { get; } = new List<string>() {"S","D","T","X","M","p","P","R"}

All these string could be displayed in the datagrid, but if the user want to edit it, I can only set S, D, T, or X. The user is not allowed to set M, p, P or R.

So I would like to hide these four letter from the combobox available Items. But I don't really know how to do that in a simple way (I found some solution on Stack Overflow but it doesn't work in my case).

Here's the code of my datagrid :

<DataGrid Grid.Row="1" x:Name="LotsListDataGrid" IsReadOnly="False" SelectionMode="Single" SelectionUnit="FullRow" SelectedItem="{Binding SelectedLot}" ItemsSource="{Binding FilteredList}"  VirtualizingPanel.IsVirtualizing="True" EnableRowVirtualization="True" HorizontalScrollBarVisibility="Auto">
    <DataGrid.Columns>
        <DataGridTextColumn Header="Lot" Width="200" Binding="{Binding Value.Lot.Intitule}" IsReadOnly="True"/>

        <DataGridTemplateColumn Header=".i." HeaderStyle="{StaticResource CenteredColumnHeaderStyle}" Width="545" IsReadOnly="False">
            <DataGridTemplateColumn.CellTemplate>
                <DataTemplate>
                    <ComboBox Height="23" Style="{StaticResource AnfComboBoxStyle}" ItemsSource="{Binding DataContext.AvailableTypeImpression, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type DataGrid}}}" SelectedItem="{Binding Value.Lot.TypeImpression, UpdateSourceTrigger=PropertyChanged}">
                </DataTemplate>
            </DataGridTemplateColumn.CellTemplate>
        </DataGridTemplateColumn>
    </DataGrid.Columns>
</DataGrid>

FilteredList.Value.Lot.TypeImpression is a string.

If I've well understood, all the possible string must be in the ItemSource otherwise they could'nt be displayed. But I need to find a way to prevent user to select some of them.

Thanks for your help.

Upvotes: 1

Views: 455

Answers (2)

Damgot
Damgot

Reputation: 428

The solution from @dheller was good but not working in my case because the user is not able to give to "Value.Lot.TypeImpression" a new Value M ,p, P or R, but he's able to edit "Value.Lot.TypeImpression" even if it equals to M ,p, P or R and set S, D, T, or X.

So I've found another way :

In my ViewModel I've defined a new class :

public class TypeImpressionAvailable
{
    public string Name { get; set; }
    public bool IsAvailable { get; set; }
}

And my list to give to my combobox as ItemSource :

public List<TypeImpressionAvailable> AvailableTypeImpression { get; } = new   List<TypeImpressionAvailable>() {
new TypeImpressionAvailable(){ Name="N", IsAvailable=true },
new TypeImpressionAvailable(){ Name="S", IsAvailable=true },
new TypeImpressionAvailable(){ Name="D", IsAvailable=true },
new TypeImpressionAvailable(){ Name="T", IsAvailable=true },
new TypeImpressionAvailable(){ Name="X", IsAvailable=true },
new TypeImpressionAvailable(){ Name="M", IsAvailable=false },
new TypeImpressionAvailable(){ Name="p", IsAvailable=false },
new TypeImpressionAvailable(){ Name="P", IsAvailable=false },
new TypeImpressionAvailable(){ Name="R", IsAvailable=false }
};

And in my View :

<DataGridTemplateColumn Header=".i." HeaderStyle="{StaticResource CenteredColumnHeaderStyle}" Width="45" IsReadOnly="False">
    <DataGridTemplateColumn.CellTemplate>
        <DataTemplate>
            <ComboBox Height="23" SelectedValuePath="Name" DisplayMemberPath="Name" 
                      SelectedValue="{Binding Value.Lot.TypeImpression, UpdateSourceTrigger=PropertyChanged}" 
                      >
                <ComboBox.Style>
                    <Style TargetType="{x:Type ComboBox}" BasedOn="{StaticResource AnfComboBoxStyle}">
                        <Setter Property="ItemsSource" Value="{Binding DataContext.AvailableTypeImpression, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type DataGrid}}}"/>
                        <Setter Property="ItemContainerStyle">
                            <Setter.Value>
                                <Style TargetType="ComboBoxItem" BasedOn="{StaticResource {x:Type ComboBoxItem}}">
                                    <Style.Triggers>
                                        <DataTrigger Binding="{Binding IsAvailable}" Value="False">
                                            <Setter Property="Visibility" Value="Collapsed" />
                                        </DataTrigger>
                                    </Style.Triggers>
                                </Style>
                            </Setter.Value>
                        </Setter>
                    </Style>
                </ComboBox.Style>
            </ComboBox>
        </DataTemplate>
    </DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>

And it works fine :)

enter image description here

Upvotes: 1

dheller
dheller

Reputation: 11

I don't know of a way to make individual items non-selectable in a combo box. But you could always show a combo box without your not-allowed letters (i.e. remove them from AvailableTypeImpression), and instead show just a simple TextBlock in your cell in case one of these letters is read from the DB.

Change your cell template to something like this:

<DataGridTemplateColumn.CellTemplate>
    <DataTemplate>
        <Grid>
            <ComboBox Visbility="{Binding IsValueEditable}" Height="23" Style="{StaticResource AnfComboBoxStyle}" ItemsSource="{Binding DataContext.AvailableTypeImpression, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type DataGrid}}}" SelectedItem="{Binding Value.Lot.TypeImpression, UpdateSourceTrigger=PropertyChanged}" />
            <TextBlock Visbility="{Binding NotIsValueEditable}" Height="23" Text="{Binding Value.Lot.TypeImpression}" />
        </Grid>
    </DataTemplate>
</DataGridTemplateColumn.CellTemplate>

Then implement IsValueEditable, NotIsValueEditable properties in your ViewModel such that only one of the controls is shown.

Alternatively, if you also want to be able to modify existing entries of M, p, P, R, you could use a DataGridTemplateColumn.CellEditingTemplate: Make the CellEditingTemplate show the ComboBox (without M, p, P, R options) while the regular CellTemplate only contains a TextBlock.

<DataGridTemplateColumn.CellTemplate>
    <DataTemplate>
        <TextBlock Height="23" Text="{Binding Value.Lot.TypeImpression}" />
    </DataTemplate>
</DataGridTemplateColumn.CellTemplate>

<DataGridTemplateColumn.CellEditingTemplate>
    <DataTemplate>
        <ComboBox Height="23" Style="{StaticResource AnfComboBoxStyle}" ItemsSource="{Binding DataContext.AvailableTypeImpression, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type DataGrid}}}" SelectedItem="{Binding Value.Lot.TypeImpression, UpdateSourceTrigger=PropertyChanged}" />
    </DataTemplate>
</DataGridTemplateColumn.CellEditingTemplate>

Upvotes: 0

Related Questions