Являются ли шаблоны данных устаревшими в MVVM? - PullRequest
2 голосов
/ 18 апреля 2011

Я создал следующую модель (код упрощен для иллюстрации ситуации):

public abstract class Account
{
    public string Name { get; set; }
}

public class Person : Account
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
}

public class Company : Account
{
    public string Owner { get; set; }
}

Далее я создал модель вида:

public class ViewModel
{
    public Account Model { ... }
    public string Name { ... }
    public string FirstName { ... }
    public string LastName { ... }
    public string Owner { ... }   
    ...
}

И, наконец, мнение:

<UserControl>
  <UserControl.Resources>

    <!-- Person data template -->
    <DataTemplate x:Key="personTemplate" DataType="{x:Type model:Person}">
      <Grid DataContext="{Binding ElementName=rootLayout, Path=DataContext}">
        <TextBlock Text="{Binding Path=Name}" />
        <TextBlock Text="{Binding Path=FirstName}" />
        <TextBlock Text="{Binding Path=LastName}" />
      </Grid>
    </DataTemplate>

    <!-- Company data template -->
    <DataTemplate x:Key="companyTemplate" DataType="{x:Type model:Company}">
      <Grid DataContext="{Binding ElementName=rootLayout, Path=DataContext}">
        <TextBlock Text="{Binding Path=Name}" />
        <TextBlock Text="{Binding Path=Owner}" />
      </Grid>
    </DataTemplate>

    <!-- Data template selector for different account types -->
    <local:AccountTemplateSelector x:Key="templateSelector" 
        PersonTemplate="{StaticResource personTemplate}" 
        CompanyTemplate="{StaticResource companyTemplate}" />

  </UserControl.Resources>

  <StackPanel Name="rootLayout" DataContext="{Binding Path=viewModel}">
    <ContentControl Content="{Binding Path=Model}" 
        ContentTemplateSelector="{StaticResource templateSelector}"/>
    <Button Content="Save" />
    <Button Content="Close" />
  </StackPanel>

</UserControl>

Итак, когда загруженная модель имеет тип Person, отображается personTemplate; наоборот, когда модель Company, отображается companyTemplate.

Мои вопросы:

  1. Имеет ли этот подход смысл? Разумнее было бы удалить Model свойство в классе ViewModel и ввести перечисление или просто bool который покажет человеку, если true, или компании, если `ложь?
  2. При определении шаблонов данных я указывал DataType с Person и Company типы (это было естественно для меня). Нужно ли это вообще, потому что в самом Следующая строка Я устанавливаю новый контекст данных, который будет из UserControl?
  3. Если DataType s шаблонов данных будут разными моделями представления, что-то вроде PersonViewModel и CompanyViewModel? Имеет ли смысл их создавать?
  4. Как я могу, и могу ли я вообще заставить шаблон данных наследовать контекст данных из ContentControl автоматически?

Я знаю, что в конечном итоге все это зависит от личного выбора, но так как я изучаю MVVM (я использую MVVM Light), мне интересно, какой подход будет наиболее рекомендуемым? Я до сих пор не до конца понимаю, когда следует использовать классы из моделей в качестве типов данных для шаблонов данных и когда следует использовать модели просмотра для этой цели. Следует ли ссылаться на сборку, которая представляет модель, даже в сборке вида (при условии, что вид, модель и модель вида находятся в отдельных сборках)?

Спасибо за все разъяснения!

ОБНОВЛЕНИЕ:

Это обновление должно объяснить проблему наличия классов модели как DataType s в шаблонах данных, когда свойство класса модели напрямую не привязано только к одному элементу управления в представлении.

В Person есть перечисление и новое свойство, поэтому теперь оно выглядит так:

public class Person : Account
{
    public enum GenderType { Female, Male, NotSpecified }

    public string FirstName { get; set; }
    public string LastName { get; set; }
    public GenderType Gender {get; set; }
}

И в представлении, шаблон данных человека также изменяется, конечно:

<!-- Person data template -->
<DataTemplate x:Key="personTemplate" DataType="{x:Type model:Person}">
  <Grid DataContext="{Binding ElementName=rootLayout, Path=DataContext}">
    <TextBlock Text="{Binding Path=Name}" />
    <TextBlock Text="{Binding Path=FirstName}" />
    <TextBlock Text="{Binding Path=LastName}" />
    <RadioButton Name="Female" />
    <RadioButton Name="Male" />
    <RadioButton Name="NotSpecified" />
  </Grid>
</DataTemplate>

Если Content для ContentControl установлено в Model свойство ViewModel, как бы я разрешил ситуацию с полами / переключателями; потому что теперь они не совпадают по способу один элемент управления / одно свойство?

Ответы [ 2 ]

2 голосов
/ 18 апреля 2011

Я бы изменил это на следующее:

<UserControl>
  <UserControl.Resources>
    <!-- Person data template -->
    <DataTemplate DataType="{x:Type model:Person}">
      <Grid>
        <TextBlock Text="{Binding Path=Name}" />
        <TextBlock Text="{Binding Path=FirstName}" />
        <TextBlock Text="{Binding Path=LastName}" />
        <RadioButton Name="Female"       IsChecked="{Binding Gender , Converter={StaticResource enumBooleanConverter}, ConverterParameter=Female}" />
        <RadioButton Name="Male"         IsChecked="{Binding Gender , Converter={StaticResource enumBooleanConverter}, ConverterParameter=Male}" />
        <RadioButton Name="NotSpecified" IsChecked="{Binding Gender , Converter={StaticResource enumBooleanConverter}, ConverterParameter=NotSpecified }" />
      </Grid>
    </DataTemplate>

    <!-- Company data template -->
    <DataTemplate DataType="{x:Type model:Company}">
      <Grid>
        <TextBlock Text="{Binding Path=Name}" />
        <TextBlock Text="{Binding Path=Owner}" />
      </Grid>
    </DataTemplate>
  </UserControl.Resources>

  <StackPanel DataContext="{Binding viewModel}">
    <ContentControl Content="{Binding Model}" />
    <Button Content="Save" />
    <Button Content="Save" />
    <Button Content="Close" />
  </StackPanel>

</UserControl>

вот так вы определяете неявные стили для ваших классов, и вам не нужно использовать шаблонный селектор.Кроме того, вам не нужны все ваши строковые свойства в классе ViewModel:

public class ViewModel
{
    public Account Model { ... } 
    ...
}

Отказ от ответственности, привязка в RadioButtons использует конвертер из здесь .

0 голосов
/ 18 апреля 2011

Абсолютно положительно, нет (они устарели).

  1. Да, это имеет смысл, однако ваши привязки, не так много.Эти проблемы могут быть решены различными способами.Например, Учетная запись может иметь свойство Parent, которое предоставляет ViewModel, в которой она содержится (я не говорил, что это был лучший подход).
  2. Это проблема с дизайном ViewModel, где вы должны связатьне против учетной записи, но ViewModel.Может быть возможно изменить дизайн так, чтобы вам не нужно было это делать;Трудно сказать с предоставленным снимком.
  3. Я не думаю, что это поможет вам на этом этапе.Я бы посмотрел, есть ли способ не допустить вашего пользовательского интерфейса, связанного с ViewModel, из DataTemplate.
  4. Вот одно хорошее решение: Создание DataTemplateSelector , который выбирает шаблонна основе свойства Account.Таким образом, вы можете привязать ItemsSource непосредственно к DataContext, и он будет доступен в DataTemplate.
...