MVVM: класс, который реализует ViewModel, не обновляя свой экземпляр Model - PullRequest
0 голосов
/ 22 марта 2011

Итак, я пытался реализовать шаблон 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

  1. Обновлены фрагменты с отсутствующим кодом (спасибо Павло и Бену)
  2. Готовое решение для публичного репозитория SVN http://nanotaboada.svn.beanstalkapp.com/dotnet/trunk/Dotnet.Samples.Rijndael/ для всех, кто заинтересован в проверке всего проекта.
  3. Изменены методы Model и ViewModel, добавлена ​​реализация ICommand. Для полного рабочего образца, пожалуйста, проверьте редакцию 16.

Ответы [ 2 ]

5 голосов
/ 22 марта 2011

Все выглядит хорошо, кроме одной маленькой, но важной детали.Похоже, вы забыли установить DataContext вашего представления для экземпляра модели представления.

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

Без этого ваши привязки потерпят неудачу (посмотрите в окне вывода Visual Studio, когда вы находитесь под отладчиком, и выВы увидите ошибки привязки).

Также обратите внимание, что значения будут обновлены в вашей модели представления и модели, когда TextBox потеряет фокус.Чтобы он обновлялся, пока вы набираете UpdateSourceTrigger в PropertyChanged на своих привязках:

<TextBox Name="FooTextBox" Text="{Binding Foo, Mode=TwoWay, ValidatesOnDataErrors=True, UpdateSourceTrigger=PropertyChanged}" />
1 голос
/ 23 марта 2011

В вашей FooBarViewModel вы не создаете экземпляр своей Модели, она остается нулевой, поскольку вы пометили ее только для чтения, вам потребуется новый в конструкторе по умолчанию.

...