BrushControl

BrushControl is a control for and/or creating WPF Brushes. It supports SolidColorBrush, LinearGradientBrush (in vertical and horizontal orientation) and RadialGradialBrush (as well as the null Brush.) Gradient stop values are restricted to between 0 and 1, and MappingMode must be RelativeToBoundingBox. If a Brush is loaded that has an unsupported MappingMode, the color picker portion of the control will be disabled, however the user will be able to select a brush type from the top row of radio buttons to create a new Brush (as opposed to editing the current Brush.)

BrushControl defines two public dependency properties: Brush and ActiveColor.

Brush property is the “value” property of the control, and always reflects the current state of the brush as it is being edited by the user.

ActiveColor is the color which is currently being manipulated or is selected by the user. BrushControl is built around ColorControl. ActiveColor is the color of the internal color control.

Using BrushControl is very simple. Here is an example taken from the CircularProgressControl sample:

<StackPanel Margin="0,3,0,0" Grid.Row="8" Orientation="Horizontal">
    <dc:DropDownButton Header="Inner Border Brush" HorizontalPopupAlignment="Right">
        <dc:BrushControl MinWidth="300" Padding="10" Brush="{Binding ElementName=BigProgressControl, Path=InnerBorderBrush, Mode=TwoWay}" />
    </dc:DropDownButton>
</StackPanel>

Following is the default Template for Brush control which you can use as starting point for customizing.

