2012-09-07 3 views
10

Я работаю над созданием своей первой игры с использованием C# и XAML для Windows 8. Я все еще изучаю основные концепции и лучшие практики, а MVVM - это препятствие. Я попытаюсь задать вопрос в двух частях.MVVM и иерархия View/ViewModel

фон

Игра Делаю это Sudoku. Судоку имеет доску, которая содержит сетку из 9x9 плиток. У меня три модели: Game, Board и Tile. Когда создается Game, он автоматически создает Board, а когда создается Board, он создает 81 (9x9) .

1. С иерархией представлений, как создаются соответствующие модели представлений?

Чтобы соответствовать иерархии моделей, я хотел бы иметь иерархию взглядов (GameView содержит BoardView, который содержит 81 TileViews). В XAML довольно легко создать эту иерархию представлений с помощью пользовательских элементов управления, но я не понимаю, как создаются модели представлений.

В примерах, которые я видел, контекст данных пользовательского элемента управления часто устанавливается на модель представления (с использованием ViewModelLocator в качестве источника), который создает новый экземпляр модели представления. Кажется, это хорошо работает, если у вас есть плоский вид, но также кажется, что он становится беспорядочным, когда у вас есть иерархия. Создает ли GameView и оставьте его до своего ребенка BoardView, чтобы создать BoardViewModel? Если да, то как связывается с BoardViewModel? Может ли BoardViewModel восстановить иерархию до ?

2. Как модель представления получает данные модели?

В iOS я бы начал с использования службы для извлечения модели Game, которая была предварительно заполнена данными. Затем я создавал бы контроллер вида GameViewController (который отвечал за создание представления) и передал ему Game. В MVVM я вижу, что значение имеет представление о создании собственной модели представления (в идеале с использованием ViewModelLocator), но я не понимаю, как эта модель представления получает модель.

Во всех примерах, которые я нашел в Интернете, модель представления использует некоторую услугу для извлечения собственных данных. Но я не сталкивался ни с одним примером, который принимает параметры конструктора или параметры, передаваемые с более высокого уровня навигации. Как это делается?

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

Не только нужна ссылка на Game модели, но BoardViewModel, который был создан каким-то образом (см вопроса 1) необходим ссылка на Board модели, которая принадлежит к Game модели. То же самое касается всех . Как вся эта информация передается по цепочке? Могу ли я сделать этот очень тяжелый подъем полностью в XAML, или мне придется делать какую-то привязку или другую инициализацию в коде?

Фу!

Я ценю любые советы, которые вы можете дать, даже если это не полный ответ. Я также хочу найти примеры проектов MVVM, которые имеют сходные проблемы для моих собственных. Благодаря тонну!

+0

