Random programming things I'd want to remember

Showing posts with label mvvm. Show all posts
Showing posts with label mvvm. Show all posts

Saturday, August 29, 2015

Using MVVM to update a property on an object.



Alright, so a fresh new solution. Adding folders: Models, ServiceClasses, ViewModels, and our view should technically go into the Views folder, but I'll make it simple for this examle and use the default MainPage.xaml that already exists in the root folder of the solution.

Adding the model class, Model.cs into the /Models folder. For the simplicity, there are only two properties.
using System;
using System.ComponentModel;

namespace PWApp.Models
{
    public class Model1
    {

        public string PropertyString { get; set; }
        public int PropertyInt { get; set; }
    }
}


Next, let's add these classes into /ServiceClasses folder:

using System;
using System.Windows.Input;

namespace PWApp.ServiceClasses
{
    public class DelegateCommand : ICommand
    {
        Func<object, bool> canExecute;
        Action<object> executeAction;

        public DelegateCommand(Action<object> executeAction)
            : this(executeAction, null) { }

        public DelegateCommand(Action<object> executeAction, Func<object, bool> canExecute)
        {
            if (executeAction == null)
            {
                throw new ArgumentNullException("executeAction");
            }
            this.executeAction = executeAction;
            this.canExecute = canExecute;
        }

        public bool CanExecute(object parameter) //can command execute in its current status?
        {
            bool result = true;
            Func<object, bool> canExecuteHandler = this.canExecute;
            if (canExecuteHandler != null)
            {
                result = canExecuteHandler(parameter);
            }
            return result;
        }

        public event EventHandler CanExecuteChanged; //occurs when changes occur that affect whether or not the command should execute

        public void RaiseCanExecuteChanged()
        {
            EventHandler handler = this.CanExecuteChanged;
            if (handler != null)
            {
                handler(this, new EventArgs());
            }
        }

        public void Execute(object parameter) //Method to call when the command is invoked
        {
            this.executeAction(parameter);
        }
    }
}



Class "ShowConverter" is what we will use to show or hide the data based on their values. If it is not clear now how it works, it'll become all clear in the end. Something worth noticing here is that we are extracting the "value" parameter and converting it to an integer, and we are doing the same thing to the "parameter" object. If the values are the same, then whatever we are tying up to this is visible, otherwise it is hidden.

using System;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Data;

namespace PWApp.ServiceClasses
{
    public class ShowConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, string language)
        {
            int i = System.Convert.ToInt32(value);
            int j = System.Convert.ToInt32(parameter);

            if (i == j) return Visibility.Visible;

            return Visibility.Collapsed;
        }

        public object ConvertBack(object value, Type targetType, object parameter, string language)
        {
            throw new NotImplementedException();
        }
    }
}


Next, adding items to the /ViewModels folder. Starting with the BaseViewModel class, it implements the events that we could use for all the other ViewModels

using System;
using System.ComponentModel;

namespace PWApp.ViewModels
{
    public class BaseViewModel : INotifyPropertyChanged
    {        
        public event PropertyChangedEventHandler PropertyChanged;
        public void OnPropertyChanged(string propertyName)
        {
            PropertyChangedEventHandler handler = this.PropertyChanged;
            if (handler != null)
            {
                handler(this, new PropertyChangedEventArgs(propertyName));
            }
        }
    }
}


Now, the actual ViewModel. This is where the magic is happening.

using System;
using System.Windows.Input;
using PWApp.Models;
using PWApp.ServiceClasses;
using PWApp.ViewModels;

namespace PWApp.ViewModels
{
    public class PWViewModel : BaseViewModel
    {
        public PWViewModel()
        {
            m1 = new Model1();
            m1.PropertyInt = 1;
            m1.PropertyString = "String 1";

            _alterM1Command = new DelegateCommand(this.AlterM1CommandAction, this.CanAlterM1); //add this line to wherever you initialize your commands
        }

