Итак, я пытался реализовать шаблон 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
не является уведомляющим * 1035) * меняет свой экземпляр на ViewModel
)
Буду очень признателен за любые советы относительно этого поста, большое спасибо вам, ребята, заранее.
EDIT
- Обновлены фрагменты с отсутствующим кодом (спасибо Павло и Бену)
- Готовое решение для публичного репозитория SVN http://nanotaboada.svn.beanstalkapp.com/dotnet/trunk/Dotnet.Samples.Rijndael/ для всех, кто заинтересован в проверке всего проекта.
- Изменены методы
Model
и ViewModel
, добавлена реализация ICommand
. Для полного рабочего образца, пожалуйста, проверьте редакцию 16.