LittleMygler
LittleMygler

Reputation: 632

Rectangle not changing color WPF

I'm trying to make my rectangle change color depending on my tree sliders. B,R and G.

Code flow: Sliders have bindings to the colorClass witch set's the g,r and b values depending on the slides.

Whenever one of these props changes it calls an event to update the resultcolor The rectangles color is set by the resultcolor

So in the theory when you drag the slider the rectangle should switch color. But it doesn't

I get this error.

System.Windows.Data Error: 5 : Value produced by BindingExpression is not valid for target property.; Value='#FF0000FF' BindingExpression:Path=Result; DataItem='VM' (HashCode=64479624); target element is 'Rectangle' (Name=''); target property is 'Fill' (type 'Brush')

Here is my XAML:

    <Label VerticalAlignment="Center" HorizontalAlignment="Center" Grid.Row="1" Grid.Column="0" FontSize="24">R</Label>
    <Slider Maximum="255" Name="RSlider" VerticalAlignment="Center" Grid.Row="1" Grid.Column="1" Value="{Binding Path=RedValue, Mode=TwoWay}"></Slider>
    <TextBox PreviewTextInput="NumberValidationTextBox" Grid.Row="1" Grid.Column="2" Height="auto" Text="{Binding Path=RedValue, Mode=TwoWay}"></TextBox>

    <Label VerticalAlignment="Center" HorizontalAlignment="Center" Grid.Row="2" Grid.Column="0" FontSize="24">G</Label>
    <Slider Maximum="255" Name="GSlider" VerticalAlignment="Center" Grid.Row="2" Grid.Column="1" Value="{Binding Path=GreenValue, Mode=TwoWay}"></Slider>
    <TextBox PreviewTextInput="NumberValidationTextBox" Grid.Row="2" Grid.Column="2" Text="{Binding Path=GreenValue, Mode=TwoWay}"></TextBox>

    <Label VerticalAlignment="Center" HorizontalAlignment="Center" Grid.Row="3" Grid.Column="0" FontSize="24">B</Label>
    <Slider Maximum="255" Name="BSlider" VerticalAlignment="Center" Grid.Row="3" Grid.Column="1" Value="{Binding Path=Color.BlueValue, Mode=TwoWay}"></Slider>
    <TextBox PreviewTextInput="NumberValidationTextBox" Grid.Row="3" Grid.Column="2" Text="{Binding Path=Color.BlueValue, Mode=TwoWay}"></TextBox>

    <Rectangle Grid.Column="3" Grid.Row="1" Grid.RowSpan="3" Fill="{Binding Path=Result}"></Rectangle>

I have a color class that is going to be saved in a database. It has 3 int props B,G and R. Here is the class:

 public class ColorModel : INotifyPropertyChanged
{
    private int _GreenValue;
    private int _RedValue;
    private int _BlueValue;

    public int GreenValue
    {
        get { return _GreenValue; }
        set
        {
            if (_GreenValue != value)
            {
                _GreenValue = value;
                if (PropertyChanged != null)
                {
                    PropertyChanged(this, new PropertyChangedEventArgs("GreenValue"));
                }
            }
        }
    }


    public int RedValue
    {
        get { return _RedValue; }
        set
        {
            if (_RedValue != value)
            {
                _RedValue = value;
                PropertyChanged(this, new PropertyChangedEventArgs("RedValue"));
            }
        }
    }


    public int BlueValue
    {
        get { return _BlueValue; }
        set
        {
            if (_BlueValue != value)
            {
                _BlueValue = value;
                PropertyChanged(this, new PropertyChangedEventArgs("BlueValue"));
            }
        }
    }

    public Color GetColor()
    {
        Color result = new Color();
        result = Color.FromScRgb(1, RedValue, GreenValue, BlueValue);

        return result;
    }

    public event PropertyChangedEventHandler PropertyChanged;
}

The GetColor Method just converts the 3 int properties to a color. Then i have a ViewModel, with 2 props 1 is this color class and one is a color (The result color) this property is the one that I want my rectangle to get it's color from.

Main Code:

        public ColorModel Col;

    public MainWindow()
    {
        InitializeComponent();
        Col = new ColorModel();
        var VM = new VM();
        VM.Color = Col;
        this.DataContext = VM;
    }

And if it helps, here is the ViewModel.

public class VM : INotifyPropertyChanged
{
    private ColorModel _Color { get; set; }
    public Color Result { get; set; }

    public ColorModel Color
    {
        get { return _Color; }
        set
        {
            _Color = value;
            Result = _Color.GetColor();

            _Color.PropertyChanged += _Color_PropertyChanged;

            if(PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs("Result"));

            }

        }
    }

    private void _Color_PropertyChanged(object sender, PropertyChangedEventArgs e)
    {

        Result = _Color.GetColor();
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs("Result"));

        }
    }

    public event PropertyChangedEventHandler PropertyChanged;
}

I'm really grateful for every answer! I'm new to WPF.

Upvotes: 2

Views: 693

Answers (2)

Clemens
Clemens

Reputation: 128060

The type of the Fill property is Brush, not Color.

You could use a SolidColorBrush like this:

<Rectangle ...>
    <Rectangle.Fill>
        <SolidColorBrush Color="{Binding Result}"/>
    </Rectangle.Fill>
</Rectangle>

Besides that, you could as well move the Result property to your ColorModel class, and bind to it in the same way you bind the Slider Values. You would thus avoid the complicated PropertyChanged event handling in the view model.

<SolidColorBrush Color="{Binding Color.Result}"/>

The ColorModel would look like this:

public class ColorModel : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    private void OnPropertyChanged(string propertyName)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }

    private int red;
    private int green;
    private int blue;

    public int RedValue
    {
        get { return red; }
        set
        {
            if (red != value)
            {
                red = value;
                OnPropertyChanged(nameof(RedValue));
                OnPropertyChanged(nameof(Result));
            }
        }
    }

    public int GreenValue
    {
        get { return green; }
        set
        {
            if (green != value)
            {
                green = value;
                OnPropertyChanged(nameof(GreenValue));
                OnPropertyChanged(nameof(Result));
            }
        }
    }

    public int BlueValue
    {
        get { return blue; }
        set
        {
            if (blue != value)
            {
                blue = value;
                OnPropertyChanged(nameof(BlueValue));
                OnPropertyChanged(nameof(Result));
            }
        }
    }

    public Color Result
    {
        get
        {
            return Color.FromRgb((byte)red, (byte)green, (byte)blue);
        }
    }
}

Upvotes: 2

Peregrine
Peregrine

Reputation: 4546

Rectangle.Fill is a Brush object, not a Color.

You need to add an IValueConverter class that will convert between your ViewModel property and a SolidColorBrush instance.

public class ColorToSolidColorBrushConverter: IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        if (value is Color color)
            return new SolidColorBrush(color);

        return DefaultValue;
    }

    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        var brush = value as SolidColorBrush;
        return brush?.Color;
    }

    public SolidColorBrush DefaultValue { get; } = Brushes.Fuchsia;
}

Usage

<Window ...>
    <Window.Resources>
        <ColorToSolidColorBrushConverter x:Key="ColorToSolidColorBrushConverter" />
    </Window.Resources>

...

<Rectangle Grid.Column="3" Grid.Row="1" Grid.RowSpan="3" Fill="{Binding Path=Result, Converter={StaticResource ColorToSolidColorBrushConverter}"></Rectangle>

Upvotes: 2

Related Questions