        private Model1 m1;
        public Model1 M1
        {
            get { return m1; }
            set
            {
                if (m1 == value) return;
                m1 = value;
                OnPropertyChanged("M1");
            }
        }

        DelegateCommand _alterM1Command;
        public ICommand AlterM1Command { get { return _alterM1Command; } }
        private void AlterM1CommandAction(object obj)
        {
            int i = M1.PropertyInt;

            Model1 backup = new Model1 { PropertyInt = M1.PropertyInt, PropertyString = M1.PropertyString };
            //I am creating a whole new copy of the object because just changing the property does not change
            //the value of the object, and does not fire the OnPropertyChanged event
            if (++i == 3)
                M1 = new Model1 { PropertyInt = 0, PropertyString = backup.PropertyString };
            else
                M1 = new Model1 { PropertyInt = i, PropertyString = backup.PropertyString };
        }

        private bool CanAlterM1(object obj)
        {
            return true;
        }
    }
}



Now, the view. The actual face of the program. First thing to notice is the xmlns:service line in the Page tag. That declares the namespace that we can use, and we declare it to use the converter. The next line is Page.Resources tag, actually what's happening inside it. First declaration is me being lazy -- I set the FontSize of all the TextBoxes at once to 24. The second item is our declaration of the ShowConverter. I declared the namespace in the Page tag to be able to access the file, I actually tell the system what it is under the Resources section. I actually use the file to toggle visibility of an item in the following manner:

Visibility="{Binding M1.PropertyInt, Converter={StaticResource sc}, ConverterParameter=0}"


Here is the entire view. If you copy it into your app, don't forget to replace the "PWApp" namespace with your own.

<Page
    x:Class="PWApp.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:PWApp"
    xmlns:service="using:PWApp.ServiceClasses"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d">
    <Page.Resources>
        <Style TargetType="TextBlock">
            <Setter Property="FontSize" Value="24" />
        </Style>
        <service:ShowConverter x:Key="sc" />
    </Page.Resources>
    <Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto" />
            <RowDefinition Height="Auto" />
            <RowDefinition Height="Auto" />
            <RowDefinition Height="Auto" />
            <RowDefinition Height="Auto" />
            <RowDefinition Height="Auto" />
            <RowDefinition Height="Auto" />
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="Auto" />
            <ColumnDefinition Width="Auto" />
            <ColumnDefinition Width="Auto" />
            <ColumnDefinition Width="Auto" />
            <ColumnDefinition Width="Auto" />
        </Grid.ColumnDefinitions>
        <Button Command="{Binding AlterM1Command}" Content="Alter M1" Margin="20, 60, 12, 12" />
        <Button Command="{Binding AlterM2Command}" Content="Alter M2" Grid.Column="1" Margin="12, 60, 12, 12" />
        <Button Command="{Binding AlterM3Command}" Content="Alter M3" Grid.Column="2" Margin="12, 60, 12, 12" />
        <TextBlock Text="M1:" Grid.Row="1" Margin="12"/>
        <Border BorderBrush="Red" Grid.Row="1" Grid.Column="1" BorderThickness="2" Padding="10" Margin="12"><TextBlock Text="{Binding M1.PropertyInt}" Margin="12" 
                   Visibility="{Binding M1.PropertyInt, Converter={StaticResource sc}, ConverterParameter=0}" /></Border>
        <Border BorderBrush="Red" Grid.Row="1" Grid.Column="2" BorderThickness="2" Padding="10" Margin="12"> <TextBlock Text="{Binding M1.PropertyInt}" Margin="12"
                   Visibility="{Binding M1.PropertyInt, Converter={StaticResource sc}, ConverterParameter=1}" /></Border>
        <Border BorderBrush="Red" Grid.Row="1" Grid.Column="3" BorderThickness="2" Padding="12" Margin="12"><TextBlock Text="{Binding M1.PropertyInt}" Margin="12"
                   Visibility="{Binding M1.PropertyInt, Converter={StaticResource sc}, ConverterParameter=2}" /></Border>
        <TextBlock Text="{Binding M1.PropertyString}" Grid.Row="1" Grid.Column="4" Margin="12" />
    </Grid>
