В этой статье я хочу рассмотреть три способа связывания View c ViewModel.
Способ первый. В коде. Как мне кажется наиболее гибкий вариант. Позволяет использовать параметризированные конструкторы. Это полезно когда, например, вам нужно инжектировать View во ViewModel. Я уже показывал этот способ, когда мы рассматривали ViewModel-First approach.
private void Application_Startup(object sender, StartupEventArgs e)
{
var mainWindow = new MainWindow();
Current.MainWindow = mainWindow;
var viewModel = new MainViewModel(new DataProvider(), mainWindow);
mainWindow.DataContext = viewModel;
mainWindow.Show();
}
Способ второй. Объявить ViewModel как статический ресурс и затем в XAML прописать привязку для View. Этот способ менее гибкий, т.к. для создания ресурса будет использован дефолтный конструктор.
В MVVM Light Toolkit проблему дефолтного конструктора решили. Вместо того чтоб объявлять сам ViewModel как статический ресурс, ресурсом там сделали класс ViewModelLocator, который внутри себя в коде создает нужные ViewModel и соответственно может использовать параметризованные конструкторы. Однако, я пока не нашел решения как используя этот способ инжектировать View во ViewModel.
Этот способ мы уже тоже видели в примерах, где использовался MVVM Light Toolkit.
<Application.Resources>
<vm:ViewModelLocator x:Key="Locator"
d:IsDataSource="True" />
</Application.Resources>
<Window
DataContext="{Binding Main, Source={StaticResource Locator}}">
Способ третий. Наверное не совсем очевидный но тем не менее. Внутри DataTemplate свойство DataContext всегда хранит ссылку на объект, к которому это DataTemplate применяется. Если использовать термины MVVM, то DataTemplate – это View, а сам объект – это ViewModel. Т.е. внутри DataTemplate можно привязывать UI контролы к любым свойствам и командам, которые светит объект.
Давайте рассмотрим небольшой пример демонстрирующий использование DataTemplate. За основу возьмем демо приложение из предыдущих статей. Список тегов для него я взял со StackOverflow. Давайте добавим к тегам еще их рейтинг. Описывать каждый тег теперь будет тип TagInfo. Это будет наш ViewModel.
public sealed class TagInfo
{
public string Name { get; set; }
public int Score { get; set; }
}
А вот так выглядит DataTemplate для TagInfo.
<DataTemplate DataType="{x:Type m:TagInfo}">
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Name}" MinWidth="150" />
<TextBlock Text="{Binding Score}" />
</StackPanel>
</DataTemplate>
Если помните, ListBox в главном окне привязан к коллекции Tags из MainViewModel. Раньше эта коллекция хранила строки, а теперь объекты TagInfo. Когда ListBox захочет отобразить свои элементы, то он надет для них наш DataTemplate и подставит ему в DataContext соответствующий TagInfo.
Вот так будет выглядеть список тегов после применения DataTemplate.
Исходный код этого примера можно скачать отсюда.
No comments:
Post a Comment