1

I'm currently doing some rescaling on data in a valueconverter whenever a panel is redrawn. I want to move some of this processing to the viewmodel as the most of the processing only occurs if the control size or a few other properties change.

To ensure the rescaled data looks acceptable I need the ActualWidth of the container in the viewmodel. I want to bind it to a property of the viewmodel one way so when it changes I can trigger the rescaling processing.

All the examples I could find bind a CLR or dependency property to an element rather than the other way and I'm clearly missing something in my understanding to work out how I should do it. I have have tried a few different things setting up the binding but am just not getting it right.

Any hints? thanks.

In MyView XAML:

<myItemsControl/>

In MyView code behind, something like:

Binding b = new Binding(MyWidthProperty);
b.Mode = BindingMode.OneWay;
b.Source = myItemsControl.Name;
.........?

and

public static readonly DependencyProperty MyWidthProperty = 
DependencyProperty.Register( "MyWidth", typeof(Double), typeof(MyViewModel));

In MyViewModel:

    public Double MyWidth{
        get { return _myWidth; }
        set { _myWidth = value; ViewChanged(this); } }
Dave Clemmer
  • 3,741
  • 12
  • 49
  • 72
DocGigawatts
  • 285
  • 6
  • 15
  • I would read a bit more about DependencyProperty. In particular, your object must be a DependencyObject and you must use the GetValue and SetValue methods to access the underlying value. Finally, you won't get a setter call when the DP is being accessed by the binding system (this is a point that's easy to miss), so you'll need to pass a Changed handler in as part of the Register call. – Dan Bryant Nov 15 '10 at 17:19

1 Answers1

2

You cannot do it this way. You cannot set a Binding to ActualWidth, as it's read-only.

You can only set a binding to MyWidth. But for this, you need first to convert MyWidth into a DependencyProperty. Then you will be able to do something like

Binding b = new Binding("ActualWidth") { Source = myItemsControl };
this.SetBinding(MyViewModel.MyWidthProperty, b);

For converting into a dependency property, you'll need to replace your definition of MyWidth with the following:

public static readonly DependencyProperty MyWidthProperty =
    DependencyProperty.Register("MyWidth", typeof(double), typeof(MyViewModel),
                                        new UIPropertyMetadata(
                                            0.0,
                                            (d, e) =>
                                            {
                                                var self = (MyViewModel)d;
                                                ViewChanged(self);
                                            }));

But be careful with dependency properties; it's better to read the documentation first.

Edit: You would also need to define the property this way:

public double MyWidth
{
    get { return (double)this.GetValue(MyWidthProperty); }
    set { this.SetValue(MyWidthProperty, value); } 
}
Vlad
  • 35,022
  • 6
  • 77
  • 199
  • Thanks for that very complete answer. Been avoiding dependency properties due to the nasty syntax whilst I made progress with the rest of WPF. First time I have been forced to use one... looks like I'd better get on top of them as I expect it will happen again. – DocGigawatts Nov 16 '10 at 19:12