2

Где-то слышал, что не рекомендуется подписываться на события VM из View. У меня в VM есть событие public event Action SomeEvent на которое я подписываюсь в конструкторе страницы

public MyPage()
{
    InitializeComponent();
    var ViewModel = new ViewModel();
    DataContext = ViewModel;
    ViewModel.SomeEvent += SomeMethod;
}

При срабатывании события метод SomeMethod на стороне View производит некоторые изменения. Допустима ли такая конструкция и какие могут быть альтернативы?

Mihail
  • 247
  • Моя точка зрения: если вы выносите некоторый интерфейс IVM, который будет содержать это событие, а VM будет реализовывать этот интерфейс, то такая зависимость от интерфейса вполне допустима. Зависеть от реализации, конечно, нехорошо. Но, возможно, тут стоит объявить об этой зависимости явно, например, запрашивая ее в конструкторе. Также стоит продумать вопрос о том, что делать при DataContextChanged, ведь тот кто владеет вашей вьюхой, имеет право изменить у нее DataContext – Андрей NOP Nov 30 '18 at 13:11
  • @АндрейNOP, спасибо. А что вы имеете в виду под объявить явно в конструкторе? – Mihail Nov 30 '18 at 13:31
  • Имею ввиду конструктор с параметром, вы вот привели код, а что в нем такое VM? Откуда оно берется? – Андрей NOP Nov 30 '18 at 13:58
  • @АндрейNOP, это ViewModel. Изменил код для наглядности – Mihail Nov 30 '18 at 14:07
  • Ну вот так точно нехорошо писать, View не должна создавать сама себе VM, это не ее обязанность – Андрей NOP Nov 30 '18 at 14:08
  • @АндрейNOP, а как лучше? Можно об этом где-то подробно почитать? – Mihail Nov 30 '18 at 14:46
  • DataContext должен устанавливать тот, кто создает вашу вьюху – Андрей NOP Nov 30 '18 at 14:50
  • @Mihail: Вопрос в том, для чего вам нужна такая подписка. Не хотите ли вы случайно вынести бизнес-логику во View? Если да, то вы делаете неправильно. – VladD Dec 01 '18 at 09:43
  • @VladD, по этому событию происходит смена содержимого + анимация – Mihail Dec 02 '18 at 07:51
  • @VladD, вообще я не очень понимаю как правильно работать с анимацией с MVVM. Вопрос в том, где она должна быть описана и как ее запускать. Если не трудно, то напишите пару строк: вопрос – Mihail Dec 02 '18 at 07:55
  • Смена содержимого должна быть в VM, а View должна узнавать о ней через привязку. Делать специальное событие для запуска анимации вообще неправильно: запуск анимации должен быть доброй волей View. Если вам нужно анимировать смену контента, это можно делать, например, так: https://ru.stackoverflow.com/a/543348/10105 – VladD Dec 02 '18 at 12:52

1 Answers1

1

Если делаеш через MVVM то используй команды вместо событий, во ViewModel:

    private RelayCommand someCommand;
    public RelayCommand SomeCommand
    {
        get
        {
            return someCommand ??
              (someCommand = new SomeCommand(obj =>
              {
                  SomeMethod();
              }));
        }
    }

Реализация RelayCommand:

public class RelayCommand : ICommand
{
    private Action<object> execute;
    private Func<object, bool> canExecute;

    public event EventHandler CanExecuteChanged
    {
        add { CommandManager.RequerySuggested += value; }
        remove { CommandManager.RequerySuggested -= value; }
    }

    public RelayCommand(Action<object> execute, Func<object, bool> canExecute = null)
    {
        this.execute = execute;
        this.canExecute = canExecute;
    }

    public bool CanExecute(object parameter)
    {
        return this.canExecute == null || this.canExecute(parameter);
    }

    public void Execute(object parameter)
    {
        this.execute(parameter);
    }
}

А в контроле который должен выполнять команду просто пропиши:

Command="{Binding SomeCommand}"
  • Каким боком тут команды? Команда это то что дёргают снаружи, чтобы попросить выполнить некую операцию, а у ТС наоборот, VM что-то делает самостоятельно и потом оповещает View – Андрей NOP Nov 30 '18 at 13:21