<Style TargetType="ctrls:BrushControl">
    <Style.Resources>
        <BooleanToVisibilityConverter x:Key="boolToVisibilityConverter" />
        <ctrls:ReverseBrushOrientationValueConverter x:Key="reverseBrushValueConverter" />
        <Style TargetType="TextBox">
            <Setter Property="Padding" Value="0" />
        </Style>
    </Style.Resources>
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="ctrls:BrushControl">
                <Border BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" Padding="{TemplateBinding Padding}">
                    <Grid>
                        <Grid.ColumnDefinitions>
                            <ColumnDefinition Width="Auto" />
                            <ColumnDefinition Width="Auto" />
                            <ColumnDefinition />
                            <ColumnDefinition Width="Auto" />
                        </Grid.ColumnDefinitions>
                        <Grid.RowDefinitions>
                            <RowDefinition Height="Auto" />
                            <RowDefinition Height="Auto" />
                            <RowDefinition Height="Auto" />
                        </Grid.RowDefinitions>
                        <ListBox Grid.ColumnSpan="4" BorderThickness="0" HorizontalAlignment="Left" VerticalAlignment="Top" Background="Transparent" SelectedValuePath="Tag"
                                SelectedValue="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=Mode, Mode=TwoWay}">
                            <ListBox.ItemContainerStyle>
                                <Style TargetType="ListBoxItem">
                                    <Setter Property="Template">
                                        <Setter.Value>
                                            <ControlTemplate TargetType="ListBoxItem">
                                                <Grid Width="22" Height="22" Margin="2">
                                                    <Border Name="SelectedBorder" Opacity="0" CornerRadius="3" BorderThickness="1" BorderBrush="Orange" />
                                                    <ContentPresenter Margin="3" />
                                                </Grid>
                                                <ControlTemplate.Triggers>
                                                    <Trigger Property="IsSelected" Value="True">
                                                        <Setter TargetName="SelectedBorder" Property="Opacity" Value="1" />
                                                    </Trigger>
                                                </ControlTemplate.Triggers>
                                            </ControlTemplate>
                                        </Setter.Value>
                                    </Setter>
                                </Style>
                            </ListBox.ItemContainerStyle>
                            <ListBox.ItemsPanel>
                                <ItemsPanelTemplate>
                                    <StackPanel Orientation="Horizontal" />
                                </ItemsPanelTemplate>
                            </ListBox.ItemsPanel>
                            <ListBoxItem Tag="{x:Static ctrls:BrushControl+ControlMode.NullBrush}" ToolTip="{DynamicResource {x:Static ctrls:BrushControl.NullBrushStringKey}}">
                                <Border BorderThickness="1" BorderBrush="Black" Background="White">
                                    <Line X1="0" X2="1" Y1="1" Y2="0" Stretch="Uniform" Stroke="Red" />
                                </Border>
                            </ListBoxItem>
                            <ListBoxItem Tag="{x:Static ctrls:BrushControl+ControlMode.SolidColorBrush}" ToolTip="Solid Color Brush">
                                <Border BorderThickness="1" BorderBrush="Black" Background="Black" />
                            </ListBoxItem>
                            <ListBoxItem Tag="{x:Static ctrls:BrushControl+ControlMode.HorizontalLinearGradientBrush}" ToolTip="{DynamicResource {x:Static ctrls:BrushControl.HorizontalGradientBrushStringKey}}">
                                <Border BorderThickness="1" BorderBrush="Black">
                                    <Border.Background>
                                        <LinearGradientBrush StartPoint="0,0.5" EndPoint="1,0.5">
                                            <GradientStop Color="Black" Offset="0" />
                                            <GradientStop Color="LightGray" Offset="1" />
                                        </LinearGradientBrush>
                                    </Border.Background>
                                </Border>
                            </ListBoxItem>
                            <ListBoxItem Tag="{x:Static ctrls:BrushControl+ControlMode.VerticalLinearGradientBrush}" ToolTip="{DynamicResource {x:Static ctrls:BrushControl.VerticalGradientBrushStringKey}}">
                                <Border BorderThickness="1" BorderBrush="Black">
                                    <Border.Background>
                                        <LinearGradientBrush StartPoint="0.5,0" EndPoint="0.5,1">
                                            <GradientStop Color="Black" Offset="0" />
                                            <GradientStop Color="LightGray" Offset="1" />
                                        </LinearGradientBrush>
                                    </Border.Background>
                                </Border>
                            </ListBoxItem>
                            <ListBoxItem Tag="{x:Static ctrls:BrushControl+ControlMode.UncommonLinearGradientBrush}" Visibility="Collapsed" />
                            <ListBoxItem Tag="{x:Static ctrls:BrushControl+ControlMode.RadialGradientBrush}" ToolTip="{DynamicResource {x:Static ctrls:BrushControl.RadialGradientBrushStringKey}}">
                                <Border BorderThickness="1" BorderBrush="Black">
                                    <Border.Background>
                                        <RadialGradientBrush>
                                            <GradientStop Color="Black" Offset="0" />
                                            <GradientStop Color="LightGray" Offset="1" />
                                        </RadialGradientBrush>
                                    </Border.Background>
                                </Border>
                            </ListBoxItem>
                            <ListBoxItem Tag="{x:Static ctrls:BrushControl+ControlMode.ImageBrush}" Visibility="Collapsed" />
                            <ListBoxItem Margin="20,0,0,0" Tag="{x:Static ctrls:BrushControl+ControlMode.Unsupported}" ToolTip="{DynamicResource {x:Static ctrls:BrushControl.UnsupportedBrushStringKey}}"
                                            Visibility="{Binding RelativeSource={RelativeSource Self}, Path=IsSelected, Converter={StaticResource boolToVisibilityConverter}}">
                                <Border BorderThickness="1" BorderBrush="Black" Background="Red" />
                            </ListBoxItem>
                        </ListBox>
 
                        <ctrls:ColorControl x:Name="ColorControl" Grid.Row="1" Grid.ColumnSpan="4" Margin="0,5,0,0" Focusable="False"
                                            Color="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=ActiveColor, Mode=TwoWay}" />
 
                        <TextBox Grid.Row="2" Width="70" Margin="0,8,0,0" VerticalAlignment="Top" ctrls:TextBoxBehavior.UpdateOnEnter="True" 
                                    IsEnabled="{Binding ElementName=ColorControl, Path=IsEnabled}"                                     
                                    Text="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=ActiveColor, Mode=TwoWay}" />
 
                        <ctrls:DropDownButton CloseOnClick="True" Margin="0,8,0,0" Grid.Row="2" Grid.Column="1" HorizontalAlignment="Center"
                                                IsEnabled="{Binding ElementName=ColorControl, Path=IsEnabled}">
                            <ctrls:StaticMemberPicker MemberType="{x:Type Color}" ItemTemplate="{StaticResource SystemColorPickerItemTemplate}"
                                                        Value="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=ActiveColor, Mode=TwoWay}" />
                        </ctrls:DropDownButton>
 
                        <Border Name="SolidColorDisplay" Grid.Row="2" Grid.Column="2" Margin="8,8,0,0" Width="50" Height="20" HorizontalAlignment="Left" VerticalAlignment="Top">
                            <Border.Background>
                                <SolidColorBrush Color="{Binding ElementName=ColorControl, Path=Color}" />
                            </Border.Background>
                        </Border>
 
                        <ListBox Name="GradientStops" Visibility="Hidden" Grid.Row="2" Grid.Column="2" Margin="8,8,0,0" VerticalAlignment="Top" Style="{StaticResource GradientStopsListBoxStyle}" 
                                    Background="{TemplateBinding Brush}" IsEnabled="{Binding ElementName=ColorControl, Path=IsEnabled}"
                                    ItemsSource="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=ActiveGradientStops}" />
 
                        <Button Name="NewGradientStopButton" Visibility="Hidden" Grid.Column="3" Grid.Row="2" Padding="2" Margin="8,8,0,0" VerticalAlignment="Top"
                                Background="Transparent" BorderThickness="0" IsEnabled="{Binding ElementName=ColorControl, Path=IsEnabled}"
                                Style="{DynamicResource {x:Static ctrls:ButtonResources.ButtonStyleKey}}" ToolTip="New Gradient Stop">
                            <Grid>
                                <Rectangle Width="3" Height="11" Fill="Black" HorizontalAlignment="Center" />
                                <Rectangle Width="11" Height="3" Fill="Black" VerticalAlignment="Center" />
                            </Grid>
                        </Button>
 
                        <Line Name="UnsupportedX1" Margin="10" Grid.Row="1" Grid.RowSpan="2" Grid.ColumnSpan="4" X1="0" X2="1" Y1="0" Y2="1" Stretch="Fill" Stroke="Yellow" StrokeThickness="1" Visibility="Collapsed" />
                        <Line Name="UnsupportedX2" Margin="10" Grid.Row="1" Grid.RowSpan="2" Grid.ColumnSpan="4" X1="0" X2="1" Y1="1" Y2="0" Stretch="Fill" Stroke="Yellow" StrokeThickness="1" Visibility="Collapsed" />
                    </Grid>
                </Border>
                <ControlTemplate.Triggers>
                    <Trigger SourceName="GradientStops" Property="HasItems" Value="True">
                        <Setter TargetName="GradientStops" Property="Visibility" Value="Visible" />
                        <Setter TargetName="NewGradientStopButton" Property="Visibility" Value="Visible" />
                        <Setter TargetName="SolidColorDisplay" Property="Visibility" Value="Hidden" />
                    </Trigger>
                    <Trigger Property="Mode" Value="Unsupported">
                        <Setter TargetName="UnsupportedX1" Property="Visibility" Value="Visible" />
                        <Setter TargetName="UnsupportedX2" Property="Visibility" Value="Visible" />
                        <Setter Property="ToolTip" Value="The current Brush has properties which are unsupported by the Brush editor. To change, select a Brush type from one of the buttons along the top." />
                        <Setter TargetName="ColorControl" Property="IsEnabled" Value="False" />
                    </Trigger>
                    <Trigger Property="Mode" Value="VerticalLinearGradientBrush">
                        <Setter TargetName="GradientStops" Property="Background" 
                                Value="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=Brush, Converter={StaticResource reverseBrushValueConverter}}" />
                    </Trigger>
                </ControlTemplate.Triggers>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

