Tuesday, July 26, 2022

Hiding a base class property

One of the problems I had when changing the look of disabled controls is that the complex controls such as DatePicker have a Background property that is ignored. They get this because they derive from the Control class but the idea of a single Background property for a complex control doesn't make sense.

I wondered if it was possible for a derived class to hide properties of its base class. There's an interesting discussion on that topic on StackOverflow, but I don't entirely agree that it's a bad idea to be able to do this.

First attempt

My first thought was to add a private overloaded property to the derived class. However if you put breakpoints on the two setters you can see that setting the property in the derived class blows right past the derived class and calls the setter on the base class. So that's a fail.

Module Module1
    Public Class BaseClass
 
        Private _X As Integer
        Public Property X As Integer
            Get
                Return _X
            End Get
            Set(value As Integer)
                _X = value
            End Set
        End Property
    End Class
 
    Public Class DerivedClass
        Inherits BaseClass
 
        Private _X As Integer
        Private Overloads Property X As Integer
            Get
                Return _X
            End Get
            Set(value As Integer)
                _X = value
            End Set
        End Property
    End Class
 
    Sub Main()
 
        Dim b As New BaseClass()
        Dim d As New DerivedClass()
 
        b.X = 4
        d.X = 4
 
        Console.ReadLine()
    End Sub
End Module

Second attempt

So how about making the derived class read-only. That would provide half the functionality we want, especially if the getter threw an exception. It does raise a build error on the setter, but only a run-time error on the getter.

Module Module1
    Public Class BaseClass
 
        Private _X As Integer
        Public Property X As Integer
            Get
                Return _X
            End Get
            Set(value As Integer)
                _X = value
            End Set
        End Property
    End Class
 
    Public Class DerivedClass
        Inherits BaseClass
        Public Overloads ReadOnly Property X As Integer
            Get
                Throw New NotImplementedException("Please stop calling me")
            End Get
        End Property
    End Class
 
    Sub Main()
 
        Dim b As New BaseClass()
        Dim d As New DerivedClass()
 
        Console.WriteLine(d.X)
        d.X = 4
        ~~~~~~~

        Console.ReadLine()
    End Sub
End Module

Third attempt

Perhaps we could use the Obsolete attribute raising an error at build time. That raises build time errors when I access the getter or the setter but the property is still listed in "Intellisense". This is the best I've been able to do so far.

Module Module1
    Public Class BaseClass
 
        Private _X As Integer
        Public Property X As Integer
            Get
                Return _X
            End Get
            Set(value As Integer)
                _X = value
            End Set
        End Property
    End Class
 
    Public Class DerivedClass
        Inherits BaseClass
        <Obsolete("Property X not supported", True)>
        Public Overloads Property X As Integer
    End Class
 
    Sub Main()
 
        Dim b As New BaseClass()
        Dim d As New DerivedClass()
 
        Console.WriteLine(d.X)
                          ~~~
        d.X = 4
        ~~~
 
        Console.ReadLine()
    End Sub
End Module


Monday, July 25, 2022

Setting Background of DatePicker, ComboBox, CheckBox

We are implementing a new UI standard that improves the readability of disabled controls. Take a look at some sample enabled and disabled controls below. You can see the disabled controls are inconsistent in look and are quite difficult to read in some cases.


Here's the XAML for the window above. 

<Window x:Class="DisabledControls.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:DisabledControls"
        mc:Ignorable="d"
        Title="Disabled Styles" Height="450" Width="800">
    <Window.Resources>
        <Color x:Key="PageBackgroundColor" >#E7E7F0</Color>
        <SolidColorBrush x:Key="PageBackgroundBrush" Color="{StaticResource PageBackgroundColor}"/>
    </Window.Resources>
    <Window.Background>
        <Binding Source="{StaticResource  PageBackgroundBrush}"/>
    </Window.Background>
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="24"/>
            <RowDefinition Height="24"/>
            <RowDefinition Height="24"/>
            <RowDefinition Height="24"/>
            <RowDefinition Height="24"/>
            <RowDefinition Height="24"/>
            <RowDefinition Height="60"/>
        
</Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="200"/>
            <ColumnDefinition Width="200"/>
        </Grid.ColumnDefinitions>
        <TextBlock Grid.Row="0" Grid.Column="0" Text="Enabled Controls"/>
        <TextBlock Grid.Row="0" Grid.Column="1" Text="Disabled Controls"/>
        <TextBox Grid.Row="1" Grid.Column="0" Text="Enabled TextBox"/>
        <TextBox Grid.Row="1" Grid.Column="1" Text="Disabled TextBox" IsEnabled="False"/>
        <DatePicker Grid.Row="2" Grid.Column="0" SelectedDate="1/1/2000"/>
        <DatePicker Grid.Row="2" Grid.Column="1" IsEnabled="False" SelectedDate="1/1/2000"/>
        <ComboBox Grid.Row="3" Grid.Column="0" SelectedIndex="0">
            <ComboBoxItem>Enabled Dropdown</ComboBoxItem>
        </ComboBox>
        <ComboBox Grid.Row="3" Grid.Column="1" SelectedIndex="0" IsEnabled="False">
            <ComboBoxItem>Disabled Dropdown</ComboBoxItem>
        </ComboBox>
        <ComboBox Grid.Row="4" Grid.Column="0" SelectedIndex="0" IsEditable="True">
            <ComboBoxItem>Enabled Combobox</ComboBoxItem>
        </ComboBox>
        <ComboBox Grid.Row="4" Grid.Column="1" SelectedIndex="0" IsEditable="True" IsEnabled="False">
            <ComboBoxItem>Disabled Combobox</ComboBoxItem>
        </ComboBox>
        <CheckBox Grid.Row="5" Grid.Column="0" Content="Enabled Checkbox" IsChecked="True"/>
        <CheckBox Grid.Row="5" Grid.Column="1" Content="Disabled Checkbox" IsChecked="True" IsEnabled="False"/>
    </Grid>
</Window>

 We decided to style disabled controls so the background is transparent and the text is black. Here's how the TextBox looks with this new standard.

TextBox with new disabled style

At first I assumed all I had to do was write a default style with an IsEnabled trigger that overrode the foreground and background. But Microsoft grays out the text by setting the opacity of the border element to 0.5. I could add a default border style to my textbox style to override this, but it's easier to simply override the textbox template like this.

    <Window.Resources>
        <Color x:Key="PageBackgroundColor" >#E7E7F0</Color>
        <Color x:Key="ControlBorderColor">DarkGray</Color>
 
        <Thickness x:Key="ControlBorderThickness">0.5</Thickness>
 
        <SolidColorBrush x:Key="PageBackgroundBrush" Color="{StaticResource PageBackgroundColor}"/>
        <SolidColorBrush x:Key="ControlBorderBrush" Color="{StaticResource ControlBorderColor}"/>
 
        <Style TargetType="TextBox">
            <Style.Triggers>
                <Trigger Property="IsEnabled" Value="False">
                    <Trigger.Setters>
                        <Setter Property="Template">
                            <Setter.Value>
                                <ControlTemplate TargetType="TextBox">
                                    <Border BorderThickness="{StaticResource ControlBorderThickness}" BorderBrush="{StaticResource ControlBorderBrush}" Padding="2" Height="{TemplateBinding Height}">
                                        <TextBlock Text="{TemplateBinding Text}" Width="{TemplateBinding Width}" Background="Transparent"/>
                                    </Border>
                                </ControlTemplate>
                            </Setter.Value>
                        </Setter>
                    </Trigger.Setters>
                </Trigger>
            </Style.Triggers>
        </Style>
    </Window.Resources>
 
You may think "that's a lot of XAML to change a background - I thought XAML was concise". You'd be right. The DatePicker gets a lot worse.

The DatePicker has several parts including a border, grid, textbox, button, and popup. It has a background property but setting this has no effect. We need to tell the textbox to be transparent and black and we need to gray out the button. In addition, the Datepicker has two rectangles it uses to gray out the text by making them semi-transparent. So we have a shopping list of things we have to do.

  1. Hide the rectangles
  2. Retemplate the TextBox (note the DatePicker actually uses a DatePickerTextBox)
  3. Gray the button
