简体   繁体   中英

WPF - Binding Background Color to Three Sliders?

I'm looking to create a color selection tool by binding the background color of a label to three slidebars, each representing either Red, Blue, or Green.

Now I know how to bind the background color to a single string, but how do I go about binding to three different controls?

You're going to need to create a IMultiValueConverter class, and use a MultiBinding . If you are trying to bind a Control 's Background property, you'll need to return a Brush . A naive implementation would look something like this:

public class BrushConverter : IMultiValueConverter
{
    public object Converter(object[] values, Type targetType, object parameter, CultureInfo culture)
    {
        return new SolidColorBrush(
            Color.FromArgb(255, Convert.ToByte(values[0]), 
                Convert.ToByte(values[1]), Convert.ToByte(values[2])));
    }

    public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
    {
        // this can be implemented fairly easily
        throw new NotSupportedException();
    }
}

And then you would use it like so:

<UserControl.Resources>
    <lcl:BrushConverter x:Key="brushConverter" />
</UserControl.Resources>

<StackPanel Orientation="Vertical">
    <StackPanel.Background>
        <MultiBinding Converter="{StaticResource brushConverter}">
            <Binding Path="Value" ElementName="r" />
            <Binding Path="Value" ElementName="g" />
            <Binding Path="Value" ElementName="b" />
        </MultiBinding>
    </StackPanel.Background>
    <Slider x:Name="r" Minimum="0" Maximum="255" IsSnapToTickEnabled="True" />
    <Slider x:Name="g" Minimum="0" Maximum="255" IsSnapToTickEnabled="True" />
    <Slider x:Name="b" Minimum="0" Maximum="255" IsSnapToTickEnabled="True" />
</StackPanel>

You should use MultiBinding . You'll need to write your converter that will convert three integers (Red, Green and Blue) into Color .

I recently solved this using attached properties

Heres the full code

    public static class BrushExtender
{
    public readonly static DependencyProperty BrushProperty =
        DependencyProperty.RegisterAttached("Brush", typeof(Brush), 
        typeof(BrushExtender), new PropertyMetadata(Brushes.Black, DoBrushChanged));

    public readonly static DependencyProperty RedChannelProperty = 
        DependencyProperty.RegisterAttached("RedChannel", typeof(int), 
        typeof(BrushExtender), new PropertyMetadata(DoColorChangedRed));

    public readonly static DependencyProperty GreenChannelProperty = 
        DependencyProperty.RegisterAttached("GreenChannel", typeof(int), 
        typeof(BrushExtender), new PropertyMetadata(DoColorChangedGreen));

    public readonly static DependencyProperty BlueChannelProperty =
        DependencyProperty.RegisterAttached("BlueChannel", typeof(int),
        typeof(BrushExtender), new PropertyMetadata(DoColorChangedBlue));

    public readonly static DependencyProperty AlphaChannelProperty = 
        DependencyProperty.RegisterAttached("AlphaChannel", typeof(int),
        typeof(BrushExtender), new PropertyMetadata(DoColorChangedAlpha));

    public readonly static DependencyProperty ColourValueProperty =
        DependencyProperty.RegisterAttached("ColourValue", typeof(string),
        typeof(BrushExtender), new PropertyMetadata(DoValueChanged));

    public static void SetRedChannel(DependencyObject o, int value)
    {
        o.SetValue(RedChannelProperty, value);
    }

    public static void SetGreenChannel(DependencyObject o, int value)
    {
        o.SetValue(GreenChannelProperty, value);
    }

    public static void SetBlueChannel(DependencyObject o, int value)
    {
        o.SetValue(BlueChannelProperty, value);
    }

    public static void SetAlphaChannel(DependencyObject o, int value)
    {
        o.SetValue(AlphaChannelProperty, value);
    }

    public static void SetBrush(DependencyObject o, SolidColorBrush brush)
    {
        o.SetValue(BrushProperty, brush);
    }

    public static void SetColourValue(DependencyObject o, string value)
    {
        o.SetValue(ColourValueProperty, value);
    }

    private static void DoColorChangedRed(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        var color = ((SolidColorBrush)d.GetValue(BrushProperty)).Color;
        DoColorChange(d, (int)e.NewValue, c => c.R, () => 
            Color.FromArgb(color.A, ((byte)(int)e.NewValue), color.G, color.B));
    }

    private static void DoColorChangedGreen(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        var color = ((SolidColorBrush)d.GetValue(BrushProperty)).Color;
        DoColorChange(d, (int)e.NewValue, c => c.G, () => 
            Color.FromArgb(color.A, color.R, ((byte)(int)e.NewValue), color.B));
    }

    private static void DoColorChangedBlue(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        var color = ((SolidColorBrush)d.GetValue(BrushProperty)).Color;
        DoColorChange(d, (int)e.NewValue, c => c.B, () => 
            Color.FromArgb(color.A, color.R, color.G, (byte)(int)e.NewValue));
    }

