Nan*_*ada 0 c# wpf mvvm inotifypropertychanged
所以我一直在尝试MVVM在WPF具有以下结构的简单应用程序中实现该模式:
模型
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)
我非常感谢有关这篇文章的任何建议,非常感谢你们提前.
编辑
Model和ViewModel方法,添加ICommand实现.如需完整的工作样品,请查看修订版16.一切看起来都不错,除了一个小而重要的细节.您似乎忘记将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)