Я думаю, вы говорите о проблеме вложенных пользовательских элементов управления (см. Http://catel.catenalogic.com/index.htm?gs_viewscontrols_nested_user_controls_problem.htm). Кабель сам по себе недоступен для WinRT (бета-версия), но вы можете хотя бы понять, как я думаю, что это нужно сделать. –

ответ

14

Я бы начал с создания класса для начала приложения. Обычно я называю этот класс что-то вроде ApplicationViewModel или ShellViewModel, хотя технически он может выполнять различные правила, чем то, что я, как правило, используют для ViewModel

Этот класс получает реализованным при запуске, и является DataContext для ShellView или ApplicationView

// App.xaml.cs 
private void OnStartup(object sender, StartupEventArgs e) 
{ 
    var shellVM = new ShellViewModel(); 
    var shellView = new ShellView();  
    shellView.DataContext = shellVM; 
    shellView.Show(); 
} 

Это, как правило, единственное место, где я устанавливаю DataContext для компонента пользовательского интерфейса напрямую. С этого момента вашиМинистеры просмотра - это приложение. Важно помнить об этом при работе с MVVM. Ваши представления - это просто удобный интерфейс, который позволяет пользователям взаимодействовать с ViewModels. На самом деле они не считаются частью кода приложения.

Например, ваш ShellViewModel может содержать:

  • BoardViewModel CurrentBoard
  • UserViewModel CurrentUser
  • ICommand NewGameCommand
  • ICommand ExitCommand

и ваш ShellView может содержать что-то вроде этого:

<DockPanel> 
    <Button Command="{Binding NewGameCommand}" 
      Content="New Game" DockPanel.Dock="Top" /> 
    <ContentControl Content="{Binding CurrentBoard}" /> 
</DockPanel> 

Это будет на самом деле сделать вашу BoardViewModel объект в UI, как ContentControl.Content. Чтобы указать, как нарисовать BoardViewModel, вы можете указать DataTemplate в ContentControl.ContentTemplate или использовать неявный DataTemplates.

Неявный DataTemplate - это просто DataTemplate для класса, не связанного с ним связанным с ним x:Key. WPF будет использовать этот шаблон в любое время, когда он сталкивается с объектом указанного класса в пользовательском интерфейсе.

Таким образом, используя

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

будет означать, что вместо рисования

<ContentControl> 
    BoardViewModel 
</ContentControl> 

он будет рисовать

<ContentControl> 
    <local:BoardView /> 
</ContentControl> 

Теперь BoardView может содержать что-то вроде

<ItemsControl ItemsSource="{Binding Squares}"> 
    <ItemsControl.ItemTemplate> 
     <ItemsPanelTemplate> 
      <UniformGrid Rows="3" Columns="3" /> 
     </ItemsPanelTemplate> 
    <ItemsControl.ItemTemplate> 
</ItemsControl> 

и он нарисовал бы доску, используя 3x3 UniformGrid, с каждой ячейкой, содержащей содержимое вашего массива Squares.Если BoardViewModel.Squares свойства оказалось массивом TileModel объектов, то каждая ячейка сетки будет содержать TileModel, и вы можете снова использовать неявные DataTemplate сказать WPF как рисовать каждый TileModel

Теперь о том, как ваш ViewModel получает его фактические объекты данных, это зависит от вас. Я предпочитаю абстрагировать весь доступ к данным за классом, например Repository, и попросить ViewModel просто позвонить примерно как SodokuRepository.GetSavedGame(gameId);. Это упрощает тестирование и поддержку приложения.

Однако вы получаете свои данные, помните, что ViewModel и Models являются вашим приложением, поэтому они должны нести ответственность за получение данных. Не делайте этого в View. Лично мне нравится поддерживать мой уровень Model для простых объектов, которые хранят только данные, поэтому всегда выполняйте операции доступа к данным из моих ViewModels.

Для связи между ViewModels, на самом деле у меня есть article on my blog. Подводя итог, используйте систему обмена сообщениями, такую ​​как или MVVM Light Messenger Microsoft Prism. Они работают как своего рода пейджинговая система: любой класс может подписаться на получение сообщений определенного типа, и любой класс может передавать сообщения.

Например, ваш ShellViewModel может подписаться на получение сообщений ExitProgram и закрыть приложение, когда оно его прослушивает, и вы можете транслировать сообщение ExitProgram из любой точки приложения.

Я полагаю, что другой метод заключается в том, чтобы просто присоединить обработчики из одного класса в другой, например, позвонить CurrentBoardViewModel.ExitCommand += Exit; из ShellViewModel, но я нахожу это беспорядочным и предпочитаю использовать систему обмена сообщениями.

В любом случае, я надеюсь, что ответы на некоторые из ваших вопросов и укажут вам в правильном направлении. Goodluck с вашим проектом :)

+0

Ничего себе, это много, чтобы переварить! Позвольте мне обобщить, чтобы увидеть, есть ли у меня: представления родителя будут содержать ContentTemplates с атрибутом контента, установленным для просмотра объектов модели. DataTemplates определяют те ContentTemplates, которые содержат соответствующие представления. Это означает, что вы не используете ViewModelLocator или IoC, правильно? –

+0

Кроме того, доступ к данным по-прежнему касается меня. Если модель представления отвечает за выборку собственной модели, есть ли способ указать дополнительную информацию о том, какую модель использовать? Если у меня есть сложные головоломки и простые головоломки, как я могу рассказать о своей новой GameViewModel, которая головоломка для использования? –

+2

@BrentTraut Лично мне не нравится использовать ViewModelLocator. С ним существуют некоторые ограничения, например, вы можете иметь только один экземпляр вашего ViewModel и не передавать его параметры. Я предпочитаю создавать свое приложение в коде, и пользовательский интерфейс просто предоставляет удобный интерфейс для моих классов. – Rachel

Смежные вопросы