Here's the Datepicker style we need.

        <Style TargetType="DatePicker" BasedOn="{StaticResource {x:Type DatePicker}}">
            <Style.Resources>
                <Style TargetType="Rectangle">
                    <Style.Triggers>
                        <DataTrigger Binding="{Binding IsEnabled, RelativeSource={RelativeSource AncestorType=DatePicker}}" Value="False">
                            <Setter Property="Opacity" Value="0"/>
                        </DataTrigger>
                    </Style.Triggers>
                </Style>
                <Style TargetType="DatePickerTextBox">
                    <Style.Triggers>
                        <DataTrigger Binding="{Binding IsEnabled, RelativeSource={RelativeSource AncestorType=DatePicker}}" Value="False">
                            <Setter Property="Template">
                                <Setter.Value>
                                    <ControlTemplate TargetType="DatePickerTextBox">
                                        <TextBlock Text="{TemplateBinding Text}"/>
                                    </ControlTemplate>
                                </Setter.Value>
                            </Setter>
                        </DataTrigger>
                    </Style.Triggers>
                </Style>
                <Style TargetType="Button">
                    <Style.Triggers>
                        <DataTrigger Binding="{Binding IsEnabled, RelativeSource={RelativeSource AncestorType=DatePicker}}" Value="False">
                            <Setter Property="Opacity" Value="0.5"/>
                        </DataTrigger>
                    </Style.Triggers>
                </Style>
            </Style.Resources>
        </Style>

 Now the disabled DatePicker looks like this.

DatePicker with new disabled style

The ComboBox has similar issues that I solved in the same way - I retemplate the control to be a simple TextBlock. Note I don't attempt to reproduce the down arrow. The style looks like this.

        <Style TargetType="{x:Type ComboBox}">
            <Style.Triggers>
                <Trigger Property="IsEnabled" Value="False">
                    <Setter Property="Template">
                        <Setter.Value>
                            <ControlTemplate TargetType="ComboBox">
                                <Border Width="{TemplateBinding Width}"
                                    Height="{TemplateBinding Height}"
                                    BorderBrush="{StaticResource ControlBorderBrush}" BorderThickness="{StaticResource ControlBorderThickness}" Padding="2">
                                    <TextBlock Text="{TemplateBinding Text}"/>
                                </Border>
                            </ControlTemplate>
                        </Setter.Value>
                    </Setter>
                </Trigger>
            </Style.Triggers>
        </Style>
 
And the result looks like this.

Combobox with new disabled style

The checkbox also has a Background property but that seems to be ignored too. I completely retemplated the CheckBox with a TextBlock instead using this style.

        <Style TargetType="{x:Type CheckBox}">
            <Style.Triggers>
                <Trigger Property="IsEnabled" Value="False">
                    <Setter Property="Template">
                        <Setter.Value>
                            <ControlTemplate TargetType="CheckBox">
                                <StackPanel Orientation="Horizontal" VerticalAlignment="Top">
                                    <Border Height="12" Width="12" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{StaticResource ControlBorderThickness}" Margin="1">
                                        <TextBlock Text="&#xFC;" FontFamily="Wingdings" FontSize="11" FontWeight="Bold">
                                            <TextBlock.Style>
                                                <Style TargetType="TextBlock">
                                                    <Style.Triggers>
                                                        <DataTrigger Binding="{Binding IsChecked, RelativeSource={RelativeSource AncestorType=CheckBox}}" Value="False">
                                                            <Setter Property="Visibility" Value="Hidden"/>
                                                        </DataTrigger>
                                                    </Style.Triggers>
                                                </Style>
                                            </TextBlock.Style>
                                        </TextBlock>
                                    </Border>
                                    <TextBlock Text="{TemplateBinding Content}" Margin="2,0,0,0"/>
                                </StackPanel>
                            </ControlTemplate>
                        </Setter.Value>
                    </Setter>
                </Trigger>
            </Style.Triggers>
        </Style> 

