开发者

MVVM: class that implements ViewModel not updating its Model instance

So I've been trying to implement the MVVM pattern within a simple WPF application that has the following structure:

MODEL

public class Foobar
{
    public string Foo { get; set; }
    public string Bar { get; set; }

    public string DoSomethingWithFoo()
    {
        return "The quick brown fox";
    }

    public string DoSomethingWithBar()
    {
        return "jumps over the lazy dog.";
    }
}

VIEW MODEL (BASE)

public abstract class ViewModel : INotifyPropertyChanged
{
    [Conditional("DEBUG")]
    [DebuggerStepThrough]
    public void VerifyPropertyName(string propertyName)
    {
        if (TypeDescriptor.GetProperties(this)[propertyName] == null)
        {
            Debug.Fail("Invalid property name: " + propertyName);
        }
    }

    protected virtual void OnPropertyChanged(string propertyName)
    {
        this.VerifyPropertyName(propertyName);

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

VIEW MODEL (IMPL)

public class FoobarViewModel : ViewModel
{
    private readonly Foobar foob开发者_如何学运维ar;

    public string Foo
    {
        get
        {
            return this.foobar.Foo;
        }
        set
        {
            this.foobar.Foo = value;
            OnPropertyChanged("Foo");
        }
    }

    public string Bar
    {
        get
        {
            return this.foobar.Bar;
        }
        set
        {
            this.foobar.Bar = value;
            OnPropertyChanged("Bar");
        }
    }

    private FoobarCommand fooCommand;
    public FoobarCommand FooCommand
    {
        get
        {
            return fooCommand;
        }
        set
        { 
            fooCommand = value;
            OnPropertyChanged("FooCommand");
        }
    }

    private FoobarCommand barCommand;
    public FoobarCommand BarCommand
    {
        get
        {
            return barCommand;
        }
        set
        { 
            barCommand = value;
            OnPropertyChanged("BarCommand");
        }
    }

    private void DoSomethingWithFoo()
    {
        if (!string.IsNullOrEmpty(this.foobar.Foo))
        {
            this.foobar.Foo = this.foobar.DoSomethingWithFoo();
            OnPropertyChanged("Foo");
        }
    }

    private void DoSomethingWithBar()
    {
        if (!string.IsNullOrEmpty(this.foobar.Bar))
        {
            this.foobar.Bar = this.foobar.DoSomethingWithBar();
            OnPropertyChanged("Bar");
        }
    }

    ///<remarks>
    /// must use the parameterless constructor to satisfy <Window.Resources>
    ///</remarks>
    public FoobarViewModel()
    {
        this.foobar = new Foobar()
        {
            Foo = "Lorem",
            Bar = "Ipsum"
        }

        this.fooCommand = new FoobarCommand(DoSomethingWithFoo);
        this.barCommand = new FoobarCommand(DoSomethingWithBar);
    };
}

COMMAND

public class FoobarCommand : ICommand
{
    Action action;

    public FoobarCommand(Action action)
    {
        this.action = action;
    }

    public bool CanExecute(object parameter)
    {
        return true;
    }

    public event EventHandler CanExecuteChanged;

    public void Execute(object parameter)
    {
        this.action.Invoke();
    }
}

VIEW

<Window.Resources>
    <local:FoobarViewModel x:Key="FoobarViewModel" />
</Window.Resources>

<Grid DataContext="{StaticResource FoobarViewModel}">

    <TextBox Name="FooTextBox" Text="{Binding Foo, Mode=TwoWay, ValidatesOnDataErrors=True}" />
    <TextBox Name="BarTextBox" Text="{Binding Bar, Mode=TwoWay, ValidatesOnDataErrors=True}" />

</Grid>

The problem with this approach is, despite that the ViewModel is binding okay with the View, the Model is not reflecting such changes (meaning the Model is not notifying-back changes to its instance at the ViewModel)

I would really appreciate any bit of advice regarding this post, thanks much you guys in advance.

EDIT

  1. Updated snippets with the missing code (thanks Pavlo and Ben)
  2. Committed solution to a public svn repo http://nanotaboada.svn.beanstalkapp.com/dotnet/trunk/Dotnet.Samples.Rijndael/ for anyone interested in checking out the whole project.
  3. Modified Model and ViewModel methods, added ICommand implementation. For a full working sample please checkout revision 16.


Everything looks OK except one small, but important detail. It looks like you forgot to set DataContext of your view to the instance of the view model.

<Window ...
        DataContext="{StaticResource FoobarViewModel}">

Without it your bindings will fail (look in the output window of Visual Studio when under debugger and you'll see binding errors).

Also note that the values will be updated in your view model and model when the TextBox looses focus. To make it update while you type set UpdateSourceTrigger to PropertyChanged on your bindings:

<TextBox Name="FooTextBox" Text="{Binding Foo, Mode=TwoWay, ValidatesOnDataErrors=True, UpdateSourceTrigger=PropertyChanged}" />


In your FooBarViewModel you are not instantiating your Model, it is left as null, since you marked it readonly, you will need to new it in a default constructor.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