    private static void DoColorChangedAlpha(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        var color = ((SolidColorBrush)d.GetValue(BrushProperty)).Color;
        DoColorChange(d, (int)e.NewValue, c => c.A, () => 
            Color.FromArgb((byte)(int)e.NewValue, color.R, color.G, color.B));
    }

    private static void DoColorChange(DependencyObject d, int newValue, Func<Color, int> colorCompare, 
        Func<Color> getColor)
    {
        var color = ((SolidColorBrush)d.GetValue(BrushProperty)).Color;
        if (colorCompare(color) == newValue)
            return;
        var newBrush = new SolidColorBrush(getColor());
        d.SetValue(BrushProperty, newBrush);
        d.SetValue(ColourValueProperty, newBrush.Color.ToString());
    }

    private static void DoValueChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        var color = ((SolidColorBrush)d.GetValue(BrushProperty)).Color;
        if (color.ToString() == (string)e.NewValue)
            return;
        Color? newColour = null;
        try
        {
            newColour = (Color) ColorConverter.ConvertFromString((string)e.NewValue);
        }
        catch { }
        if (newColour == null)
            return;
        var newBrush = new SolidColorBrush(newColour.Value);
        d.SetValue(BrushProperty, newBrush);
    }


    private static void DoBrushChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        if (e.NewValue == e.OldValue)
            return;
        var colour = ((SolidColorBrush)e.NewValue).Color;
        d.SetValue(RedChannelProperty, (int)colour.R);
        d.SetValue(GreenChannelProperty, (int)colour.G);
        d.SetValue(BlueChannelProperty, (int)colour.B);
        d.SetValue(AlphaChannelProperty, (int)colour.A);
        d.SetValue(ColourValueProperty, colour.ToString());
    }
}

and heres the XAML

<Window x:Class="ColourBlender.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    xmlns:ColourBlender="clr-namespace:ColourBlender" 
    Title="MainWindow" Height="350" Width="525">
<Grid>
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="Auto" />
        <ColumnDefinition Width="Auto" />
        <ColumnDefinition Width="Auto" />
    </Grid.ColumnDefinitions>
    <Grid.RowDefinitions>
        <RowDefinition Height="Auto" />
        <RowDefinition Height="Auto" />
        <RowDefinition Height="Auto" />
        <RowDefinition Height="Auto" />
        <RowDefinition Height="Auto" />
        <RowDefinition Height="Auto" />
    </Grid.RowDefinitions>

    <TextBlock Text="Red" />
    <TextBlock Text="Green" Grid.Row="1" />
    <TextBlock Text="Blue" Grid.Row="2" />
    <TextBlock Text="Alpha" Grid.Row="3" />

    <Slider Name="redSlider" Grid.Column="1" Minimum="0" Maximum="255" Width="200" Height="20" 
            Grid.ColumnSpan="2" Value="{Binding ElementName=rect, 
            Path=(ColourBlender:BrushExtender.RedChannel), Mode=TwoWay}" />
    <Slider Name="greenSlider" Grid.Column="1" Grid.Row="1" Minimum="0" Maximum="255" Width="200" Height="20" 
            Grid.ColumnSpan="2" Value="{Binding ElementName=rect, 
            Path=(ColourBlender:BrushExtender.GreenChannel), Mode=TwoWay}"  />
    <Slider Name="blueSlider" Grid.Column="1" Grid.Row="2" Minimum="0" Maximum="255" Width="200" Height="20" 
            Grid.ColumnSpan="2" Value="{Binding ElementName=rect, 
            Path=(ColourBlender:BrushExtender.BlueChannel), Mode=TwoWay}"  />
    <Slider Name="alphaSlider" Grid.Column="1" Grid.Row="3" Minimum="0" Maximum="255" Width="200" Height="20" 
            Grid.ColumnSpan="2" Value="{Binding ElementName=rect, 
            Path=(ColourBlender:BrushExtender.AlphaChannel), Mode=TwoWay}"  />

    <Rectangle Fill="SandyBrown" Name="rect" Width="200" Height="50" Grid.Row="4" Grid.ColumnSpan="3" 
            Margin="0,20,0,10" ColourBlender:BrushExtender.Brush="{Binding RelativeSource={RelativeSource Self}, 
            Path=Fill, Mode=TwoWay}"/>

    <TextBlock Text="Colour Value" Margin="5,0,5,0" Grid.Row="5" HorizontalAlignment="Center"  />
    <TextBox Text="{Binding ElementName=rect, Path=(ColourBlender:BrushExtender.ColourValue), Mode=TwoWay}" 
            Margin="0,0,0,0" Grid.Row="5" Grid.Column="1" Width="100" HorizontalAlignment="Center" />

    <Button Content="Update" Grid.Row="5" Grid.Column="3" />
</Grid>

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM