Posted by: Zeeshan Amjad | January 22, 2010

MVVM Patterns using Dependency Property


We have already seen the example of using MVVM using INotifyPropertyChange interface. But we can do the same thing with dependency property. Here is our same model class, but this time instead of implementing INotifyPropertyChange interface, we are going to make its properties dependency properties. Here is a piece of code to make these properties as Dependency Property.

  1: public class Numbers : DependencyObject
  2: {
  3:     public static readonly DependencyProperty FirstNoProperty =
  4:         DependencyProperty.Register("FirstNo", typeof(int), typeof(Numbers));
  5: 
  6:     public static readonly DependencyProperty SecondNoProperty =
  7:         DependencyProperty.Register("SecondNo", typeof(int), typeof(Numbers));
  8: 
  9:     public static readonly DependencyProperty ResultProperty =
 10:         DependencyProperty.Register("Result", typeof(int), typeof(Numbers));
 11: 
 12:     public static readonly DependencyProperty ResultLabelProperty =
 13:         DependencyProperty.Register("ResultLabel", typeof(String), typeof(Numbers));
 14: 
 15:     public int FirstNo
 16:     { 
 17:         get { return (int)GetValue(FirstNoProperty); }
 18:         set { SetValue(FirstNoProperty, value); }
 19:     }
 20: 
 21:     public int SecondNo
 22:     { 
 23:         get { return (int)GetValue(SecondNoProperty); }
 24:         set { SetValue(SecondNoProperty, value); }
 25:     }
 26: 
 27:     public String ResultLabel
 28:     { 
 29:         get { return (String)GetValue(ResultLabelProperty); }
 30:         set { SetValue(ResultLabelProperty, value); }
 31:     }
 32: 
 33:     public int Result
 34:     { 
 35:         get { return (int)GetValue(ResultProperty); }
 36:         set { SetValue(ResultProperty, value); }
 37:     }
 38: }
 39: 

Rest of the program is same as previous program. Here is a complete XAML code of our program.

  1: <Window x:Class="WpfCommandBinding.Window1"
  2:     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  3:     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  4:     xmlns:local="clr-namespace:WpfCommandBinding"
  5:     Title="MVVM" Height="200" Width="300">
  6:     <Grid Name="grid" Background="Wheat">
  7:         <Grid.ColumnDefinitions>
  8:             <ColumnDefinition/>
  9:             <ColumnDefinition/>
 10:         </Grid.ColumnDefinitions>
 11:         <Grid.RowDefinitions>
 12:             <RowDefinition/>
 13:             <RowDefinition/>
 14:             <RowDefinition/>
 15:             <RowDefinition/>
 16:         </Grid.RowDefinitions>
 17:         <TextBlock Grid.Column="0" Grid.Row="0" Margin="5"
 18:                    VerticalAlignment="Center" Text="Enter first number"/>
 19:         <TextBox Grid.Column="1" Grid.Row="0" Margin="5" 
 20:                  VerticalAlignment="Center" Text="{Binding Path=Numbers.FirstNo}"/>
 21:         <TextBlock Grid.Column="0" Grid.Row="1" Margin="5"
 22:                    VerticalAlignment="Center" Text="Enter second number"/>
 23:         <TextBox Grid.Column="1" Grid.Row="1" Margin="5" 
 24:                    VerticalAlignment="Center" Text="{Binding Path=Numbers.SecondNo}"/>
 25:         <TextBlock Grid.Column="0" Grid.Row="2" Margin="5"
 26:                    VerticalAlignment="Center" Text="{Binding Path=Numbers.ResultLabel}"/>
 27:         <TextBlock Grid.Column="1" Grid.Row="2" Margin="5"
 28:                    VerticalAlignment="Center" Text="{Binding Path=Numbers.Result}"/>
 29:         <Button Grid.Column="0" Grid.Row="3" Margin="5" 
 30:                 Content="GCD" Command="{Binding CalculateGCDCommand}"/>
 31:         <Button Grid.Column="1" Grid.Row="3" Margin="5" 
 32:                 Content="LCM" Command="{Binding CalculateLCMCommand}"/>        
 33:     </Grid>
 34: </Window>
 35: 