</Page>


Finally, setting the DataContext of the MainPage, tying up the View to the ViewModel:

    public sealed partial class MainPage : Page
    {
        public MainPage()
        {
            this.InitializeComponent();
            this.DataContext = new PWViewModel();
        }
    }



Saturday, March 22, 2014

Code snippet for MVVM command in a ViewModel

Since code snippets are not that hard to do, here is another one. This one gets all the plumbing for a command in a ViewModel, I used DelegateCommand class to abstract all the INotifyPropertyChanged functionality. See my other posts on the subject. Call this one in VisualStudio by its shortcut, dcmvvm.
<?xml version="1.0" encoding="utf-8"?>
<CodeSnippets
    xmlns="http://schemas.microsoft.com/VisualStudio/2005/CodeSnippet">
  <CodeSnippet Format="1.0.0">
    <Header>
      <Title>Plumbing for an MVVM DelegateCommand</Title>
      <Author>yevgeller</Author>
      <Description>Plumbing for an MVVM DelegateCommand for use in a ViewModel</Description>
      <Shortcut>dcmvvm</Shortcut>
    </Header>
    <Snippet>
      <Declarations>
        <Literal>
          <ID>cmd1</ID>
          <ToolTip>Prefix for a private variable that holds command name.</ToolTip>
          <Default>your</Default>
        </Literal>
        <Literal>
          <ID>cmd2</ID>
          <ToolTip>Prefix for a property Name that exposes the command to the View.</ToolTip>
          <Default>Your</Default>
        </Literal>
      </Declarations>
      <Code Language="csharp">
        <![CDATA[
        DelegateCommand _$cmd1$Command;
        public ICommand $cmd2$Command { get { return _$cmd1$Command; } }
        private void $cmd2$CommandAction(object obj)
        {
            throw new NotImplementedException();
        }
        //add the following line to ViewModel constructor or wherever else you initialize your commands:
        _$cmd1$Command = new DelegateCommand(this.$cmd2$CommandAction, this.Can$cmd2$);
        private bool Can$cmd2$(object obj)
        {
            return true;
        }
      ]]>
      </Code>
    </Snippet>
  </CodeSnippet>
</CodeSnippets>

Tuesday, March 18, 2014

Code snippet file for a property that calls for OnPropertyChanged event

With minimal changes, this snippet will also work for PropertyChanged event. How to use:
  1. Save the following contents into a .snippet file
  2. Visual Studio -> Tools -> Code Snippets Manager (or Ctrl+K, Ctrl+B)
  3. Import, find your file
  4. While working on another ViewModel, type in propopc and enjoy

Note to self: while working on the next snippet, if variables don't show up in the result, make sure that they are included in the <Snippet> section

Helpful resource 1, helpful resource 2.

<?xml version="1.0" encoding="utf-8"?>
<CodeSnippets
    xmlns="http://schemas.microsoft.com/VisualStudio/2005/CodeSnippet">
  <CodeSnippet Format="1.0.0">
    <Header>
      <Title>Property with a call to OnPropertyChanged</Title>
      <Author>yevgeller</Author>
      <Description>Property calling OnPropertyChanged method</Description>
      <Shortcut>propopc</Shortcut>
    </Header>
    <Snippet>
      <Declarations>
        <Literal>
          <ID>var</ID>
          <ToolTip>Replace with a private variable.</ToolTip>
          <Default>_privateVar</Default>
        </Literal>
        <Literal>
          <ID>type</ID>
          <ToolTip>Replace with a property type.</ToolTip>
          <Default>string</Default>
        </Literal>
        <Literal>
          <ID>propName</ID>
          <ToolTip>Replace with a property name.</ToolTip>
          <Default>MyProperty</Default>
        </Literal>
      </Declarations>
      <Code Language="csharp">
        <![CDATA[
  private $type$ $var$;
         public $type$ $propName$
         {
              get { return $var$; }
              set
              {
                  if ($var$ == value) return;
                  $var$ = value;
                  OnPropertyChanged("$propName$");
              }
         }
      ]]>
      </Code>
    </Snippet>
  </CodeSnippet>
