Как лучше всего применять WPF MVVM? - PullRequest
2 голосов
/ 17 февраля 2012

Я пытаюсь настроить приложение в стиле MVVM и думаю, что я ввязываюсь в несколько узлов с взаимодействиями этих элементов и надеюсь, что кто-то может помочь.Я что-то здесь не так делаю?

Я полагаю, что мои главные 2 вопроса

  1. Как мне перейти от моей модели к моей точке зрения.В настоящее время я пытаюсь сделать это через конвертер.
  2. Если использование конвертера правильно, как мне заставить это работать правильно?Я полагаю, что текстовый набор данных в конструкторе Node заменяется XAML, который включает в себя конвертер.

Мои классы (немного упрощены):

IFieldDescription

 // Interface that is supposed to be the Model
 public interface IFieldDescription
 {
    String Name { get; }
    bool Disabled { get; }
 }

NodeModel

// Class that is supposed to be the ViewModel
public class NodeModel : NotifyPropertyChanged
{   
    internal NodeModel() { }

    public NodeModel(IFieldDescription fieldDescription)
    {               
       this.FieldDescription = fieldDescription;
    }

    protected IFieldDescription FieldDescription
    {
       get { return this.fieldDescription; }
       set {
        this.fieldDescription = value;
        this.OnPropertyChanged("Name");
        this.OnPropertyChanged("Disabled");
        this.OnPropertyChanged("PrimaryKey");       }
    }
    private IFieldDescription fieldDescription;

    public String Name { get { return this.FieldDescription.Name; } }
    public Boolean Disabled { get { return this.FieldDescription.Disabled; } }
}

Узел Код позади

public Node(NodeModel model)
{
   this.DataContext = model;
   this.InitializeComponent();
}

XAML

<UserControl xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:local="clr-namespace:GO" x:Class="GO.Node" Background="White"
    >

    <Grid x:Name="LayoutRoot">
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="Auto"/>    <!-- Primary Key Icon -->
            <ColumnDefinition Width="Auto"/>    <!-- Type Icon -->
            <ColumnDefinition/>                 <!-- Node Text -->
            <ColumnDefinition Width="Auto"/>    <!-- Option Cog -->
            <ColumnDefinition Width="Auto"/>    <!-- Match Icon -->
            <ColumnDefinition Width="Auto"/>    
        </Grid.ColumnDefinitions>
        <Grid.Resources>
            <local:AttributeDataTypeConverter x:Key="DateTypeConverter"/>
        </Grid.Resources>
        <Image Grid.Column="0" Source="C:\Users\ian.wright\Documents\Expression\Blend 4\Projects\GO\GO\Resources\Images\PrimaryKey.png" Stretch="None" Visibility="{Binding Path=IsPrimaryKey}"/>
        <Image Grid.Column="1" Source="{Binding Path=Type, Converter={StaticResource DateTypeConverter}}" Stretch="None"/>
        <TextBlock Grid.Column="2" Text="{Binding Path=Name}" VerticalAlignment="Bottom" Margin="0,0,0,2"/>
        <Image Grid.Column="3" Source="C:\Users\ian.wright\Documents\Expression\Blend 4\Projects\GO\GO\Resources\Images\Cog.png" Stretch="None" Visibility="{Binding Path=HasOptions}"/>
        <Image Grid.Column="4" Source="{Binding Path=CastType}" Stretch="None"/>
    </Grid>
</UserControl>

MainWindow

<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d"
x:Class="GO.MainWindow"
xmlns:local="clr-namespace:GO"
x:Name="Window"
Title="MainWindow"
Width="640" Height="480">

<Grid Width="200" Height="500">
    <Grid.Resources>
        <local:NodeConverter x:Key="NodeConverter"/>
        <local:ModelToViewConverter x:Key="ModelConverter"/>
    </Grid.Resources>
        <!--<ListView Grid.Column="1" ItemsSource="{Binding Path=FieldDescriptions, Converter={StaticResource ModelConverter}}">-->

    <ListView Grid.Column="1" ItemsSource="{Binding Path=FieldDescriptions}">
        <ListView.ItemTemplate>
            <DataTemplate>
                <local:Node DataContext="{Binding Converter={StaticResource ModelConverter}}" />
            </DataTemplate>
        </ListView.ItemTemplate>
        </ListView>
</Grid>

В качестве контекста данных для главного окна задан новый RD (), который определен ниже: RD

public class RD
    {
        private IEnumerable<IFieldDescription> GetTestData()
        {
            yield return new FieldDescription("String", true);
            yield return new FieldDescription("Integer", false);
            yield return new FieldDescription("Double", false);
            yield return new FieldDescription("Date", false);
            yield return new FieldDescription("Enum", false);
        }

        public virtual ObservableCollection<IFieldDescription> FieldDescriptions
        {
            get { return new ObservableCollection<IFieldDescription>(GetTestData()); }
        }
    }

Любой мой конвертер в настоящее время определяется как:

public class ModelToViewConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            if (value == null)
                return null;

            if (value is IFieldDescription)
            {
                NodeModel model = new NodeModel((IFieldDescription)value);
                return new Node(model);
            }

            return null;
        }

        public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            throw new NotImplementedException();
        }
    }

1 Ответ

4 голосов
/ 17 февраля 2012

Обычно я использую DataTemplates для связывания View с Model или ViewModel

Единственное место, где программный код моего View когда-либо ссылается на Model или ViewModel, находится при запуске, когда он устанавливает начальную ViewModel в качестве стартового View DataContext. Все остальное подключено DataTemplates (или DataTemplateSelectors для Silverlight).

(На самом деле, чтобы быть справедливым, иногда мне нужно сделать что-то особенное, и я отдам объект DataContext как ViewModel или Model в коде, но эти случаи редки, и я рассматриваю их как хаки)

Например, настройка запуска View / ViewModel:

public partial class App : Application
{
    protected override void OnStartup(StartupEventArgs e)
    {
        base.OnStartup(e);

        var app = new ShellView();
        var context = new ShellViewModel();
        app.DataContext = context;
        app.Show();
    }
}

Вот пример некоторых шаблонов данных:

<Window.Resources>
    <DataTemplate DataType="{x:Type local:SomeViewModel}">
        <local:SomeViewForViewModel />
    </DataTemplate>

    <DataTemplate DataType="{x:Type local:SomeModel}">
        <local:SomeViewForModel />
    </DataTemplate>
</Window.Resources>

И, наконец, я буду использовать ContentControls в своем XAML, где я хочу отобразить свои просмотры

<ContentControl Content="{Binding SomeViewModelProperty}" />

или

<ContentControl Content="{Binding SomeModelProperty}" />

Иногда ContentControls даже не нужны. Например, если вы связали ListView с ObservableCollection<NodeModel>, то каждый элемент в ListView будет объектом типа NodeModel, и WPF автоматически выберет DataTemplate для этого.

<ListView ItemsSource="{Binding Path=CollectionOfNodeModel}">
    <ListView.Resources> <!-- Could also put this in Window.Resources -->
        <DataTemplate DataType="{x:Type local:NodeModel}">
            <local:Node /> <!-- DataContext will implicitly be the NodeModel object -->
        </DataTemplate>
    </ListView.Resources>
</ListView>

Идея, лежащая в основе MVVM, заключается в том, что все ваше приложение функционирует в ваших моделях ViewModel, а представления - это просто симпатичный пользовательский интерфейс, который расположен поверх моделей ViewModel, чтобы сделать их более удобными для пользователя. В идеальном мире View можно легко заменить любым другим пользовательским интерфейсом

.

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...