How to define a style for a listbox depending upon the collection?

482 views Asked by At

I want to change a style of a listbox depending upon the collection I am using. In my code, the first class has a collection of TypeAItemViewModel. The collection will has 1 item that cannot be selected (assume as a header), and for that I will use IsHitTestVisible.

But the other class uses a collection of NormalParameters that has no IsHitTestVisible. Then, when I use a view with a NormalParameter collection it gives me an error with no IsHitTestVisible property.

public List<NormalParameters> Items{get;set;}
public List<TypeAItemViewModel> Items;

Class: TypeAItemViewModel

public class TypeAItemViewModel
{
    private TypeAParameter _parameter;      
    public bool IsHitTestVisible{get;set;}
}

style:

<Style x:Key="SelectableListBoxItem" TargetType="{x:Type ListBoxItem}">
    <Setter Property="IsHitTestVisible" Value="{Binding IsHitTestVisible}" />   
    <Style.Triggers>
        <DataTrigger Binding="{Binding IsHitTestVisible}" Value="false">
            <Setter Property="FontWeight" Value="SemiBold" />
            <Setter Property="FontSize" Value="{StaticResource FontSizeTextBlock}" />
        </DataTrigger>
    </Style.Triggers>
</Style>

Listbox: (work fines with collection of TypeAItemViewModel)

<ListBox HorizontalContentAlignment="Stretch" ItemsSource="{Binding Items}" SelectedItem="{Binding SelectedItem}" ItemContainerStyle="{DynamicResource SelectableListBoxItem}">
    <ListBox.ItemTemplate>                    
        <DataTemplate>
            <Grid Height="{StaticResource Height}">
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="*" />
                    <ColumnDefinition Width="100" />
                </Grid.ColumnDefinitions>
                <Grid Grid.Column="0">
                    <TextBlock DataContext="{Binding Name}" Text="{Binding Value}" HorizontalAlignment="Left" VerticalAlignment="Center"/>
                </Grid>
            </Grid>
        </DataTemplate>
    </ListBox.ItemTemplate>
</ListBox>

I thought it should to work with ItemContainerStyle but I still cannot solve it.

if unclear, please let me know.

edit: I have 2 collections. I want to display them different style with 1 xaml listbox. edit: Listbox that I use is a usercontrol

2

There are 2 answers

0
user3089631 On BEST ANSWER

@Valera thank you so much. your answer is a very healthy food for my problem.

I have added a new boolean property then use it to define which style I want to use.

<Style x:Key="ListBoxWithIsHitTestVisible" TargetType="{x:Type ListBox}">
    <Style.Triggers>
        <DataTrigger Binding="{Binding IsListBoxWithHeaderItem}" Value="true">
            <Setter Property="ItemContainerStyle" Value="{DynamicResource SelectableListBoxItem}" />
        </DataTrigger>
    </Style.Triggers>
</Style>

<Style x:Key="SelectableListBoxItem" TargetType="{x:Type ListBoxItem}">
    <Setter Property="IsHitTestVisible" Value="{Binding IsHitTestVisible}" />
    <Style.Triggers>
        <DataTrigger Binding="{Binding IsHitTestVisible}" Value="false">
            <Setter Property="FontWeight" Value="SemiBold" />
            <Setter Property="FontSize" Value="{StaticResource FontSizeTextBlock}" />
        </DataTrigger>
    </Style.Triggers>
</Style>

and this is a listbox xaml code

<ListBox Grid.Row="1" HorizontalContentAlignment="Stretch" ItemsSource="{Binding Items}" SelectedItem="{Binding SelectedItem}" Style="{StaticResource ListBoxWithIsHitTestVisible}">
    <ListBox.ItemTemplate>
        <DataTemplate>
            <Grid Height="{StaticResource Height}">
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="*" />
                    <ColumnDefinition Width="100" />
                </Grid.ColumnDefinitions>
                <Grid Grid.Column="0">
                    <TextBlock DataContext="{Binding Name}" Text="{Binding Value}" HorizontalAlignment="Left" VerticalAlignment="Center"/>
                </Grid>
            </Grid>
        </DataTemplate>                    
    </ListBox.ItemTemplate>
</ListBox>
0
Valera Scherbakov On

You need to define not selectable style in resources. And check on it in suitable conditions programmicaly.

MyListBox.ItemContainerStyle = (Style) MyListBox.Resources["SelectableListBoxItem"];
or
MyListBox.ItemContainerStyle = null;

Your XAML

<ListBox x:Name="MyListBox" HorizontalContentAlignment="Stretch" ItemsSource="{Binding Items}" SelectedItem="{Binding SelectedItem}" ItemContainerStyle="{DynamicResource SelectableListBoxItem}">
<ListBox.Resources>
<Style x:Key="SelectableListBoxItem" TargetType="{x:Type ListBoxItem}">
    <Setter Property="IsHitTestVisible" Value="{Binding IsHitTestVisible}" />   
    <Style.Triggers>
        <DataTrigger Binding="{Binding IsHitTestVisible}" Value="false">
            <Setter Property="FontWeight" Value="SemiBold" />
            <Setter Property="FontSize" Value="{StaticResource FontSizeTextBlock}" />
        </DataTrigger>
        <Trigger Property="IsSelected" Value="True">
             <Setter Property="Background" Value="{x:Null}" />
             <Setter Property="BorderBrush" Value="{x:Null}" />
        </Trigger>
    </Style.Triggers>
    </Style>
</ListBox.Resources>

    <ListBox.ItemTemplate>                    
... your template
    </ListBox.ItemTemplate>
</ListBox>

It's not final solution, but food for thought :)