Adding support for ListBox:

 If you disable a ListBox you cannot scroll it. The same applies if you set IsHitTestVisible to false. There is no IsReadOnly property on a ListBox. So in the absence of a useful property, we need to get the look and feel we want from a style. This actually makes things a lot easier because we don't have to fight Microsoft's desire to make all disabled controls difficult to read.

Add a read only ListBox style to the window's resources.

        <Style x:Key="ReadOnlyListBox" TargetType="{x:Type ListBox}">
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="{x:Type ListBox}">
                        <Border x:Name="Bd" SnapsToDevicePixels="true" Background="Transparent" Padding="1"
                                BorderBrush="{TemplateBinding BorderBrush}"
                                BorderThickness="{TemplateBinding BorderThickness}">
                            <ScrollViewer Padding="{TemplateBinding Padding}" Focusable="false">
                                <ItemsPresenter SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" IsHitTestVisible="False"/>
                            </ScrollViewer>
                        </Border>
                        <ControlTemplate.Triggers>
                            <Trigger Property="IsGrouping" Value="true">
                                <Setter Property="ScrollViewer.CanContentScroll" Value="false"/>
                            </Trigger>
                        </ControlTemplate.Triggers>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>

and add a couple of ListBoxes to our XAML.

        <ListBox Grid.Row="6" Grid.Column="0" SelectedIndex="0">
            <ListBoxItem>Enabled ListBoxItem One</ListBoxItem>
            <ListBoxItem>Enabled ListBoxItem Two</ListBoxItem>
            <ListBoxItem>Enabled ListBoxItem Three</ListBoxItem>
            <ListBoxItem>Enabled ListBoxItem Four</ListBoxItem>
            <ListBoxItem>Enabled ListBoxItem Five</ListBoxItem>
        </ListBox>
        <ListBox Grid.Row="6" Grid.Column="1" SelectedIndex="0" Style="{StaticResource ReadOnlyListBox}">
            <ListBoxItem>Disabled ListBoxItem One</ListBoxItem>
            <ListBoxItem>Disabled ListBoxItem Two</ListBoxItem>
            <ListBoxItem>Disabled ListBoxItem Three</ListBoxItem>
            <ListBoxItem>Disabled ListBoxItem Four</ListBoxItem>
            <ListBoxItem>Disabled ListBoxItem Five</ListBoxItem>
        </ListBox>


ReadOnly but scrollable ListBox

The entire XAML for this page including the new styles is...

