Как правильно написать на MVVM?

Подскажите, как правильно использовать шаблон MVVM в WPF приложении. Пример классов:

Использование контрола в стороннем классе (Создание из кода):
BrowserView someBrowser = new BrowserView();
	container.Children.Add(someBrowser);
	someBrowser.Navigate("http://google.ru/");
	someBrowser.SomeControlText = "Перешёл на сайт google.ru";


View класс:
public partial class BrowserView : UserControl
	{
		BrowserViewModel viewModel;
		public BrowserView()
		{
			InitializeComponent();
			viewModel = new BrowserViewModel(this.GetType());
			this.DataContext = viewModel;
		}
		
        public string SomeControlText
        {
            get { return viewModel.Model.SomeControlText; }
            set { viewModel.Model.SomeControlText = value; }
        }
		
        public void Navigate(string newAddress)
        {
            viewModel.Model.SomeBrowser.Address = newAddress;
        }
	}

XAML:
<UserControl x:Class="GPClient.View.BrowserView">
		<Grid x:Name="BrowserContainer">
			<ContentControl Content="{Binding Path=Model.SomeBrowser}"></ContentControl>
		</Grid>
		<SomeControl Text="{Binding Path=Model.SomeControlText}" />
	</UserControl>



ViewModel класс:
public class BrowserViewModel : Notifier
    {
        public BrowserModel Model { get; private set; }
        public BrowserViewModel(Type typeControl)
        {
            Model = new BrowserModel();
			
            ChromiumWebBrowser browser = new ChromiumWebBrowser();
            Model.SomeBrowser = browser;
        }
    }


Model класс:
public class BrowserModel : Notifier
    {
        ChromiumWebBrowser someBrowser;
        public ChromiumWebBrowser SomeBrowser
        {
            get { return someBrowser; }
            set { someBrowser = value; OnPropertyChanged("SomeBrowser"); }
        }
		
        string someControlText;
        public string SomeControlText
        {
            get { return someControlText; }
            set { someControlText = value; OnPropertyChanged("SomeControlText"); }
        }
    }


Есть пара конкретных вопросов:
1) Допустим, я хочу изменить свойство Text у SomeControl.
Это свойство забиндено на Model.SomeControlText.
Как правильно это сделать?
- Есть вариант viewModel сделать публичным и обратитсья вот так:
someBrowser.viewModel.Model.SomeControlText = "какой-то текст";


- Есть вариант продублировать это свойство в ViewModel (при этом viewModel так же сделать публичным) и сделать вот так:
someBrowser.viewModel.SomeControlText = "какой-то текст";


- Ещё вариант, создать свойство во View и сделать как-то так:
public string SomeControlText
        {
            get { return viewModel.Model.SomeControlText; }
            set { viewModel.Model.SomeControlText = value; }
        }

Обращаться вот так:
someBrowser.SomeControlText = "какой-то текст";
Вопрос, какой из этих вариантов правильный и если никакой, то как это делается?

2) Я хочу изменить свойство Address у объекта ChromiumWebBrowser в ViewModel. Есть такие-же варианты как в прошлом вопросе. А как это делать правильно?

Что я делаю не так? Или все верно?
  • Вопрос задан
  • 3873 просмотра
Решения вопроса 1
yarosroman
@yarosroman Куратор тега C#
C# the best
Для начала, возьмите какой нибудь MVVM framework (SimpleMVVM, MVVMLight, у них есть куча примеров), делаем свой view, ViewModel. В этих фрейморках уже реализованы базовые классы для создания VM (реализован INotyfyPropertyChanged). В VM надо добавить необходимые свойства, с которыми будет привязка свойств элементов. Так же желательно сделать класс-сервис, который будет создавать по требованию модель, экземпляр класса прописать в App.Resources, и биндить необходимую VM сразу в Xalm, к DataContext="{Binding GroupsViewModel, Mode=OneWay, Source={StaticResource Locator}}">(у локатора есть свойство GroupsViewModel, в котором зоздается необходимый VM, передаются все параметры на сервисы (например работа с БД).

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

те, например в вашем случае:

locator.cs
public class Locator
{
  public MainViewModel MainVM 
  {
      get {return new MainViewModel(); }
  }
}


MainViewModel.cs
public class MainViewModel : Notifier
    {
       MainViewModel ()
       {
       }

        string address;
        public string Address;
        {
            get { return address; }
            set { address = value; OnPropertyChanged("Address"); }
        }

        string someControlText;
        public string SomeControlText
        {
            get { return someControlText; }
            set { someControlText = value; OnPropertyChanged("SomeControlText"); }
        }
    }


в App.xaml в ресурсы прописываем (естественно добавляем необходимые xmlns)
<Locator x:Key="Locator"/>

MainView.xaml
<UserControl x:Class="GPClient.View.BrowserView" DataContext="{Binding MainViewModel, Source={StaticResource Locator}}">>
    <ChromiumWebBrowser Address="{Binding Path=Address, Mode=TwoWay}"/>
    <SomeControl Text="{Binding Path=SomeControlText, Mode=TwoWay}" />
  </UserControl>


Все дело в Mode=TwoWay. если элемент сам устанавливает свойство, то оно автоматом обновляется в VM, и наоборот, те если вам надо перейти на адрес, в методе в VM пишем Address="http://перейди-на.сайт"; обращаемся к полю VM, а не к приватному члену, иначе не вызовется PropertyChanged, с SomeText, так же.
Если у нас есть TextBox, то привязка таким образом позволяет получать введенное в него значение.

для привязки методов, и событий, используются Command и триггеры в XAML.

У вас тут немного спутано понятие ViewModel и Model. В VM прописываются, свойства, к которым будет привязка элементов View, а Model, это данные с которыми мы работаем, например модель БД, классы в которые сериализуется XML.

Скачайте MVVMLight, SimpleMVVM, это простые фреймворки, с хорошими примерами и легковесные.
Ответ написан
Пригласить эксперта
Ответы на вопрос 1
Casper-SC
@Casper-SC
Программист (.NET)
Если актуалити, то могу показать пример с библиотекой MvvmLight.
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы