web-dev-qa-db-ja.com

親のDataContextの使用(WPF-動的メニューコマンドバインディング)

私はこのウェブとグーグルを調べましたが、解決策は私にとってはうまくいきませんでした。

UserControlのViewModelにコマンドがあります。ユーザーコントロールには、ObservableCollectionにバインドされたItemsControlがあります。 ItemsControl.ItemTemplateのDataTemplate内にボタンがあり、コマンドを使用したいと思います。 DataTemplate内で、datacontextはViewModelではなく、ObservableCollectionのアイテムであるため、コマンドをバインドできません。

問題は、親のデータコンテキストが失われた場合にボタンをコマンドにバインドするにはどうすればよいですか。

これは一般的な問題だと思うので、簡単な解決策が必要だと思います。

このシーンを想像してみてください。

ItemsSourceとしてobservableCollectionを持つListBoxアイテムがあるため、コレクション内のすべての要素のListBox内でdatatemplateを使用しています。さて、あなたは選択したアイテムを削除したいと思い、その仕事のためにすべての行にボタンを置きます。 thatどうやってやるの?

MVPでは、ボタンのクリックイベントでこれを行うことができます。

Button but = e.Source as Button;

if (but != null)
      Presenter.ActualNote = but.DataContext as Note;

要するに。行(選択したアイテム)のデータコンテキストをプレゼンターに送信します。

しかし、どうすればmvvmのようにできますか?コマンドを使用する必要がありますが、ボタンにViewModel(コマンドが存在する場所)について何も知らないため、コマンドをボタンに割り当てることができません。

ご覧のように、ボタンはdatatemplate内に存在する必要があり、datacontextはViewModelではなくなります。コマンドにアクセスするために、親のDataContextにアクセスする必要があるのはそのためです。

私の問題をよりよく理解していただければ幸いです。

ありがとうございました。

30
Jesus Rodriguez

ダーティなMVVMを壊すソリューションが必要な場合は、ボタンにTag = "{Binding}"を設定して、Clickイベントを処理します。イベントハンドラーで、ViewModelのコマンドを呼び出します。

5
geofftnz

以下のバインディングをボタンのコマンドに使用します。

{Binding DataContext.CommandName, 
         RelativeSource={RelativeSource FindAncestor, 
                         AncestorType={x:Type MyUserControl}}}

これは、ユーザーコントロールを見つけてそのDataContextを使用するように指示します。

89
Eddie Deyo

では、モデルビュー全体を参照するプロパティを持つようにデータアイテムクラスを変更する方法はどうでしょうか。

ItemsSourceのタイプがObservableCollection<DataItem>の場合、DataItemタイプを次のように変更します。

public class DataItem
{
    public BusinessObject Value { get; set; }

    private ModelView modelView;

    public ModelView ModelView
    {
        get
        {
            return modelView;
        }
    }

    public DataItem(ModelView modelView)
    {
        this.modelView = modelView;
    }
}
3

RelativeSourceは機能しますが、コントロールが互いのプロパティ間を移動できるようにするのは適切ではないと思います。奇妙なことに、アイテムビュー内に配置されたボタンが、バインドされたアイテムではなく、外部データソースで何かを実行します。プログラムコードの設計を確認する必要があるかもしれません。

2