Jivlain
Jivlain

Reputation: 3658

Replicating the background colour on a WPF control

I have written a user control which consists of a ListBox and a couple extra controls. I want to wrap the whole thing in a border using the same brush as a standard ListBox would have.

MSDN has a page given a standard style for the ListBox, but it has hardcoded colours whereas a standard ListBox uses different styles on different platforms or with different themes. How can I recreate the border of a ListBox in my own control?

Upvotes: 2

Views: 654

Answers (2)

Jivlain
Jivlain

Reputation: 3658

What I've done is to write a function that extracts the default style for a control, and the relevant property from that style:

private static TReturn ExtractStyleProperty<TReturn, TFromControl>(string name, TReturn defVal)
{
  var style = Application.Current.FindResource(typeof(TFromControl)) as Style;
  if (style == null){
    return defVal;
  }
  var setter = style.Setters.Where(s => s is Setter).Cast<Setter>().First(s => s.Property.Name.Equals(name));
  if (setter == null){
    return defVal;
  }
  return (TReturn)setter.Value;
}

With that I can create a property for each property I want to recreate:

public Brush ListBoxBorderBrush {
  get {
    return ExtractStyleProperty<Brush, ListBox>("BorderBrush", new SolidColorBrush(Color.FromRgb(130, 135, 144)));
  }
}

And then bind my control's properties to those ones. This gets the value appropriate to the system and WPF theme.

Upvotes: 0

Alan
Alan

Reputation: 7951

I used Microsoft Expression Blend to create a copy of the standard ListBox template. Here's what I got from it...

<SolidColorBrush x:Key="ListBorder" Color="#828790"/>
<Style x:Key="ListBoxStyle2" TargetType="{x:Type ListBox}">
    <Setter Property="Background" Value="{DynamicResource {x:Static SystemColors.WindowBrushKey}}"/>
    <Setter Property="BorderBrush" Value="{StaticResource ListBorder}"/>
    <Setter Property="BorderThickness" Value="1"/>
    <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}"/>
    <Setter Property="ScrollViewer.HorizontalScrollBarVisibility" Value="Auto"/>
    <Setter Property="ScrollViewer.VerticalScrollBarVisibility" Value="Auto"/>
    <Setter Property="ScrollViewer.CanContentScroll" Value="true"/>
    <Setter Property="ScrollViewer.PanningMode" Value="Both"/>
    <Setter Property="Stylus.IsFlicksEnabled" Value="False"/>
    <Setter Property="VerticalContentAlignment" Value="Center"/>
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type ListBox}">
                <Border x:Name="Bd" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" Padding="1" SnapsToDevicePixels="true">
                    <ScrollViewer Focusable="false" Padding="{TemplateBinding Padding}">
                        <ItemsPresenter SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/>
                    </ScrollViewer>
                </Border>
                <ControlTemplate.Triggers>
                    <Trigger Property="IsEnabled" Value="false">
                        <Setter Property="Background" TargetName="Bd" Value="{DynamicResource {x:Static SystemColors.ControlBrushKey}}"/>
                    </Trigger>
                    <Trigger Property="IsGrouping" Value="true">
                        <Setter Property="ScrollViewer.CanContentScroll" Value="false"/>
                    </Trigger>
                </ControlTemplate.Triggers>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

You should be able to use the same brushes in this default style to get the brushes related to the current theme.

Upvotes: 2

Related Questions