2017-03-27 45 views
0

私は、MVVMパターンを厳密に守りながら、メモリゲームを作成しようとしています。今私は実行時にビューを作成することに問題があります。C#MVVM動的にビューを作成する方法

  • Modelプロジェクト
  • -MemoryCardModel30
  • -card
  • のViewModelプロジェクト
  • -MainWindowViewModel
  • -CardViewModel:

    私は、次のプロジェクト構造を作成しました

  • Viewプロジェクト
  • -CardView
  • てstartApplicationプロジェクト
  • -MainWindowView

次のように依存関係は次のとおりです。てstartApplicationプロジェクト - > Viewプロジェクト - >のViewModelプロジェクト - >モデルプロジェクト

MainWindowViewのボタンをクリックすると、そのボタンのICommand機能MainWindowViewModel内のModelCodeModel30インスタンスがModelプロジェクトからロードされます。 MemoryCardModel30インスタンス内の各Cardに対して、CardViewModelが作成されます。

CardViewインスタンスを作成する方法、DataViewextをCardViewModelsにリンクする方法、およびCardViewをMainWindowViewに配置/割り当てる方法について教えてください。 ViewModelプロジェクトはViewプロジェクトに依存しないため、ビューを作成できません(循環依存を作成してパターンを分割します)。 MVVMパターンに従ってこの問題を解決するには?

P .:カードビューは、xとyの位置によって正確に配置する必要があります。対応するCardViewModelに行くべき複雑な計算が必要になります。グリッドのようないくつかの基本的なレイアウトは十分ではないと私は思います。

+0

フレームワークを使用していて、アプローチは「モデルファースト」か「ビューファースト」ですか?また、WrapPanelを使用して、必要な操作を行うこともできます。https://msdn.microsoft.com/en-us/library/system.windows.controls.wrappanel(v=vs.110).aspx –

+0

MV ** P ** VMを私の仕事で使う理由は、モデルをビューにリンクして表示することは、MVVMにうまく収まる仕事ではなく、プレゼンターの仕事です。 –

+0

@BerinLoritschいいえ、現時点ではフレームワークを使用していません。私は最初からパターンを学びたかったのです。私は、EntityFrameworkのコンテキストでは「モデル・ファースト」に慣れていますが、MVVMではそうではありません。しかし、この場合は、ViewModelからモデルを作成し、ビューを最後に開始しました。 – user2653422

答えて

4

ItemsControlに表示してください。私はMainWindowViewModel.CardsObservableCollection<CardViewModel>と仮定しています。

<ItemsControl 
    ItemsSource="{Binding Cards}" 
    > 
    <!-- 
    This creates UI for each item. There are other ways, if you've got a collection 
    of heterogeneous item types. 
    --> 
    <ItemsControl.ItemTemplate> 
     <DataTemplate DataType="local:CardViewModel"> 
      <views:CardView /> 
     </DataTemplate> 
    </ItemsControl.ItemTemplate> 

    <!-- 
    Make it use a Canvas to be the actual container for the items, so we can control 
    their position arbitrarily, instead of the default StackPanel that just stacks 
    them up vertically. 
    --> 
    <ItemsControl.ItemsPanel> 
     <ItemsPanelTemplate> 
      <Canvas /> 
     </ItemsPanelTemplate> 
    </ItemsControl.ItemsPanel> 

    <!-- 
    The ItemsControl will put the instantiated item templates in ContentPresenters 
    that it creates. The positioning attributes have to go on the ContentPresenters, 
    because those are the direct children of the Canvas. The ContentPresenters are 
    the "item containers". You can customize them via the ItemContainerStyle property 
    of the ItemsControl. 
    --> 
    <ItemsControl.ItemContainerStyle> 
     <Style TargetType="ContentPresenter"> 
      <!-- 
      The datacontext will be CardViewModel. 

      Bind Canvas.Left and Canvas.Top to appropriate properties 
      of CardViewModel. I'll assume it's got Point Position { get; } 

      A much better, more "pure MVVM" way to do this is for the items to 
      provide some kind of abstraction, maybe row/column or something else, 
      and either place them in a Grid or UniformGrid or some other kind of 
      dynamic layout control, or else convert that abstraction into Canvas 
      coordinates with a value converter on the Binding. 

      Then you can display the same item objects in different ways at the same 
      time without locking them into one layout. 

      Don't drive yourself crazy striving for ideological purity at the expense 
      of getting code out the door, but do consider redesigning that part. 
      --> 

      <Setter Property="Canvas.Left" Value="{Binding Position.X}" /> 
      <Setter Property="Canvas.Top" Value="{Binding Position.Y}" /> 
     </Style> 
    </ItemsControl.ItemContainerStyle> 

これは、WPF/MVVMで標準的な方法です。適切なタイプのビュー・インスタンスを作成するには、DataTemplateを使用します。ビューモデルは、どのオブジェクトをユーザに提示すべきかを担当する。それらのビューがどのように表示されているかについてのビューがあります。このためにMVVMフレームワークを必要としない、または必要としません。 WPFの組み込みのDataTemplate機能は非常に強力です。あなたがこのサイズの2桁の大きさのプロジェクトのために何か他のものが必要だと考える人は誰も信じてはいけません。

+1

私は座標をVMレイヤに置くのではなく、それらを抽象化して、コンバータを介してビューレイヤで解決されます。 – Rekshino

+0

@Rekshinoそれはそれを行うのに正しい(または少なくとも正しい)方法です。私は適切に答えを更新します。 –

0

私はあなたの質問を誤解したと思います。私はもともと、特定のビューモデル用に新しいウィンドウを表示する方法を尋ねていると思っていました。この回答は特にあなたには当てはまりませんが、接線関係にあるので、私はそれを残しておきます。それは、他の人々が何を検索するのか混乱するのを助けるかもしれません。


ビュータイプをビューモデルタイプにリンクするViewManagerクラスがあります。

  • はそのviewmodelのタイプのビューを検索します。その上で方法の一つは、それがのviewmodelのインスタンスを取得して、このタスクを処理することShowViewForです。
  • そのビューのインスタンスを作成します。
  • このビューインスタンスのDataContextを、渡されたビューモデルに設定します。
  • ビューを表示します。等また、メッセージボックスおよびダイアログを表示する、オープンビューを追跡するような他のタスクの束を行い

ViewManagerは、インターフェースを介してIOC容器も使用可能であり、それがためにアップ嘲笑することができます単体テスト。

そこには既存のフレームワークがたくさんあると確信していますが、あなたのように、MVVMを "ルーツアップ"から学びたいと思っていました。

関連する問題