The above Template depends on the following resources:

<sys:String x:Key="{x:Static ctrls:BrushControl.VerticalGradientBrushStringKey}">Vertical Gradient Brush</sys:String>
<sys:String x:Key="{x:Static ctrls:BrushControl.HorizontalGradientBrushStringKey}">Horizontal Gradient Brush</sys:String>
<sys:String x:Key="{x:Static ctrls:BrushControl.RadialGradientBrushStringKey}">Radial Gradient Brush</sys:String>
<sys:String x:Key="{x:Static ctrls:BrushControl.NullBrushStringKey}">Null Brush</sys:String>
<sys:String x:Key="{x:Static ctrls:BrushControl.SolidColorBrushStringKey}">Solid Color Brush</sys:String>
<sys:String x:Key="{x:Static ctrls:BrushControl.UnsupportedBrushStringKey}">Unsupported Brush</sys:String>
<sys:String x:Key="{x:Static ctrls:BrushControl.AddNewGradientStopStringKey}">New Gradient Stop</sys:String>
 
<DataTemplate x:Key="SystemColorPickerItemTemplate">
    <ctrls:SelectableItem Padding="5,1" Content="{Binding DisplayName}" IsSelected="{Binding IsSelected, Mode=TwoWay}" FocusVisualStyle="{x:Null}">
        <ctrls:SelectableItem.Template>
            <ControlTemplate TargetType="ctrls:SelectableItem">
                <Grid Background="Transparent">
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition Width="Auto" />
                        <ColumnDefinition />
                    </Grid.ColumnDefinitions>
                    <Border Width="14" Height="14" Margin="0,1,3,1">
                        <Border.Background>
                            <SolidColorBrush Color="{Binding Value}" />
                        </Border.Background>
                    </Border>
                    <Rectangle Name="HighlightRectangle" Grid.Column="1" Opacity="0" Fill="{DynamicResource {x:Static ctrls:CommonResources.HighlightKey}}" />
                    <ContentPresenter Grid.Column="1" Margin="{TemplateBinding Padding}" />
                </Grid>
                <ControlTemplate.Triggers>
                    <Trigger Property="IsHighlighted" Value="True">
                        <Setter TargetName="HighlightRectangle" Property="Opacity" Value="1" />
                        <Setter Property="Foreground" Value="{DynamicResource {x:Static ctrls:CommonResources.HighlightForegroundKey}}" />
                    </Trigger>
                </ControlTemplate.Triggers>
            </ControlTemplate>
        </ctrls:SelectableItem.Template>
    </ctrls:SelectableItem>
</DataTemplate>
 
<Style x:Key="GradientStopsListBoxStyle" TargetType="ListBox">
    <Setter Property="BorderBrush" Value="Gray" />
    <Setter Property="BorderThickness" Value="1" />
    <Setter Property="Background" Value="LightGray" />
    <Setter Property="Height" Value="16" />
    <Setter Property="ItemsPanel">
        <Setter.Value>
            <ItemsPanelTemplate>
                <Canvas />
            </ItemsPanelTemplate>
        </Setter.Value>
    </Setter>
    <Setter Property="ItemContainerStyle">
        <Setter.Value>
            <Style TargetType="ListBoxItem">
                <Setter Property="Canvas.Left" Value="{Binding Position}" />
                <Setter Property="IsSelected" Value="{Binding IsSelected, Mode=TwoWay}" />
                <Setter Property="Template">
                    <Setter.Value>
                        <ControlTemplate TargetType="ListBoxItem">
                            <Grid Background="Transparent" VerticalAlignment="Bottom" Margin="-7,0,2,-20">
                                <Path Stroke="White" Fill="Black" Data="M 0,7 L 6,0 12,7" />
                                <Path Stroke="Black" Data="M 1.5,7 L 10.5,7 10.5,12 1.5,12 Z">
                                    <Path.Fill>
                                        <SolidColorBrush Color="{Binding Color}" />
                                    </Path.Fill>
                                </Path>
                                <Thumb Background="Transparent" Focusable="True">                                        
                                    <Thumb.Template>
                                        <ControlTemplate TargetType="Thumb">                                                
                                            <Grid Background="Transparent" />
                                        </ControlTemplate>
                                    </Thumb.Template>
                                </Thumb>
                            </Grid>
                            <ControlTemplate.Triggers>
                                <Trigger Property="IsSelected" Value="True">
                                    <Setter Property="Effect">
                                        <Setter.Value>
                                            <DropShadowEffect ShadowDepth="0" BlurRadius="5" Color="Black" /> 
                                        </Setter.Value>
                                    </Setter>
                                </Trigger>
                            </ControlTemplate.Triggers>
                        </ControlTemplate>
                    </Setter.Value>
                </Setter>
            </Style>
        </Setter.Value>
    </Setter>
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="ListBox">
                <Border Padding="{TemplateBinding Padding}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}">
                    <ItemsPresenter Name="ItemsHost" />
                </Border>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

Related posts:

  1. WPF Color Control Quick Start Guide
  2. Circular Progress Control (WPF) Quick Start Guide
  3. Rating Control for WPF Quick Start Guide
  4. WPF EnumPicker
  5. How to make a password editor in WPF PropertyGrid.