Here is complete C# code of program.

  1: using System;
  2: using System.Collections.Generic;
  3: using System.Linq;
  4: using System.Text;
  5: using System.Windows;
  6: using System.Windows.Controls;
  7: using System.Windows.Data;
  8: using System.Windows.Documents;
  9: using System.Windows.Input;
 10: using System.Windows.Media;
 11: using System.Windows.Media.Imaging;
 12: using System.Windows.Navigation;
 13: using System.Windows.Shapes;
 14: using System.ComponentModel;
 15: 
 16: namespace WpfCommandBinding
 17: {
 18:     /// <summary>
 19:     /// Interaction logic for Window1.xaml
 20:     /// </summary>
 21:     public partial class Window1 : Window
 22:     {
 23:         private Numbers nos = new Numbers();
 24: 
 25:         public Window1()
 26:         {
 27:             InitializeComponent();
 28: 
 29:             DataContext = new MyViewModel();
 30:         }
 31:     }
 32: 
 33:     public class MyViewModel : INotifyPropertyChanged
 34:     {
 35:         private Numbers _numbers;
 36:         public event PropertyChangedEventHandler PropertyChanged;
 37: 
 38:         public MyViewModel()
 39:         {
 40:             _numbers = new Numbers();
 41:             CalculateGCDCommand = new MyCommand(CalculateGCD);
 42:             CalculateLCMCommand = new MyCommand(CalculateLCM);
 43:         }
 44: 
 45:         public Numbers Numbers
 46:         {
 47:             get
 48:             {
 49:                 return _numbers;
 50:             }
 51:             set
 52:             {
 53:                 _numbers = value;
 54:                 RaisePropertyChanged("Numbers");
 55:             }
 56:         }
 57: 
 58:         private void RaisePropertyChanged(string propertyName)
 59:         {
 60:             PropertyChangedEventHandler handler = this.PropertyChanged;
 61: 
 62:             if (handler != null)
 63:             {
 64:                 handler(this, new PropertyChangedEventArgs(propertyName));
 65:             }
 66:         }
 67: 
 68:         public ICommand CalculateGCDCommand
 69:         { get; set; }
 70: 
 71:         public ICommand CalculateLCMCommand
 72:         { get; set; }
 73: 
 74:         private int CalculateGCD()
 75:         {
 76:             int x = Numbers.FirstNo;
 77:             int y = Numbers.SecondNo;
 78: 
 79:             Numbers.Result = CalculateGCDInternal(x, y);
 80:             Numbers.ResultLabel = "GCD";
 81: 
 82:             return Numbers.Result;
 83:         }
 84: 
 85:         private int CalculateGCDInternal(int x, int y)
 86:         {
 87:             if (x == 0)
 88:                 return 0;
 89: 
 90:             while (y != 0)
 91:             {
 92:                 if (x > y)
 93:                     x = x - y;
 94:                 else
 95:                     y = y - x;
 96:             }
 97: 
 98:             return x;
 99:         }
100: 
101:         private int CalculateLCM()
102:         {
103:             int x = Numbers.FirstNo;
104:             int y = Numbers.SecondNo;
105: 
106:             int lcm = x * y / CalculateGCDInternal(x, y);
107: 
108:             Numbers.Result = lcm;
109:             Numbers.ResultLabel = "LCM";
110:             return lcm;
111:         }
112:     }
113: 
114:     public class MyCommand : ICommand
115:     {
116:         public Func<int> Function
117:         { get; set; }
118: 
119:         public MyCommand()
120:         {
121:         }
122: 
123:         public MyCommand(Func<int> function)
124:         {
125:             Function = function;
126:         }
127: 
128:         public bool CanExecute(object parameter)
129:         {
130:             if (Function != null)
131:             {
132:                 return true;
133:             }
134: 
135:             return false;
136:         }
137: 
138: 
139:         public void Execute(object parameter)
140:         {
141:             if (Function != null)
142:             {
143:                 Function();
144:             }
145:         }
146: 
147:         public event EventHandler CanExecuteChanged
148:         {
149:             add { CommandManager.RequerySuggested += value; }
150:             remove { CommandManager.RequerySuggested -= value; }
151:         }
152:     }
153: 
154:     public class Numbers : DependencyObject
155:     {
156:         public static readonly DependencyProperty FirstNoProperty =
157:             DependencyProperty.Register("FirstNo", typeof(int), typeof(Numbers));
158: 
159:         public static readonly DependencyProperty SecondNoProperty =
160:             DependencyProperty.Register("SecondNo", typeof(int), typeof(Numbers));
161: 
162:         public static readonly DependencyProperty ResultProperty =
163:             DependencyProperty.Register("Result", typeof(int), typeof(Numbers));
164: 
165:         public static readonly DependencyProperty ResultLabelProperty =
166:             DependencyProperty.Register("ResultLabel", typeof(String), typeof(Numbers));
167: 
168:         public int FirstNo
169:         { 
170:             get { return (int)GetValue(FirstNoProperty); }
171:             set { SetValue(FirstNoProperty, value); }
172:         }
173: 
174:         public int SecondNo
175:         { 
176:             get { return (int)GetValue(SecondNoProperty); }
177:             set { SetValue(SecondNoProperty, value); }
178:         }
179: 
180:         public String ResultLabel
181:         { 
182:             get { return (String)GetValue(ResultLabelProperty); }
183:             set { SetValue(ResultLabelProperty, value); }
184:         }
185: 
186:         public int Result
187:         { 
188:             get { return (int)GetValue(ResultProperty); }
189:             set { SetValue(ResultProperty, value); }
190:         }
191:     }
192: }
193: 

