A view model references a fact in the data model. It interprets that fact and related facts for the purpose of rendering a view. It exposes properties suitable for data binding.

Add a new Silverlight Class Library project to the solution. Call this project "Lesson.ViewModel". Add a Project reference to this new project. Select "Lesson.Model." Also add a NuGet reference to this new project. Search for Correspondence.

Add two classes to this project, a MachineNavigationModel and a MachineViewModel.
public class MachineNavigationModel
{
}

public class MachineViewModel
{
    private Machine _machine;
    private MachineNavigationModel _navigation;

    public MachineViewModel(
        Machine machine,
        MachineNavigationModel navigation)
    {
        _machine = machine;
        _navigation = navigation;
    }
}

We're going to unit test the new view model. Add a reference from Lesson.UnitTest to the new Lesson.ViewModel project. Add a folder to Lesson.UnitTest called "ViewModelTests". Create a new test in this folder called "MachineViewModelTest". Initialize the test class.
[TestClass]
public class MachineViewModelTest
{
    private Community _community;
    private MachineViewModel _viewModel;

    [TestInitialize]
    public void Initialize()
    {
        _community = new Community(new MemoryStorageStrategy())
            .Register<Model.CorrespondenceModel>();
        Machine machine = _community.AddFact(new Machine());
        MachineNavigationModel navigation = new MachineNavigationModel();
        _viewModel = new MachineViewModel(machine, navigation);
    }
}
The view will have a visual indicator showing which user is logged on. This indicator will be data bound to a view model property. Define that property.
public string LoggedOnUserName
{
    get
    {
        LogOn activeLogOn = _machine.LogOns.FirstOrDefault();
        return activeLogOn == null
            ? null
            : activeLogOn.User.UserName;
    }
}
Test that the property is initially null.
[TestMethod]
public void NoUserIsLoggedOn()
{
    Assert.IsNull(_viewModel.LoggedOnUserName);
}
Now the user needs to log on. The view is going to have a TextBox for the user to enter their user name. This property needs to be read/write, since the user will be editing it. It is not yet the userName of a User fact, so it is not immutable.

This kind of data goes into the navigation model. A navigation model holds data that it not persistent. It just helps the user to navigate their persistent data. Add a UserName property to the MachineNavigationModel. This property uses the Independent<> field type from Update Controls, so it can be data bound through the view model.
public class MachineNavigationModel
{
    private Independent<string> _userName = new Independent<string>();

    public string UserName
    {
        get { return _userName; }
        set { _userName.Value = value; }
    }
}
Now expose that property through the view model.
public string UserName
{
    get { return _navigation.UserName; }
    set { _navigation.UserName = value; }
}
The user is going to enter a user name and hit a "Log On" button. This button is bound to a command on the view model. Make a command that calls Machine.LogOnUser.
public ICommand LogOn
{
    get
    {
        return MakeCommand
            .Do(() => _machine.LogOnUser(_navigation.UserName));
    }
}
Test your command. The user enters a user name and hits the button. Then the user is logged on.
[TestMethod]
public void UserLogsOn()
{
    _viewModel.UserName = "alan1";
    _viewModel.LogOn.Execute(null);

    Assert.AreEqual("alan1", _viewModel.LoggedOnUserName);
}
The view model interprets the data model for the user. Views don't bind directly to facts. They bind to properties of the view model, which in turn delegate to the facts in the data model.

Data that is not persisted to the data model is stored in the navigation model. The navigation model helps the user to navigate through their data. It represents the user's point-of-view.

Next: Lesson 2c: Command activation

Last edited May 15, 2011 at 3:39 AM by MichaelLPerry1971, version 5

Comments

No comments yet.