1

I'm trying to bind the SelectedColor property of the WPF Extended Toolkit ColorPicker to a DependencyProperty with type SolidColorBrush. This color is then supposed to be used as the Fill color of a Shape sitting on/in a Canvas.

This isn't working, and as I understand it, the problem is that the SelectedColor property of the ColorPicker is actually an object with type Color?. My question is, how do I get this to work? If I just do it in code through a method hooked up to an event, I can use SelectedColor.Value, but AFAIK that isn't as option in XAML.

I did try to use a regular property and have the class inherit from INotifyPropertyChanged (as in SelectedColor binding doesn't update from ColorPicker to Model), rather than from DependencyObject, but that didn't work either.

I'd prefer to do this with Binding, as I'm trying to get more in the practice of using MVVM. I've only recently learned how to use MVVM, and I actually prefer it now, so I'd really like avoid just using code-behind.

XAML:

    <toolkit:ColorPicker x:Name="fillColor" Grid.Column="1" Grid.Row="8" Margin="5" VerticalAlignment="Top" SelectedColor="{Binding Path=FillColor, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" SelectedColorChanged="fillColor_SelectedColorChanged" />
    <toolkit:ColorPicker x:Name="lineColor" Grid.Column="2" Grid.Row="8" Margin="5" VerticalAlignment="Top" />

C#: private static DependencyProperty FillColorProperty = DependencyProperty.Register("FillColor", typeof(SolidColorBrush), typeof(TuckboxModel), new FrameworkPropertyMetadata(Brushes.Purple));

    private static DependencyProperty LineColorProperty = DependencyProperty.Register("LineColor", typeof(SolidColorBrush),
        typeof(TuckboxModel), new FrameworkPropertyMetadata(Brushes.Black));

public SolidColorBrush FillColor
    {
        get { return (SolidColorBrush)GetValue(FillColorProperty); }
        set
        {
            SetValue(FillColorProperty, value);
        }
    }

    public SolidColorBrush LineColor
    {
        get { return (SolidColorBrush)GetValue(LineColorProperty); }
        set { SetValue(LineColorProperty, value); }
    }

public void CreateBox(Canvas drawingCanvas, TuckboxModel model, double width, double height, double depth, SolidColorBrush shading, SolidColorBrush outline)
    {
        double xOrigin = 50;
        double yOrigin = 450;

        double xCoord = xOrigin;
        double yCoord = yOrigin;
        Shape item;
        double flapSize;
        long count;

        //Remove all previous shapes from Canvas
        drawingCanvas.Children.Clear();

        Path border = new Path();
        border.Stroke = model.LineColor;
        border.StrokeThickness = 1.0;            
        border.Fill = model.FillColor;
        //border.Fill = shading;

        yCoord -= ToPts(depth);
        xCoord += ToPts(depth);

        RectangleGeometry rectangleA = new RectangleGeometry();
        Rect rectA = new Rect(xCoord, yCoord, ToPts(width), ToPts(depth));
        rectangleA.Rect = rectA;

        xCoord += ToPts(width);

        RectangleGeometry rectangleB = new RectangleGeometry();
        Rect rectB = new Rect(xCoord + 3, yCoord, ToPts(depth) - 5, ToPts(depth));
        rectangleB.Rect = rectB;

        xCoord += ToPts(depth);

        RectangleGeometry rectangleC = new RectangleGeometry();
        Rect rectC = new Rect(xCoord + 2, yCoord, ToPts(width) - 4, ToPts(depth) - 2);
        rectangleC.Rect = rectC;

        xCoord += ToPts(width);

        RectangleGeometry rectangleD = new RectangleGeometry();
        Rect rectD = new Rect(xCoord + 2, yCoord, ToPts(depth) - 5, ToPts(depth));
        rectangleD.Rect = rectD;

        xCoord = xOrigin;
        yCoord -= ToPts(height);

        RectangleGeometry rectangleE = new RectangleGeometry();
        Rect rectE = new Rect(xCoord, yCoord, ToPts(depth), ToPts(height));
        rectangleE.Rect = rectE;

        xCoord += ToPts(depth);

        RectangleGeometry rectangleF = new RectangleGeometry();
        Rect rectF = new Rect(xCoord, yCoord, ToPts(width), ToPts(height));
        rectangleF.Rect = rectF;

        xCoord += ToPts(width);

        RectangleGeometry rectangleG = new RectangleGeometry();
        Rect rectG = new Rect(xCoord, yCoord, ToPts(depth), ToPts(height));
        rectangleG.Rect = rectG;

        xCoord += ToPts(depth);

        RectangleGeometry rectangleH = new RectangleGeometry();
        Rect rectH = new Rect(xCoord, yCoord, ToPts(width), ToPts(height));
        rectangleH.Rect = rectH;

        xCoord += ToPts(width);

        RectangleGeometry rectangleI = new RectangleGeometry();
        Rect rectI = new Rect(xCoord, yCoord, ToPts(depth) - 3, ToPts(height));
        rectangleI.Rect = rectI;

        xCoord = xOrigin;
        yCoord -= ToPts(depth);

        RectangleGeometry rectangleJ = new RectangleGeometry();
        Rect rectJ = new Rect(xCoord + 1, yCoord, ToPts(depth) - 2, ToPts(depth));
        rectangleJ.Rect = rectJ;

        xCoord += ToPts(depth);

        RectangleGeometry rectangleK = new RectangleGeometry();
        Rect rectK = new Rect(xCoord, yCoord, ToPts(width), ToPts(depth));
        rectangleK.Rect = rectK;

        xCoord += ToPts(width);

        RectangleGeometry rectangleL = new RectangleGeometry();
        Rect rectL = new Rect(xCoord + 1, yCoord, ToPts(depth) - 2, ToPts(depth));
        rectangleL.Rect = rectL;            

        EllipseGeometry ellipseA = new EllipseGeometry();
        ellipseA.Center = new Point(rectK.Right - (rectK.Width / 2), yCoord);
        ellipseA.RadiusX = rectK.Width / 2;

        if(height < 1.0)
            flapSize = ToPts(height);
        else
            flapSize = 72;

        ellipseA.RadiusY = flapSize;

        GeometryGroup finalShape = new GeometryGroup();
        finalShape.Children.Add(rectangleA);
        finalShape.Children.Add(rectangleB);
        finalShape.Children.Add(rectangleC);
        finalShape.Children.Add(rectangleD);
        finalShape.Children.Add(rectangleE);
        finalShape.Children.Add(rectangleF);
        finalShape.Children.Add(rectangleG);

        finalShape.Children.Add(rectangleH);
        finalShape.Children.Add(rectangleI);
        finalShape.Children.Add(rectangleJ);
        finalShape.Children.Add(rectangleK);
        finalShape.Children.Add(rectangleL);
        finalShape.Children.Add(ellipseA);

        finalShape.FillRule = FillRule.Nonzero;

        border.Data = finalShape;

        drawingCanvas.Children.Add(border);
    }

Any help will be greatly appreciated!

Keven M
  • 914
  • 14
  • 39

1 Answers1

0

I think a Converter is an answer for your troubles. Here is an example of a converter class:

using System;
using System.Globalization;
using System.Windows.Data;

namespace SO_app.Converters
{
    public class DebugConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            if (null == value) {
                return null;
            }
            // For a more sophisticated converter, check also the targetType and react accordingly..
            if (value is Color) {
                Color color = (Color)value;
                return new SolidColorBrush(color);
            }
            // You can support here more source types if you wish
            // For the example I throw an exception

            Type type = value.GetType();
            throw new InvalidOperationException("Unsupported type ["+type.Name+"]");  
        }

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            return value;
        }
    }
}  