<Window x:Class="DisabledControls.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:DisabledControls"
        mc:Ignorable="d"
        Title="Disabled Styles" Height="450" Width="800">
    <Window.Resources>
        <SolidColorBrush x:Key="PageBackgroundBrush" Color="#D7E2F7"/>
 
        <Style TargetType="TextBox">
            <Style.Triggers>
                <Trigger Property="IsEnabled" Value="False">
                    <Trigger.Setters>
                        <Setter Property="Template">
                            <Setter.Value>
                                <ControlTemplate TargetType="TextBox">
                                    <Border BorderThickness="{TemplateBinding BorderThickness}" BorderBrush="{TemplateBinding BorderBrush}" Padding="{TemplateBinding Padding}" Height="{TemplateBinding Height}">
                                        <TextBlock Text="{TemplateBinding Text}" Width="{TemplateBinding Width}" Background="Transparent"/>
                                    </Border>
                                </ControlTemplate>
                            </Setter.Value>
                        </Setter>
                    </Trigger.Setters>
                </Trigger>
            </Style.Triggers>
        </Style>
 
        <Style TargetType="DatePicker" BasedOn="{StaticResource {x:Type DatePicker}}">
            <Style.Resources>
                <Style TargetType="Rectangle">
                    <Style.Triggers>
                        <DataTrigger Binding="{Binding IsEnabled, RelativeSource={RelativeSource AncestorType=DatePicker}}" Value="False">
                            <Setter Property="Opacity" Value="0"/>
                        </DataTrigger>
                    </Style.Triggers>
                </Style>
                <Style TargetType="DatePickerTextBox">
                    <Style.Triggers>
                        <DataTrigger Binding="{Binding IsEnabled, RelativeSource={RelativeSource AncestorType=DatePicker}}" Value="False">
                            <Setter Property="Template">
                                <Setter.Value>
                                    <ControlTemplate TargetType="DatePickerTextBox">
                                        <TextBlock Text="{TemplateBinding Text}"/>
                                    </ControlTemplate>
                                </Setter.Value>
                            </Setter>
                        </DataTrigger>
                    </Style.Triggers>
                </Style>
                <Style TargetType="Button">
                    <Style.Triggers>
                        <DataTrigger Binding="{Binding IsEnabled, RelativeSource={RelativeSource AncestorType=DatePicker}}" Value="False">
                            <Setter Property="Opacity" Value="0.5"/>
                        </DataTrigger>
                    </Style.Triggers>
                </Style>
            </Style.Resources>
        </Style>
        <Style TargetType="{x:Type ComboBox}">
            <Style.Triggers>
                <Trigger Property="IsEnabled" Value="False">
                    <Setter Property="Template">
                        <Setter.Value>
                            <ControlTemplate TargetType="ComboBox">
                                <Border Width="{TemplateBinding Width}"
                                    Height="{TemplateBinding Height}"
                                    BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Padding="2">
                                    <TextBlock Text="{TemplateBinding Text}"/>
                                </Border>
                            </ControlTemplate>
                        </Setter.Value>
                    </Setter>
                </Trigger>
            </Style.Triggers>
        </Style>
 
        <Style TargetType="{x:Type CheckBox}">
            <Style.Triggers>
                <Trigger Property="IsEnabled" Value="False">
                    <Setter Property="Template">
                        <Setter.Value>
                            <ControlTemplate TargetType="CheckBox">
                                <StackPanel Orientation="Horizontal" VerticalAlignment="Top">
                                    <Border Height="13" Width="13" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Margin="1">
                                        <TextBlock Text="&#xFC;" FontFamily="Wingdings" FontSize="11" FontWeight="Bold">
                                            <TextBlock.Style>
                                                <Style TargetType="TextBlock">
                                                    <Style.Triggers>
                                                        <DataTrigger Binding="{Binding IsChecked, RelativeSource={RelativeSource AncestorType=CheckBox}}" Value="False">
                                                            <Setter Property="Visibility" Value="Hidden"/>
                                                        </DataTrigger>
                                                    </Style.Triggers>
                                                </Style>
                                            </TextBlock.Style>
                                        </TextBlock>
                                    </Border>
                                    <TextBlock Text="{TemplateBinding Content}" Margin="2,0,0,0"/>
                                </StackPanel>
                            </ControlTemplate>
                        </Setter.Value>
                    </Setter>
                </Trigger>
            </Style.Triggers>
        </Style>
 
        <Style TargetType="ListBox">
            <Style.Triggers>
                <Trigger Property="IsHitTestVisible" Value="False">
                    <Setter Property="Template">
                        <Setter.Value>
                            <ControlTemplate TargetType="ListBox">
                                <Border Background="Transparent"
                                    BorderBrush="{TemplateBinding BorderBrush}"
                                    BorderThickness="{TemplateBinding BorderThickness}">
                                    <ScrollViewer HorizontalScrollBarVisibility="Auto">
                                        <StackPanel Orientation="Vertical"
                                                VerticalAlignment="Stretch"
                                                HorizontalAlignment="Stretch"
                                                IsItemsHost="True">
                                        </StackPanel>
                                    </ScrollViewer>
                                </Border>
                            </ControlTemplate>
                        </Setter.Value>
                    </Setter>
                </Trigger>
            </Style.Triggers>
        </Style>
 
        <Style x:Key="ReadOnlyListBox" TargetType="{x:Type ListBox}">
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="{x:Type ListBox}">
                        <Border x:Name="Bd" SnapsToDevicePixels="true" Background="Transparent" Padding="1"
                                BorderBrush="{TemplateBinding BorderBrush}"
                                BorderThickness="{TemplateBinding BorderThickness}">
                            <ScrollViewer Padding="{TemplateBinding Padding}" Focusable="false">
                                <ItemsPresenter SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" IsHitTestVisible="False"/>
                            </ScrollViewer>
                        </Border>
                        <ControlTemplate.Triggers>
                            <Trigger Property="IsGrouping" Value="true">
                                <Setter Property="ScrollViewer.CanContentScroll" Value="false"/>
                            </Trigger>
                        </ControlTemplate.Triggers>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>
    </Window.Resources>
    <Window.Background>
        <Binding Source="{StaticResource  PageBackgroundBrush}"/>
    </Window.Background>
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="24"/>
            <RowDefinition Height="24"/>
            <RowDefinition Height="24"/>
            <RowDefinition Height="24"/>
            <RowDefinition Height="24"/>
            <RowDefinition Height="24"/>
            <RowDefinition Height="70"/>
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="200"/>
            <ColumnDefinition Width="200"/>
        </Grid.ColumnDefinitions>
        <TextBlock Grid.Row="0" Grid.Column="0" Text="Enabled Controls"/>
        <TextBlock Grid.Row="0" Grid.Column="1" Text="Disabled Controls"/>
        <TextBox Grid.Row="1" Grid.Column="0" Text="Enabled TextBox"/>
        <TextBox Grid.Row="1" Grid.Column="1" Text="Disabled TextBox" IsEnabled="False"/>
        <DatePicker Grid.Row="2" Grid.Column="0" SelectedDate="1/1/2000"/>
        <DatePicker Grid.Row="2" Grid.Column="1" IsEnabled="False" SelectedDate="1/1/2000"/>
        <ComboBox Grid.Row="3" Grid.Column="0" SelectedIndex="0">
            <ComboBoxItem>Enabled Dropdown</ComboBoxItem>
        </ComboBox>
        <ComboBox Grid.Row="3" Grid.Column="1" SelectedIndex="0" IsEnabled="False">
            <ComboBoxItem>Disabled Dropdown</ComboBoxItem>
        </ComboBox>
        <ComboBox Grid.Row="4" Grid.Column="0" SelectedIndex="0" IsEditable="True">
            <ComboBoxItem>Enabled Combobox</ComboBoxItem>
        </ComboBox>
        <ComboBox Grid.Row="4" Grid.Column="1" SelectedIndex="0" IsEditable="True" IsEnabled="False">
            <ComboBoxItem>Disabled Combobox</ComboBoxItem>
        </ComboBox>
        <CheckBox Grid.Row="5" Grid.Column="0" Content="Enabled Checkbox" IsChecked="True"/>
        <CheckBox Grid.Row="5" Grid.Column="1" Content="Disabled Checkbox" IsChecked="True" IsEnabled="False"/>
        <ListBox Grid.Row="6" Grid.Column="0" SelectedIndex="0">
            <ListBoxItem>Enabled ListBoxItem One</ListBoxItem>
            <ListBoxItem>Enabled ListBoxItem Two</ListBoxItem>
            <ListBoxItem>Enabled ListBoxItem Three</ListBoxItem>
            <ListBoxItem>Enabled ListBoxItem Four</ListBoxItem>
            <ListBoxItem>Enabled ListBoxItem Five</ListBoxItem>
        </ListBox>
        <ListBox Grid.Row="6" Grid.Column="1" SelectedIndex="0" Style="{StaticResource ReadOnlyListBox}">
            <ListBoxItem>Disabled ListBoxItem One</ListBoxItem>
            <ListBoxItem>Disabled ListBoxItem Two</ListBoxItem>
            <ListBoxItem>Disabled ListBoxItem Three</ListBoxItem>
            <ListBoxItem>Disabled ListBoxItem Four</ListBoxItem>
            <ListBoxItem>Disabled ListBoxItem Five</ListBoxItem>
        </ListBox>
    </Grid>
</Window>
 
 
If you think this is a ridiculous amount of work to make a few backgrounds transparent and some text black, I agree with you.