0

基幹業務プロジェクトに MVVM パターンを実装する最初の試み。次のような簡単な答えがあると思われる質問に出くわしています。

プロトタイプ ウィンドウは、アイテム リストの基本的なマスター詳細ビューです。(Person オブジェクトのリスト)。ビューには、マスター リストの Infragistics xamDataGrid が含まれています。グリッドでアイテムが選択されると、下の詳細パネルで詳細を編集できます。詳細パネルのフィールドをタブで移動すると、更新がグリッド データに「リアルタイム」で表示されます。唯一のことは、「プレスト」が必要ないことです。「[変更を適用] ボタンを押すまで待ち​​たい」ということです。

詳細パネルで追加/削除/変更しているアイテムの作業セットからマスターリストを分離するために、リストの別のインスタンスを作成しないようにしたいと考えていました。

私が行った道:

バインディングを「OneWay」に設定できるように、グリッド フィールドの CellValuePresenter スタイルをオーバーライドしました。これにより、リアルタイムの更新が妨げられます。

<ControlTemplate TargetType="{x:Type igDP:CellValuePresenter}">
  <ControlTemplate.Resources>
    <Style TargetType="TextBlock">
      <Setter Property="Background" Value="{Binding Path=DataItem.NameUIProperty.IsDirty, Converter={StaticResource BooleanBrushConverter}}" />
      <Setter Property="IsEnabled" Value="{Binding Path=DataItem.NameUIProperty.IsEditable}" />
    </Style>
  </ControlTemplate.Resources>
  <ContentControl>
    <TextBlock Text="{Binding Path=DataItem.Name, Mode=OneTime}" />
  </ContentControl>                                                     
</ControlTemplate>      

次に、「ApplyUpdates」コマンド (RelayCommand) を PersonListViewModel に追加します。これにより、「PERSON _ITEM_UPDATED」メッセージが発生します。MVVM Foundation Messenger および RelayCommand クラスの VB ポートを使用しています。

#Region "ApplyUpdates Command"

Private mApplyUpdatesCommand As New RelayCommand(AddressOf ApplyUpdates)
Public ReadOnly Property ApplyUpdatesCommand() As ICommand
    Get
        Return mApplyUpdatesCommand
    End Get
End Property

Private Sub ApplyUpdates()
    'the changes are already in the object in the list so we don't have to do anything here except fire off the Applied message
    Messages.AppMessenger.NotifyColleagues(Messages.PERSON_ITEM_UPDATED)
End Sub

#End Region

PersonView は PERSON _ITEM_UPDATED メッセージを登録し、メッセージの受信時にグリッドを再バインドします。

'In Loaded Event

'register for window messages we care about
Messages.AppMessenger.Register(Messages.PERSON_ITEM_UPDATED, AddressOf OnPersonItemUpdated)

'EventHandler
Private Sub OnPersonItemUpdated()
  PersonGrid.DataSource = Nothing
  PersonGrid.DataSource = mViewModel.List
End Sub

それで、それはうまくいきますが、それは間違ったにおいがします. ビューにはあまりにも多くのロジックが含まれているようで、ViewModel は UI の状態を指示していません。ビューはそうです。

私は何が欠けていますか?ビューへの変更の公開を遅らせるために ViewModel を取得するには、どのような方法を使用しますか?

更新: 現在、グリッド用のカスタム ViewModel (読み取り専用、Propertychanged 通知なし) と詳細領域用の編集可能な ViewModel を作成する道をたどっています。両方の VM が同じビジネス オブジェクトをラップしますが、読み取り専用バージョンは変更を発行しません。これにより、ビューがいつ更新されるかを VM が制御できるようになります。

4

2 に答える 2

0

インフラジスティックデータグリッドのフィールドレイアウトを宣言するときは、Fieldの代わりにUnboundFieldを使用できます。このクラスは、基になるバインディングのBindingPathプロパティとBindingModeプロパティを公開します。この手法を使用すると、リアルタイムの更新を取り除くことができ、カスタムコントロールテンプレートは必要ありません。

ロジックをVMに移動することについての私の考え:

グリッドのDataSourceとnViewModel.Listの一方向バインディングを作成します。次に、ApplyChangesは:BindingOperations.GetBindingExpressionBase(dependencyObject, dependencyProperty).UpdateTarget();を呼び出して、ターゲットプロパティDataSourceを強制的に更新します。残念ながら、これによりVMがバインディングに関連付けられますが、ビューにコードが表示されなくなります。

ここでの大きな問題は、この遅延バインディングシナリオがある場合、ApplyChangesは、ビューのみが実際に更新を行う方法を知っているため(Bindingなどを使用して)、ビューにIoCを実際に必要とするものであるということです。最終的に、チェーンに沿った何かがリストの2つのインスタンスを管理します。ビュー内のインスタンスとVM内の実際のインスタンスです。この特定のシナリオでは、更新の遅延はビューの動作のようです。ただし、VMのUpdateChangesコマンドは、実際にはその動作をVMに結合します。その場合、2つのリストインスタンスをVMに保存するのが理にかなっていると思います。

お役に立てれば。

于 2009-11-30T18:31:01.810 に答える