Here is the output of the program when we click on the GCD.

MVVM_Output_01

And here is the output of the program when click on LCM.

MVVM_Output_02


Responses

  1. […] Depreciation using MVVM Pattern We have already discussed one example of MVVM pattern here and here. In that example there is only one class for data. In other words […]

  2. […] encoding using MVVM We have already saw few example of MVVM here and here. But in both example we were using the Func class to implement the ICommand interface. Now […]

  3. Thanks for this nice Tutorial !
    was very helpful for me.

  4. … would be helpful if you could post the getValue / setValue Methods – i don’t know where to implement them (see property setters)

    • May be i didn’t understand your question. I didn’t implement GetValue and SetValue methods. These methods are in fact in DependencyObject class. When we inherit class from DependencyObject (One basic requirement to create dependency properties) then we automatically get these methods.

  5. Hi!

    Thanks for this post. I have a question. What concerns me, is that if we really should mix very UI specific mechanisms, like DependencyProperties, with your model?

    I think the point to surface a model, which consists of POCOs, to a view with properties on a viewmodel, that has an ability to notify any changes to the view. Moreover, I think the only place where you should be using DependencyPropeties is the view.

    Do you have any convincing arguments for following your way?

    Regards,
    macqm

    • Hi

      Thanks to like this. Yes i understand your concern and you have a valid point that dependency property should be related to UI. In this post i justed wanted to show that theoritically it is possible to use the notification in two ways, one is INotifyPropertyChanged interface (which i discussed in another post) and other is dependency property, which i discussed here. In fact in few of my posts when i created a base class for ViewModel i used the INotifyPropertyChanged interface not dependency property.

      Thanks to bring this on to avoid any confusion for future reader of this article.

      Regards
      Zeeshan Amjad

      • Hi Zeeshan,

        I like your article. Very interresting.
        Regarding your answer to macqm, I think that the main advantage of DependencyProperty over INPC interface is for creating userControl to make dataBinding easier.

        But I have a concern… probably due to my ignorance, I wonder if there is anything that would’nt work properly if the propertyObject is defined in the model instead of directly under the control itself. There wouldn’t be a link between the dp and it’s parent control ???

        Regards,
        Eric

      • Hi Eric

        Thanks to like my article and thinks for giving more clear and indepth answer to macqm. I came across an interesting article that discuss the same issue in more depth. View Models: POCOs versus DependencyObjects. I hope you find it interesting too.

        Regards
        Zeeshan Amjad

  6. Thanks Zeeshan,

    After reading part of the link I was a bit shock…
    I’m crude but I think that Boogart has few things wrong…
    Too me it is simple, DPs for every property of userControl, otherwise we should use INotifyPropertyChange (many reasons explain that but it will be too long too explain).
    Also, View Model inheritance, too me, is a non-sense. And more…
    But i’m not sure i’m right..
    Thanks for your help and your article and good luck !

  7. Ho also, if the DP is not in the userControl (ie in the viewModel) then you would not be able to bind to it (either through VS designer or code).

  8. Is it interesting use the Dependency Properties also on ViewModel Layer? Or just in Model layer? Your website is incredible… Congrats…

    • Thanks for visiting and like my blog. Usually dependency property is not used in Models. Model usually implement INotifyPropertyChanged interface. Dependency property is usually more useful in UserControl.

  9. Hello,
    I would like to add other property in ViewModel with RaisePropertyChanged.
    How can I track changes on dependencyProperty and binding to other property(‘Result’ with other property ‘VmProp’)?

    View :

    VM:

    public int VmProp
    {
    get { return vmProp; }
    set
    {
    vmProp = value;
    RaisePropertyChanged(“VmProp”);
    }
    }


Leave a comment

Categories