1

I'm currently writing a program for drawing class diagrams, and I'm using the MVVM pattern. My classes' width and height in the user interface is set to auto, as I let the containing elements define the size.

Problem is that I need the width and the height in my model to do some calculations, so I need a reverse binding or something to update the properties in my model, which I don't know much about. How do I do this?

I tried this, but didn't work:

XAML:

Width="{Binding Width, Mode=OneWayToSource}" Height="{Binding Height,
Mode=OneWayToSource}">

C#

private int width;
    public int Width {
        get { return width; }
        set {
            width = value;
        }
    }
    private int height;
    public int Height {
        get { return height; }
        set {
            height = value;
        }
    }
Jacob Schoen
  • 14,034
  • 15
  • 82
  • 102
Reppien
  • 125
  • 6

4 Answers4

1

What you have there should correctly update your width and height member variables when you resize whatever element the XAML is pointing to.

If you also want to update the values in code and have that reflected in your XAML element, you will need INotifyPropertyChanged and TwoWay binding. You could also use dependency properties, but you probably don't want to do that in ViewModel code.

Edit: Per my comment below, it appears that you wanted to bind to the ActualWidth and ActualHeight properties. MS Silverlight documentation states:

For purposes of ElementName binding, ActualWidth does not post updates when it changes (due to its asynchronous and run-time calculated nature). Do not attempt to use ActualWidth as a binding source for an ElementName binding. If you have a scenario that requires updates based on ActualWidth, use a SizeChanged handler.

The .NET Framework 4.5 documentation does not state the same caveat, but it seems to be implied for ReadOnly DP's. I have also seen workarounds for this online using Triggers in XAML. See the discussion following the accepted answer here. This discussion suggests that MS have no intention of fixing this issue with ReadOnly DP's.

Community
  • 1
  • 1
AJ.
  • 1,621
  • 1
  • 10
  • 23
  • Thanks a lot for steering me in the right direction. I found the solution [here](http://stackoverflow.com/questions/1083224/pushing-read-only-gui-properties-back-into-viewmodel), and now it's finally working. – Reppien Nov 24 '12 at 18:03
  • Good you found the solution and I've been interested to read that too so thanks for posting the link as a comment. Sorry I couldn't be more specific with the answer in the first place! – AJ. Nov 25 '12 at 15:13
0

Edited:

There are 3 things which you might have to do.

  1. Your class (model or view model where Width and Height properties are defined) needs to implement INotifyPropertyChanged interface.

  2. You also need two way binding, since you wanted to set Width/Height from code as well as capture it from the user.

  3. You need to bind with the ActualWidth and ActualHeight - What is the difference between Width and ActualWidth in WPF?

More info on INotifyPropertyChanged - http://msdn.microsoft.com/en-us/library/ms743695.aspx

Community
  • 1
  • 1
  • It already implements INotifyPropertyChanged. And i don't need to set Width/Height from code, these are set to auto, so that when the containing elements grow, so do the container. I just need my model to change its properties when the view's auto-width and auto-height changes. – Reppien Nov 20 '12 at 18:38
  • 1
    Your sample code does *not* implement INotifyPropertyChanged. It sounds to me like you need to be binding to ActualWidth and ActualHeight rather than Width and Height. – AJ. Nov 20 '12 at 18:50
  • I think you're right, but since ActualWidth and ActualHeight is readonly, i can't bind to it with the syntax ActualWidth="{Binding Width}" Mode="OneWayToSource". – Reppien Nov 20 '12 at 22:19
  • 1
    From some further research, this seems to be by design. I've updated my answer with a couple of links. – AJ. Nov 21 '12 at 10:20
0

Make sure that your view-model is set as the DataContext of your view. You'll need to implement INotifyPropertyChanged in your view-model. Then, update your properties to look like this:

    public int Width 
    {
        get { return width; }
        set 
          {
            if(width != value)
              {
                 width = value;
                 NotifyPropertyChanged();
              }
          }
    }
Big Daddy
  • 5,160
  • 5
  • 46
  • 76
0

You can try with

ActualWidth="{Binding Width, Mode=OneWayToSource}" ActualHeight="{Binding Height,
Mode=OneWayToSource}">

But this code may not work everytime as atual width and height are not available until UI is rendered.

Or you may create the dependency property in VM and bind it with width and height with Mode=OneWay. But your frame work should support this as you are using MVVM.

D J
  • 6,908
  • 13
  • 43
  • 75