所以我一直在尝试在具有以下结构的简单MVVM
应用程序中实现WPF
模式:
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.";
}
}
查看模型(基础)
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));
}
}
}
查看模型(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);
};
}
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();
}
}
查看
<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>
这种方法的问题是,尽管ViewModel
与View
绑定正常,但Model
并未反映此类更改(意味着Model
不是通知更改其ViewModel
上的实例
我非常感谢有关这篇文章的任何建议,非常感谢你们。
修改
Model
和ViewModel
方法,添加了ICommand
实施。如需完整的工作样本,请查看修订版16。答案 0 :(得分:5)
除了一个小而重要的细节之外,一切看起来还不错。您似乎忘记将视图的DataContext
设置为视图模型的实例。
<Window ...
DataContext="{StaticResource FoobarViewModel}">
没有它,您的绑定将失败(在调试器下查看Visual Studio的输出窗口,您将看到绑定错误)。
另请注意,当TextBox
失去焦点时,值将在视图模型和模型中更新。要在绑定时将UpdateSourceTrigger
设置为PropertyChanged
,请对其进行更新:
<TextBox Name="FooTextBox" Text="{Binding Foo, Mode=TwoWay, ValidatesOnDataErrors=True, UpdateSourceTrigger=PropertyChanged}" />
答案 1 :(得分:1)
在你的FooBarViewModel中,你没有实例化你的模型,它被保留为null,因为你只读了它,你需要在默认的构造函数中 new 。