MVVM:实现ViewModel而不更新其Model实例的类

Nan*_*ada 0 c# wpf mvvm inotifypropertychanged

所以我一直在尝试MVVMWPF具有以下结构的简单应用程序中实现该模式:

模型

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.";
    }
}
Run Code Online (Sandbox Code Playgroud)

查看模型(基础)

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));
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

查看模型(IMPL)

public class FoobarViewModel : ViewModel
{
    private readonly Foobar foobar;

    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);
    };
}
Run Code Online (Sandbox Code Playgroud)

命令

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();
    }
}
Run Code Online (Sandbox Code Playgroud)

视图

<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>
Run Code Online (Sandbox Code Playgroud)

这种方法的问题在于,尽管它ViewModel具有良好的绑定性View,但是Model没有反映出这种变化(意味着它的实例Model没有通知返回的变化ViewModel)

我非常感谢有关这篇文章的任何建议,非常感谢你们提前.

编辑

  1. 更新了缺少代码的片段(感谢Pavlo和Ben)
  2. 致力于检查整个项目的公共svn repo http://nanotaboada.svn.beanstalkapp.com/dotnet/trunk/Dotnet.Samples.Rijndael/的承诺解决方案.
  3. 修改ModelViewModel方法,添加ICommand实现.如需完整的工作样品,请查看修订版16.

Pav*_*kov 5

一切看起来都不错,除了一个小而重要的细节.您似乎忘记将DataContext视图设置为视图模型的实例.

<Window ...
        DataContext="{StaticResource FoobarViewModel}">
Run Code Online (Sandbox Code Playgroud)

如果没有它,您的绑定将失败(在调试器下查看Visual Studio的输出窗口,您将看到绑定错误).

另请注意,当TextBox丢失焦点时,将在视图模型和模型中更新值.要在绑定时键入set UpdateSourceTrigger,使其更新PropertyChanged:

<TextBox Name="FooTextBox" Text="{Binding Foo, Mode=TwoWay, ValidatesOnDataErrors=True, UpdateSourceTrigger=PropertyChanged}" />
Run Code Online (Sandbox Code Playgroud)