holland
holland

Reputation: 2182

WPF bind command to colorpicker

To begin with, in my application I'm using the Extended WPF Toolkit ColorPicker.

On a canvas I draw several rectangles based on a deserialized XML file (this works well). For each drawn rectangle, I add a ColorPicker so that the user of the app can change the color of the rectangle. I tried working with implementing the ICommand interface but the colorpicker doesn't seem to support binding custom commands, so I'm sort of stuck and don't really know what to do. Here's my current code:

<ItemsControl Name="inputs2">
      <ItemsControl.ItemTemplate>
      <DataTemplate>
      <Grid Name="testgrid" Margin="0,0,0,5">
      <Grid.ColumnDefinitions>
           <ColumnDefinition Width="*" />
           <ColumnDefinition Width="*" />
           </Grid.ColumnDefinitions>

           <TextBlock HorizontalAlignment="Left" Grid.Column="0" Text="{Binding Title}" />
           <xctk:ColorPicker HorizontalAlignment="Left" 
                             Grid.Column="1" 
                             Name="ClrPcker_Background" 
                             SelectedColor="{Binding Color}" 

                           <!--tryig to bind here???-->
            />
       </Grid>
       </DataTemplate>
       </ItemsControl.ItemTemplate>
</ItemsControl> 

My C#

internal class BackgroundInput
{
    public BackgroundInput()
    {
    }

    public string Color { get; set; }
    public string Title { get; set; }
}

part two:

public override void Draw(Canvas label)
{
    Rectangle rect = new Rectangle();
    //...... drawing method
    label.Children.Add(rect );
}

internal override void AddInputs(ItemsControl inputPanel)
{
    inputPanel.Items.Add(new BackgroundInput() { Title = "Backgroundcolor:", Color = BackgroundColor });        
}
//both methods get called

So whenever the color of the ColorPicker gets changed, I want the connected rectangle to update it's background color. ColorPicker doesn't seem to support Command="..." and CommandParameter="..." to send data so I would like to have advice on how to do this. Thanks!

Edit

A small example of what I have right now. I'm trying to change the color if the user changes the color of the color picker.

enter image description here

EDIT

I sort of got it working but I don't think this is the right way. Here's my updated code:

internal class BackgroundInput
{
    private string _bg;
    public BackgroundInput()
    {
    }

    public Box Box { get; internal set; }

    public string Color
    {
        get { return _bg; }
        set { _bg = value; Box.BackgroundColor = _bg; Box.redraw(); }
    }

    public string Title { get; set; }
}

the rectangle code:

public class Box : Field
{
      Canvas label;
    Border _border;

    public override void Draw(Canvas label)
    {
        _border = new Border();
        _label = label;
        Rectangle x= new Rectangle ();

        label.Children.Add(x);
    }

    internal override void AddInputs(ItemsControl inputPanel)
    {
        inputPanel.Items.Add(new BackgroundInput() { Title = "Background:", Box = this, Color = BackgroundColor });           
    }   

    public void redraw()
    {
        _label.Children.Remove(_label);
        Draw(_label);
    }
}

Upvotes: 0

Views: 1812

Answers (1)

Mat
Mat

Reputation: 2072

I highly recommend you to use the MVVM pattern. I guess you have a list of objects that you want to draw on a layout panel (in that case a canvas).

First thing you need is a ViewModel. It will represent one instance of a Rectangle:

public class MyRectangleViewModel : INotifyPropertyChanged
{
    private Color _background;
    public Color Background
    {
        get
        {
            return _background;
        }
        set
        {
            _background = value;
            OnPropertyChanged();
        }
    }

    /// <summary>
    /// Occurs when [property changed].
    /// </summary>
    public event PropertyChangedEventHandler PropertyChanged;

    private void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}

Please note the INotifiyPropertyChanged interface. This will add the "WPF binding magic". Each time the property is changed the PropertyChanged event is fired. There are tons of tutorials and examples on SO and the web....

Than you could use an ItemsControl or similar and bind all your items to the ItemsSource.

Anyway. It looks like you want to create all your Elements in code (for whatever reason). So here you have a code behind solution #ItGivesMeTheCreeps:

/// <summary>
/// All my recangles
/// </summary>
private ObservableCollection<MyRectangleViewModel> AllMyRecangles = new ObservableCollection<MyRectangleViewModel>();
/// <summary>
/// Call this method if you add/remove objects to your list.
/// </summary>
public void RefreshObjects()
{
    this.myCanvas.Children.Clear();

    foreach (MyRectangleViewModel item in AllMyRecangles)
    {
        Rectangle newRectangle = new Rectangle();

        //set the DataContext
        newRectangle.DataContext = item;

        //create the binding
        Binding b = new Binding();
        b.Source = item;
        b.Path =new PropertyPath(nameof(Background));
        b.Mode = BindingMode.TwoWay;
        b.UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged;

        //setup the binding XAML: <Rectangle Fill = {Binding Path="Background", Mode=TwoWay, UpdateSourceTrigger ="PropertyChanged" />
        BindingOperations.SetBinding(newRectangle, Rectangle.FillProperty, b);


        //add the rectangle to the canvas
        myCanvas.Children.Add(newRectangle);
    }
}

Upvotes: 1

Related Questions