Note that there are some explanatory texts on larger screens.

plurals
  1. POFat Models, skinny ViewModels and dumb Views, the best MVVM approach?
    primarykey
    data
    text
    <p>Through generous help on <a href="https://stackoverflow.com/questions/851595">this question</a>, I put together the following MVVM structure which displays the changes of a model in real time in XAML (current date/time), very nice.</p> <blockquote> <p>A cool advantage of this set up is that when you look at your view <em>in design mode</em> of Visual Studio or Blend, <em>you see the time ticking by</em>, which means that <em>at design time you have access to live data from your model.</em></p> </blockquote> <p>In the process of getting this to work, I was surprised to see <strong>most of the bulk move from my ViewModel into my Model</strong>, including implementation of INotifyPropertyChange. Another change is that I <strong>no longer bind to <em>properties</em> on the ViewModel but to <em>methods</em></strong>. </p> <p>So currently this is my favorite flavor of MVVM:</p> <ol> <li><p>View is dumb: </p> <ul> <li>one ObjectDataProvider for each object you need from your model</li> <li>each ObjectDataProvider maps to a method on the ViewModel (not a property)</li> <li>no x:Name properties in XAML elements</li> </ul></li> <li><p>ViewModel is skinny:</p> <ul> <li>the only thing in your ViewModel are the <em>methods</em> to which your view binds</li> </ul></li> <li><p>Model is fat:</p> <ul> <li>the model implements INotifyPropertyChanged on each of its properties.</li> <li>for every method on your ViewModel (e.g. GetCurrentCustomer) there is a corresponding <em>singleton method</em> in your Model (e.g. GetCurrentCustomer).</li> <li>the model takes care of any real time threading functionality as in this example</li> </ul></li> </ol> <p><strong>Questions:</strong></p> <ol> <li>Those of you who have been implementing MVVM in real scenarios, is this the basic structure you have also settled upon, and if not, how does yours vary?</li> <li>How would you extend this to include routed commands and routed events?</li> </ol> <p><em>The following code will work if you just copy the XAML and code behind into a new WPF project.</em></p> <p><strong>XAML:</strong></p> <pre><code>&lt;Window x:Class="TestBinding99382.Window1" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="clr-namespace:TestBinding99382" Title="Window1" Height="300" Width="300"&gt; &lt;Window.Resources&gt; &lt;ObjectDataProvider x:Key="DataSourceCustomer" ObjectType="{x:Type local:ShowCustomerViewModel}" MethodName="GetCurrentCustomer"/&gt; &lt;/Window.Resources&gt; &lt;DockPanel DataContext="{StaticResource DataSourceCustomer}"&gt; &lt;StackPanel DockPanel.Dock="Top" Orientation="Horizontal"&gt; &lt;TextBlock Text="{Binding Path=FirstName}"/&gt; &lt;TextBlock Text=" "/&gt; &lt;TextBlock Text="{Binding Path=LastName}"/&gt; &lt;/StackPanel&gt; &lt;StackPanel DockPanel.Dock="Top" Orientation="Horizontal"&gt; &lt;TextBlock Text="{Binding Path=TimeOfMostRecentActivity}"/&gt; &lt;/StackPanel&gt; &lt;/DockPanel&gt; &lt;/Window&gt; </code></pre> <p><strong>Code Behind:</strong></p> <pre><code>using System.Windows; using System.ComponentModel; using System; using System.Threading; namespace TestBinding99382 { public partial class Window1 : Window { public Window1() { InitializeComponent(); } } //view model public class ShowCustomerViewModel { public Customer GetCurrentCustomer() { return Customer.GetCurrentCustomer(); } } //model public class Customer : INotifyPropertyChanged { private string _firstName; private string _lastName; private DateTime _timeOfMostRecentActivity; private static Customer _currentCustomer; private Timer _timer; public string FirstName { get { return _firstName; } set { _firstName = value; this.RaisePropertyChanged("FirstName"); } } public string LastName { get { return _lastName; } set { _lastName = value; this.RaisePropertyChanged("LastName"); } } public DateTime TimeOfMostRecentActivity { get { return _timeOfMostRecentActivity; } set { _timeOfMostRecentActivity = value; this.RaisePropertyChanged("TimeOfMostRecentActivity"); } } public Customer() { _timer = new Timer(UpdateDateTime, null, 0, 1000); } private void UpdateDateTime(object state) { TimeOfMostRecentActivity = DateTime.Now; } public static Customer GetCurrentCustomer() { if (_currentCustomer == null) { _currentCustomer = new Customer { FirstName = "Jim" , LastName = "Smith" , TimeOfMostRecentActivity = DateTime.Now }; } return _currentCustomer; } //INotifyPropertyChanged implementation public event PropertyChangedEventHandler PropertyChanged; private void RaisePropertyChanged(string property) { if (PropertyChanged != null) { PropertyChanged(this, new PropertyChangedEventArgs(property)); } } } } </code></pre>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload