【问题标题】:How can I convert the values of three sliders into a Color?如何将三个滑块的值转换为颜色?
【发布时间】:2015-06-23 01:31:45
【问题描述】:

我正在尝试创建一个允许用户在 WPF 中定义颜色的自定义用户控件。我以前在 WinForms 中这样做过,但在 WPF 中似乎并不那么直接。这也是我第一次处理多转换器。

该控件有 3 个滑块 - 就像这样:

<Slider x:Name="sdrRed" Height="32" LargeChange="5" SmallChange="1" Maximum="255" Width="321" TickPlacement="Both"/>

唯一的区别是每个的名称 - sdrRed、sdrGreen 和 sdrBlue。

这是多值转换器:

public class ByteToColorConverter : IMultiValueConverter 
{
    public object Convert( object[ ] values, Type targetType, object parameter, System.Globalization.CultureInfo culture ) {
        return Color.FromArgb( (byte)values[0], (byte)values[1], (byte)values[2], (byte)values[3]);
    }

    public object[ ] ConvertBack( object value, Type[ ] targetTypes, object parameter, System.Globalization.CultureInfo culture ) {
        Color C = ( Color )value;
        return new object[ ] { C.A, C.R, C.G, C.B };
    }
}

这是我所能得到的 - 我无法找到如何进行的示例。

另外 - 我如何将静态值传递给多转换器,以便我可以仅使用单个滑块定义颜色(例如,我可以定义红色、蓝色或绿色的阴影)?

编辑

为了清楚起见;控件本身将具有依赖属性:

private static readonly DependencyProperty
    _Color = DependencyProperty.Register( "Color", typeof( Color ), typeof( ColorDefiner ), new PropertyMetadata( Colors.Black ) );

public Color Color {
    get { return ( Color )this.GetValue( ColorDefiner._Color ); }
    set { this.SetValue( ColorDefiner._Color, value ); }
}

此控件会将转换后的颜色值传递给该绑定,以便其他颜色可以绑定到它。我希望这能解决问题。

【问题讨论】:

  • 你需要的大部分都在这里:stackoverflow.com/questions/2109756/…
  • @Ulric :不是真的 - 我知道如何将十六进制值转换为颜色。我不想将滑块值转换为字符串,我想将三个滑块的滑块值转换为单一颜色。
  • @Tim 我不熟悉那个界面 - 谢谢。我会收回我的评论。
  • @Will 你打算在哪里使用这个转换器?您是否尝试将某些东西的(例如)背景颜色设置为这些滑块的输出?向我们展示您计划在其中使用的一些 XAML,这将使我们更容易为您提供帮助。

标签: c# wpf colors multibinding imultivalueconverter


【解决方案1】:

首先,我建议您对 ByteToColorConverter 进行以下更改:

public class DoubleToColorConverter : IMultiValueConverter
{
    public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        // Values bound to sliders are going to be doubles.
        return Color.FromScRgb((float)(double)values[0], (float)(double)values[1], (float)(double)values[2], (float)(double)values[3]);
    }

    public object[] ConvertBack(object value, Type[] targetTypes, object parameter, System.Globalization.CultureInfo culture)
    {
        Color C = (Color)value;
        return new object[] { (double)C.ScA, (double)C.ScR, (double)C.ScG, (double)C.ScB };
    }
}

我已从字节切换为双精度值,因为您尝试绑定的滑块值只会返回/接受双精度值。 (float)(double) 演员表用于处理数组中的值的拆箱。

通过这个 XAML,我可以让一个基本的 ARGB 颜色混合器正常工作。请注意,我已经更改了滑块上的 Min/Max 值,现在我们不再处理字节了。

<StackPanel>
    <Slider x:Name="sdrAlpha" Height="32" LargeChange="0.5" SmallChange="0.1" Minimum="0" Maximum="1" Width="321" TickPlacement="Both"/>
    <Slider x:Name="sdrRed" Height="32" LargeChange="0.5" SmallChange="0.1" Minimum="0" Maximum="1" Width="321" TickPlacement="Both"/>
    <Slider x:Name="sdrGreen" Height="32" LargeChange="0.5" SmallChange="0.1" Minimum="0" Maximum="1" Width="321" TickPlacement="Both"/>
    <Slider x:Name="sdrBlue" Height="32" LargeChange="0.5" SmallChange="0.1" Minimum="0" Maximum="1" Width="321" TickPlacement="Both"/>
    <Border x:Name="colourBorder" Height="200" HorizontalAlignment="Stretch">
        <Border.Background>
            <SolidColorBrush>
                <SolidColorBrush.Color>
                    <MultiBinding Converter="{StaticResource colorConverter}">
                        <Binding ElementName="sdrAlpha" Path="Value" Mode="TwoWay" />
                        <Binding ElementName="sdrRed" Path="Value" Mode="TwoWay" />
                        <Binding ElementName="sdrGreen" Path="Value" Mode="TwoWay" />
                        <Binding ElementName="sdrBlue" Path="Value" Mode="TwoWay" />
                    </MultiBinding>
                </SolidColorBrush.Color>
            </SolidColorBrush>
        </Border.Background>
    </Border>
