Search code examples
c#wpfmvvmdependency-propertieswpf-extended-toolkit

Binding WPF Extended Toolkit ColorPicker SelectedColor Property to DependencyProperty


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!


Solution

  • 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