</CodeSnippets>

Friday, February 28, 2014

Another simple MVVM tutorial for Windows Phone explained

I will take another attempt to explain the use of MVVM on Windows Phone. I already tried it before, but this time code is available on GitHub. Clone the project and follow along with my explanations.

This time we are building a registration database. The app will be tracking people's names along with gender.

1. Model

There is a class called "Person" in the Models folder. For the sake of simplicity, the app will track the name and gender.

2. View

There is MainPage.xaml file in ViewModels folder that is the front-end of the app (to change startup page for a Windows Phone app, go to Properties/WMAppManifest.xml and change it in "Navigation Page" field to whatever you need; the sample app already has it set up properly). There is a textbox for name, and radiobuttons to select a gender. The app must only allow to register when a name is provided and a gender is selected. So it can either provide feedback to the user when not all data is supplied for registration, or we can disable the Register button until all data is present.

There is a tricky part here. TextBox's text property originally had the following binding:

Text="{Binding UserName, Mode=TwoWay}"
The problem with that is that the Text property is updated in the view model only after textbox loses focus. To mitigate the situation, we can use the solution provided by Charles Petzold in his "Programming Windows Phone 7" book:
<!-- TextBox full declaration in XAML -->
<TextBox Text="{Binding UserName, Mode=TwoWay, UpdateSourceTrigger=Explicit}" 
                     x:Name="boundTextBox" 
                     TextChanged="boundTextBox_TextChanged" />

//and then, the event in the code-behind file for the View:
private void boundTextBox_TextChanged(object sender, TextChangedEventArgs e)
{
  TextBox txtbox = sender as TextBox;
  BindingExpression bindingExpression = txtbox.GetBindingExpression(TextBox.TextProperty);
  bindingExpression.UpdateSource();
}

As a result of this modification, every time a key is pressed in that TextBox, the property in our view model will be updated. One can argue that the true MVVM has no data in the code-behind files and this event might violate that principle, but the reality is that sometimes it's not easily possible. In addition, one of the main benefits of MVVM is testability. Having such an event in the code-behind of the view only affects internal workings of the app and does not affect data or business logic, so testability is very much preserved intact.

Now let's look a little closer at bindings. RegisterViewModel exposes properties and commands, which the view uses to display data or react to user input. For example, RegisterViewModel exposes a property named ProspectiveRegistration, which it calculates as as combination of name and gender:

public string ProspectiveRegistration
{
    get
    {
        string ret = this.UserName;
        ret += this.UserName.Length > 0 ? ", " : "";

        if (this.IsALady)
            ret += "Lady";
        if (this.IsAGentleman)
            ret += "Gentleman";

        return ret;
    }
}
The view binds this property to a TextBlock's Text property in the following manner:
<TextBlock Text="{Binding ProspectiveRegistration}" />
How does the view know that the property was updated? The answer to that lies in the setters of the all the other properties used in ProspectiveRegistration (UserName, IsALady, IsAGentleman). They all have the following line of code:
this.OnPropertyChanged("ProspectiveRegistration");
This line of code is the magic that updates the view with the new value of the property.

The example above was somewhat simple because the view only displayed the value of a property that belongs to the view model. What if the view needs to send data back to the ViewModel? Let's look at how the gender radiobuttons are declared:

<RadioButton Content="Lady" IsChecked="{Binding IsALady, Mode=TwoWay}" GroupName="genderGroup" />
IsChecked property is declared as a two-way property, and not only it displays the state of the property in the view model, but it also sends its value back to the view model. This is one of the ways how the view propagates data to the view model.