</StackPanel>

如果您想将单个滑块绑定到转换器,您可以更新转换器以检查 values[] 数组中的值的数量。您也许可以使用ConverterParameter 传递您希望单个滑块影响的颜色......像这样:

<MultiBinding Converter="{StaticResource colorConverter}" ConverterParameter="Red">
    <Binding ElementName="sdrRed" Path="Value" Mode="TwoWay" />
</MultiBinding>

【讨论】:

  • 是的 - 这很好;谢谢 - 我没有传递参数,而是定义了资源并传递了这些。
【解决方案2】:

好的 - 我要感谢大家的帮助;我终于想出了一个解决方案 - 如果有人对此感兴趣或偶然发现,这也是 MVVM 的一个很好的教训(也许;我不知道......)。

无论如何:

这是我实现的 MVVM:

public class ColorViewModel : INotifyPropertyChanged {

    public event PropertyChangedEventHandler PropertyChanged;

    private Color _Color = Colors.Black;

    public double A {
        get { return this.Color.ScA; }
        set {
            this._Color.ScA = ( float )value;
            if ( this.PropertyChanged != null ) {
                this.PropertyChanged( this, new PropertyChangedEventArgs( "A" ) );
                this.PropertyChanged( this, new PropertyChangedEventArgs( "Color" ) );
            }
        }
    }
    public double R {
        get { return this.Color.ScR; }
        set {
            this._Color.ScR = ( float )value;
            if ( this.PropertyChanged != null ) {
                this.PropertyChanged( this, new PropertyChangedEventArgs( "R" ) );
                this.PropertyChanged( this, new PropertyChangedEventArgs( "Red" ) );
                this.PropertyChanged( this, new PropertyChangedEventArgs( "Color" ) );
            }
        }
    }
    public double G {
        get { return this.Color.ScG; }
        set {
            this._Color.ScG = ( float )value;
            if ( this.PropertyChanged != null ) {
                this.PropertyChanged( this, new PropertyChangedEventArgs( "G" ) );
                this.PropertyChanged( this, new PropertyChangedEventArgs( "Green" ) );
                this.PropertyChanged( this, new PropertyChangedEventArgs( "Color" ) );
            }
        }
    }
    public double B {
        get { return this._Color.ScB; }
        set {
            this._Color.ScB = ( float )value;
            if ( this.PropertyChanged != null ) {
                this.PropertyChanged( this, new PropertyChangedEventArgs( "B" ) );
                this.PropertyChanged( this, new PropertyChangedEventArgs( "Blue" ) );
                this.PropertyChanged( this, new PropertyChangedEventArgs( "Color" ) );
            }
        }
    }

    public Color Color {
        get { return this._Color; }
        set {
            this._Color = value;
            if ( this.PropertyChanged != null )
                this.AllChanged( );
        }
    }
    public Color Red { get { return Color.FromScRgb( 1.0F, ( float )this.R, 0.0F, 0.0F ); } }
    public Color Green { get { return Color.FromScRgb( 1.0F, 0.0F, ( float )this.G, 0.0F ); } }
    public Color Blue { get { return Color.FromScRgb( 1.0F, 0.0F, 0.0F, ( float )this.B ); } }

    private void AllChanged( ) {
        this.PropertyChanged( this, new PropertyChangedEventArgs( "A" ) );
        this.PropertyChanged( this, new PropertyChangedEventArgs( "R" ) );
        this.PropertyChanged( this, new PropertyChangedEventArgs( "G" ) );
        this.PropertyChanged( this, new PropertyChangedEventArgs( "B" ) );
        this.PropertyChanged( this, new PropertyChangedEventArgs( "Red" ) );
        this.PropertyChanged( this, new PropertyChangedEventArgs( "Green" ) );
        this.PropertyChanged( this, new PropertyChangedEventArgs( "Blue" ) );
        this.PropertyChanged( this, new PropertyChangedEventArgs( "Color" ) );
    }
}

这是控制类:

public partial class ColorDefiner : UserControl {

    public static readonly DependencyProperty
        _Color = DependencyProperty.Register( "Color", typeof( Color ), typeof( ColorDefiner ) );

    public Color Color {
        get { return ( Color )this.GetValue( ColorDefiner._Color ); }
        set { this.SetValue( ColorDefiner._Color, value ); }
    }

    private ColorViewModel CVM { get { return this.DataContext as ColorViewModel; } }

    public ColorDefiner( ) {
        InitializeComponent( );
        Binding B = new Binding( "Color" ) { Source = this.DataContext };
        this.SetBinding( ColorDefiner._Color, B );
    }
}

这是用户控件的 XAML(是的,我是用 UserControl 完成的;这需要一个数据上下文,我真的不想在自定义控件中对此大惊小怪 - 这真的只是无论如何都是我自己的个人控制权):

<UserControl
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
    xmlns:Components="clr-namespace:WPFTools.Components"
    xmlns:Controls="clr-namespace:WPFTools.Controls"
    x:Class="WPFTools.Controls.ColorDefiner"
    mc:Ignorable="d"
    Width="100" Height="100" FontFamily="Arial" FontWeight="Bold">
    <UserControl.DataContext>
        <Controls:ColorViewModel/>
    </UserControl.DataContext>
    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition/>
            <ColumnDefinition/>
            <ColumnDefinition/>
            <ColumnDefinition/>
        </Grid.ColumnDefinitions>
        <Grid.RowDefinitions>
            <RowDefinition Height="20"/>
            <RowDefinition Height="5"/>
            <RowDefinition/>
        </Grid.RowDefinitions>
        <Viewbox HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
            <Components:WPFGLabel Text="A" StrokeThickness="0.5" TextAlignment="Right" Stroke="#99000000">
                <Components:WPFGLabel.Fill>
                    <SolidColorBrush Color="{Binding Color}"/>
                </Components:WPFGLabel.Fill>
            </Components:WPFGLabel>
        </Viewbox>
        <Viewbox HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Grid.Column="1">
            <Components:WPFGLabel Text="R" StrokeThickness="0.5" TextAlignment="Right" Stroke="#99000000">
                <Components:WPFGLabel.Fill>
                    <SolidColorBrush Color="{Binding Red, Mode=OneWay}"/>
                </Components:WPFGLabel.Fill>
            </Components:WPFGLabel>
        </Viewbox>
        <Viewbox HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Grid.Column="2">
            <Components:WPFGLabel Text="G" StrokeThickness="0.5" TextAlignment="Right" Stroke="#99000000">
                <Components:WPFGLabel.Fill>
                    <SolidColorBrush Color="{Binding Green, Mode=OneWay}"/>
                </Components:WPFGLabel.Fill>
            </Components:WPFGLabel>
        </Viewbox>
        <Viewbox HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Grid.Column="3">
            <Components:WPFGLabel Text="B" StrokeThickness="0.5" TextAlignment="Right" Stroke="#99000000" RenderTransformOrigin="-7.272,0.575">
                <Components:WPFGLabel.Fill>
                    <SolidColorBrush Color="{Binding Blue, Mode=OneWay}"/>
                </Components:WPFGLabel.Fill>
            </Components:WPFGLabel>
        </Viewbox>
        <Viewbox HorizontalAlignment="Stretch" Grid.Row="2" VerticalAlignment="Stretch">
            <Slider Orientation="Vertical" TickPlacement="Both" LargeChange="0.1" Maximum="1" SmallChange="0.01" TickFrequency="0.02" Height="90" TabIndex="0" Value="{Binding A, Mode=TwoWay}"/>
        </Viewbox>
        <Viewbox HorizontalAlignment="Stretch" Grid.Row="2" Grid.Column="1"  VerticalAlignment="Stretch">
            <Slider Orientation="Vertical" TickPlacement="Both" LargeChange="0.1" Maximum="1" SmallChange="0.01" TickFrequency="0.02" Height="90" TabIndex="1" Value="{Binding R, Mode=TwoWay}"/>
        </Viewbox>
        <Viewbox HorizontalAlignment="Stretch" Grid.Row="2" Grid.Column="2"  VerticalAlignment="Stretch">
            <Slider Orientation="Vertical" TickPlacement="Both" LargeChange="0.1" Maximum="1" SmallChange="0.01" TickFrequency="0.02" Height="90" TabIndex="2" Value="{Binding G, Mode=TwoWay}"/>
        </Viewbox>
        <Viewbox HorizontalAlignment="Stretch" Grid.Row="2" Grid.Column="3"  VerticalAlignment="Stretch">
            <Slider Orientation="Vertical" TickPlacement="Both" LargeChange="0.1" Maximum="1" SmallChange="0.01" TickFrequency="0.02" Height="90" Value="{Binding B, Mode=TwoWay}"/>
        </Viewbox>
    </Grid>
</UserControl>

我将标签的画笔颜色绑定到视图模型中它们各自的颜色(A 得到了全部内容)。我双向将每个滑块的值绑定到视图模型中的相应值,并且在代码中我将依赖属性绑定到视图模型的颜色属性。我对此进行了测试,它确实有效。

再次感谢大家的帮助。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-09-10
    • 2013-12-10
    • 1970-01-01
    • 1970-01-01
    • 2013-01-14
    • 2012-12-23
    • 1970-01-01
    相关资源
    最近更新 更多