And then in your xaml it would look like this:
This is for my project:

xmlns:converter="clr-namespace:SO_app.Converters"

Then in resources:

<converter:DebugConverter x:Key="DebugConverter"/>

Then in xaml:

<toolkit:ColorPicker x:Name="fillColor" Grid.Column="1" Grid.Row="8" Margin="5" VerticalAlignment="Top" SelectedColor="{Binding Path=FillColor, Converter={StaticResource DebugConverter}, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" SelectedColorChanged="fillColor_SelectedColorChanged" />  

Note:
The code for conversion of types is from this SO post.
UPDATE:
Check this SO post which means that there is a built in converter in toolkit

XAMlMAX
  • 2,140
  • 1
  • 12
  • 21
  • I hadn't thought of that, but should have. I think this is definitely the answer, although it actually won't work in my case for a different reason. As I generate the Shape dynamically (and need to, as the whole application is a shape generator based on input dimensions), there's nowhere to put the binding to the converter. When I put the binding in the ColorPicker SelectedColor property, it fires the ConvertBack method. This i due to the "backwards" nature of Converter bindings (at least it seems backwards to me) where you bind in the control opposite the one you want to change. – Keven M Aug 15 '18 at 13:28
  • You could have a `SelectedShape` property, this would allow you to set it to currently selected Colour. – XAMlMAX Aug 16 '18 at 08:32
  • Which object would `SelectedShape` go onto? Like onto the dynamic shape? I'm interested in this approach, as I'd rather use the binding, but I'm not visualizing exactly what that would look like. – Keven M Aug 16 '18 at 12:52