3. ViewModel

The view model for the project is the class called RegisterViewModel and it resides in the ViewModels folder along with the class called ViewModel. ViewModel class is the parent class for RegisterViewModel and it has the plumbing for INotifyPropertyChanged interface. It also has plumbing for navigation since it may be a bit tricky if using MVVM, but there are usage instructions.

RegisterViewModel.cs

A couple of interesting points here. First, the data store is an ObservableCollection. The difference between an ObservableCollection and List is that ObservableCollection lets know when it changed. The app conveniently subscribes to the CollectionChanged event to update properties bound to the view.

Next, let's look at the register command. Declaration:

private DelegateCommand _registerCommand;
It is an instance of a DelegateCommand. What is a DelegateCommand? Any command bound to the view must implement ICommand interface. DelegateCommand wraps up all the members of the ICommand interface so that the app does not have to re-implement them every time. DelegateCommand.cs can be found in ServiceClasses folder.

_registerCommand as it is declared in constructor of the RegisterViewModel:

_registerCommand = new DelegateCommand(this.RegisterCommandAction, CanRegister); //initialize command
Method RegisterCommandAction is where the registration actually happens. This is what the command is supposed to do:
//Registration procedure
private void RegisterCommandAction(object obj)
{
    people.Add(new Person
    {
        Name = this.UserName,
        Gender = this.IsALady ? "Lady" : "Gentleman"
    });
    this.UserName = "";
    this.IsALady = false;
    this.IsAGentleman = false;
}
CanRegister method defines whether the command can execute or not. Here is what it looks like:
//Data consistency conditions that must be satisfied for a successful registration
private bool CanRegister(object arg)
{
    return (IsALady || IsAGentleman) && UserName.Length > 0;
}
This method enables/disables the register button in the view without having to bind the IsEnabled property of the button on the view. By the way, IsEnabled property can be managed by binding this property on the view to a boolean property on a view model. Pretty much any property on the view can be bound to a property on the view model, sometimes one might need to use a converter class (any class that implements an IValueConverter interface).

There is just one piece missing. The app somehow needs to know when CanRegsiter changes. For that, the DelegateCommand exposes a method called RaiseCanExecuteChanged(). Every time a property changes in the RegisterViewModel, not only the app has to notify that the property value changed, but it also has to make sure we can (or cannot) register. Here is, for example, an implementation of the UserName property in the view model:

private string _userName;
public string UserName
{
    get
    {
        if (_userName == null)
            _userName = "";
        return _userName;
    }
    set
    {
        if (_userName == value)
            return;
        _userName = value;
        this.OnPropertyChanged("UserName");
        this.OnPropertyChanged("ProspectiveRegistration");
        _registerCommand.RaiseCanExecuteChanged(); //checking on RegisterCommand to see if it can execute
    }
}

4. Testing

Now you can see that MVVM decouples View from ViewModel making it easy to test ViewModels. Visual Studio (even Express versions) provides tools for testing. A couple of test methods included with the Test project give a basic idea of how testing can go.

5. Conclusion

Hopefully this article explained the usage of MVVM pattern on Windows Phone. Again, the code is available on GitHub, feel free to ask questions and/or leave comments

UPDATE 3/16/2014:

I updated the code in the repository to include a technique where a Text propery (or another one for that matter) can be used as a CommandParameter. See the code for full example, but in short, here is what you need to do:

In the View, I added a TextBox, gave it an x:Name property of "typeSomethingHere" (that's the second named control on the entire page). Then I added a Button, and I assigned the following properties to it besides Content and position on the page:

Command="{Binding DisplayInputWithoutAdditionalPropertyCommand}"
CommandParameter="{Binding ElementName=typeSomethingHere, Path=Text}"
The Command property is just as usual, but the CommandParameter property shows the beauty and flexibility of XAML, it grabs the Text property from the TextBox.

The rest are details, I create a string property ShowWhatWasTyped and it displays what was typed.

What's the bottom line here? I could have bound the Text property of a typeSomethingHere TextBox and use it to get text, but instead I taught the button to grab Text directly from the TextBox and pass it to the ViewModel. This works well only if you need to pass one value into a method quickly. You can, of course, use other properties of the ViewModel in the method.


Wednesday, December 11, 2013

MVVM Controls inside ListBox (ItemsControl) not firing

Scenario: you built an app using something that more or less closely resembles the MVVM approach that I described earlier, and you have a data control with a nested control that must execute some command. Here is how it might look:

//YourViewModel.cs:
private DelegateCommand yourCommand;

public YourPageConstructor()
{
  yourCommand = new DelegateCommand(this.YourMethod);
  ...
}

private void YourMethod(object obj)
{
  ...//do something here
}

public ICommand YourCommand { get { return yourCommand; } }

//yourPage.xaml.cs:
public yourPage()
{
  InitializeComponent();
  this.DataContext = new YourViewModel();
}

//yourPage.xaml:
<ListBox x:Name="yourDataControl" ...>
  <ListBox.ItemTemplate>
    <DataTemplate>
      <StackPanel>
        <Button Command="{Binding YourCommand}" Content="YourItems" ... />
      </StackPanel>
    </DataTemplate>
  </ListBox.ItemTemplate>
</ListBox>



You go to test your page, but your command is not firing. When you set a breakpoint at the "public ICommand YourCommand ..." line, you see that it is not being hit when the page loads. What's happening?

The thing is, your command should be a part of the collection that the ListBox is bound to for the ListBox to see (and execute it). Your command lives in your ViewModel, while the ListBox is bound to a collection. What to do? Bind your command in the following way:

//yourPage.xaml, add an x:Name attribute to the content of the opening PhoneApplicationPage tag:
<phone:PhoneApplicationPage
    x:Class="YourProjectName.Views.yourPage"
    x:Name="nameYourXAMLPageName"
    ...>

//and then change the Button's binding:
<ListBox x:Name="yourDataControl" ...>
  <ListBox.ItemTemplate>
    <DataTemplate>
      <StackPanel>
        <Button Command="{Binding ElementName=nameYourXAMLPageName, Path=DataContext.YourCommand}"
                   Content="{Binding YourItems}" ... />
     </StackPanel>
    </DataTemplate>
  </ListBox.ItemTemplate>
</ListBox>
...


This way, we are not embedding the command into the collection bound to ListBox, but rather, let the ListBox know where to find the command by providing the "address" of the current page's DataContext.


As usual, leave your thoughts in comments.

Saturday, October 19, 2013

Implementing your own keyboard on Windows Phone using MVVM pattern

In my previous article on MVVM pattern in Windows phone, I explained the entire model. Today, I will explain the usage of same pattern on Windows Phone in simpler terms. I will show how to implement a bunch of buttons (which can be repurposed for keyboard) on Windows Phone using MVVM. Let's start with a view:

    <Grid x:Name="LayoutRoot" Background="Transparent">
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="Auto"/>
        </Grid.RowDefinitions>
        
        <TextBlock Text="{Binding MyText}" />

        <ItemsControl ItemsSource="{Binding MyButtons}" HorizontalAlignment="Center" Padding="0" Grid.Row="1"
                              Style="{StaticResource HorizontalStackPanel}" />

    </Grid>

Quite a standard phone page, the first row contains the property we will be changing through the buttons that we create. The second row contains the ItemsControl that will display the collection of newly-created buttons.

What is non-standard about it is the style definiton for ItemsControl (HorizontalStackPanel). The reason for it is that by default, ItemsControl lays out its children in vertical fashion. But if you add the following code into App.xaml file in <Application.Resources> block, your items will be laid out horizontally:

        <Style x:Key="HorizontalStackPanel" TargetType="ItemsControl">
            <Setter Property="ItemsPanel">
                <Setter.Value>
                    <ItemsPanelTemplate>
                        <StackPanel Orientation="Horizontal" />
                    </ItemsPanelTemplate>
                </Setter.Value>
            </Setter>
        </Style>

Now let's get to the code-behind page, pretty easy too:

public MainPage()
{
    InitializeComponent();
    this.DataContext = new ButtonsViewModel();
}

And now let's get to the ButtonsViewModel. First, implementing the MyText property in accordance with MVVM:

        private string _myText;
        public string MyText
        {
            get { return _myText; }
            set
            {
                if (_myText == value)
                    return;
                _myText = value;
                this.RaisePropertyChanged("MyText");
            }
        }

Then, implementing the plumbing for INotifyPropertyChanged interface:
//INotifyPropertyChanged implementation
        public event PropertyChangedEventHandler PropertyChanged;
        public void RaisePropertyChanged(string propertyName)
        {
            PropertyChangedEventHandler handler = this.PropertyChanged;
            if (handler != null)
            {
                handler(this, new PropertyChangedEventArgs(propertyName));
            }
        }

And here we implement the MyButtons property by creating a list of Buttons and adding Buttons one-by-one:

//Buttons property
        public List<Button> MyButtons
        {
            get
            {
                List<Button> buttons = new List<Button>();
                buttons.Add(MakeAButton("q");
                buttons.Add(MakeAButton("w");
                buttons.Add(MakeAButton("e");
                buttons.Add(MakeAButton("r");
                buttons.Add(MakeAButton("s");
                return buttons;
            }
        }
//Button plumbing
        private Button MakeAButton(string letter)
        {
            Button b = new Button
            {
                CommandParameter = letter,
                Content =  new TextBlock { Text = letter, FontSize = 24, FontFamily = new System.Windows.Media.FontFamily("Segoe UI Mono") },
                Height=80
            };
            b.Click += b_Click; 
            return b;
        }
//The magic
        void b_Click(object sender, System.Windows.RoutedEventArgs e)
        {
            string a = (sender as Button).CommandParameter.ToString();
            SomeText += a;
        }

This example is not a classic MVVM implementation, it uses the Button Click event to alter the value of the MyText property. The classic implementation would be to use ICommand, but I chose not to do it here because this is a quick and easy example. Hopefully it can provide the feel for MVVM for those who are trying to understand the pattern.

A word of caution: if you need to fit a lot of buttons on the same row, you will be better off adjusting Margin property on each button.

Wednesday, January 2, 2013

Simple MVVM tutorial for Windows Phone explained

Once I started learning MVVM pattern for Windows Phone, I decided to write a short sample demonstrating all the features so that I can sum it up for myself. Here it is. This article was a great starting point to understand MVVM. The most important thought I got out of that article was the INotifyProperty changed interface, which allows the controls on the phone be notified about the changes in the elements that they are bound to. We'll start with the view:
<!--ContentPanel - place additional content here-->
        <Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="0.5*"/>
                <ColumnDefinition Width="0.5*"/>
            </Grid.ColumnDefinitions>

            <Button Content="{Binding OneText}" Command="{Binding OneCommand}" IsEnabled="{Binding IsButton1Enabled}" />
            <Button Content="{Binding TwoText}" Command="{Binding TwoCommand}" IsEnabled="{Binding IsButton2Enabled}" Grid.Column="1" />
        </Grid>


There are many ways to hook up ViewModel to the View. This is the simplest one:
        public MainPage()
        {
            InitializeComponent();
            this.DataContext = new OneViewModel();
        }


The idea behind the app is very simple: there are two buttons, pressing one of them deactivates it and activates the other. It also changes the Content property of the other button. So my ViewModel should expose two properties for buttons' contents, two commands, and two properties for buttons' enabled/disabled status. Let's get to it. By the way, Random class will be my model, it will provide Content for buttons.
//ViewModel
    public class OneViewModel : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;
        Random r;

        private string _oneText;
        public string OneText
        {
            get { return this._oneText; }
            set
            {
                if (value == this._oneText)
                    return;
                this._oneText = value;
                this.OnPropertyChanged("OneText");
            }
        }

        private string _twoText;
        public string TwoText
        {
            get { return this._twoText; }
            set
            {
                if (value == this._twoText)
                    return;
                this._twoText = value;
                this.OnPropertyChanged("TwoText");
            }
        }

        private bool _isButton1Enabled;
        public bool IsButton1Enabled
        {
            get { return _isButton1Enabled; }
            set
            {
                if (_isButton1Enabled == value)
                    return;
                _isButton1Enabled = value;
                this.OnPropertyChanged("IsButton1Enabled");
            }
        }


        private bool _isButton2Enabled;
        public bool IsButton2Enabled
        {
            get { return _isButton2Enabled; }
            set
            {
                if (_isButton2Enabled == value)
                    return;
                _isButton2Enabled = value;
                this.OnPropertyChanged("IsButton2Enabled");
            }
        }

        private DelegateCommand _oneCommand;
        private DelegateCommand _twoCommand;
        
        //Constructor
        public OneViewModel()
        {
            r = new Random(); //This is my model
            IsButton1Enabled = true;
            IsButton2Enabled = false;
            OneText = r.Next(100).ToString();
            TwoText = r.Next(100).ToString();
            _oneCommand = new DelegateCommand(this.OneCommandAction);
            _twoCommand = new DelegateCommand(this.TwoCommandAction);
        }

        private void TwoCommandAction(object obj)
        {
            OneText = r.Next(100).ToString();
            IsButton1Enabled = true;
            IsButton2Enabled = false;
        }

        private void OneCommandAction(object obj)
        {
            TwoText = r.Next(100).ToString();
            IsButton1Enabled = false;
            IsButton2Enabled = true;
        }

        public ICommand OneCommand { get { return _oneCommand; } }
        public ICommand TwoCommand { get { return _twoCommand; } }

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



Not much to explain here, everything seems pretty obvious and simple. As I said before, the this.OnPropertyChanged(...) methods letting the View know that things change and the View adjusts accordingly.

Here is the definition for the DelegateCommand class.


    public class DelegateCommand : ICommand
    {
        Func<object, bool> canExecute;
        Action<object> executeAction;

        public DelegateCommand(Action<object> executeAction)
            : this(executeAction, null)        {        }

        public DelegateCommand(Action<object> executeAction, Func<object, bool> canExecute)
        {
            if (executeAction == null)
            {
                throw new ArgumentNullException("executeAction");
            }
            this.executeAction = executeAction;
            this.canExecute = canExecute;
        }

        public bool CanExecute(object parameter) //can command execute in its current status?
        {
            bool result = true;
            Func<object, bool> canExecuteHandler = this.canExecute;
            if (canExecuteHandler != null)
            {
                result = canExecuteHandler(parameter);
            }
            return result;
        }

        public event EventHandler CanExecuteChanged; //occurs when changes occur that affect whether or not the command should execute

        public void RaiseCanExecuteChanged()
        {
            EventHandler handler = this.CanExecuteChanged;
            if (handler != null)
            {
                handler(this, new EventArgs());
            }
        }

        public void Execute(object parameter) //Method to call when the command is invoked
        {
            this.executeAction(parameter);
        }
    }

        


A couple of points of interest. If your buttons don't seem like they are reacting to the commands and you think everything is hooked up properly, check to make sure your ViewModel class is declared as public.

This site has videos on MVVM implementation for more serious things like, navigation and so on.

Also, be sure to check out my other article on MVVM where I implement a simple keyboard on Windows Phone. That tutorial is easier than this one.

For another tutorial, be sure to check my other article on the subject.