2

別のユーザー コントロール 'B' を子として持つユーザー コントロール 'A' があります。ユースケースのシナリオは、ユーザーが「A」のボタンをクリックすると、「B」に何らかの情報 (通常は「B」の状態に関連する) を処理して結果を取得するように要求する必要があり、その結果は何らかの計算で使用されます。 「A」で。

現在、MVVM パターンを使用しています。「A」のビューモデルには、A または B の UI への参照がありません。まさにこれを探しています。ユーザーが「A」の UI のボタンをクリックすると、「B」でコマンドを呼び出す必要があります。 '、'A' のビューモデルでデリゲートをパラメーターとしてそのコマンドに渡すことによって。このようにして、'B' のコマンドが情報を処理するときに、'A' から渡されたコールバック関数を呼び出すことができます。

現在、デリゲートはパラメーターなしです。ユーザーコントロール 'B' のコマンドが何らかの情報を処理すると、状態が更新されます。この状態は、'A' のビューモデル内のプロパティにバインドされる依存プロパティです。

このようなことを達成する方法はありますか?

現在、実用的なソリューションがあります。しかし、私はコードを即興で改善したいと考えています。これは、この問題に対する現在の一時的な回避策です。

ユーザーが「A」のボタンをクリックすると、「A」(xaml.cs) にイベント ハンドラーがあります。イベントハンドラーでは、'B' の参照があるので、'B' のコマンドが実行できるかどうかを確認して呼び出します。次に、コマンド ('A' のビューモデル内) を実行できるかどうかを確認し、それを呼び出します。

私の質問が十分に説明的でない場合は、それをサポートするコード サンプルを次に示します。

'A' の XAML:

<bNameSpace:B x:Name="BObject" DepenPropertyInB="{Binding PropInA, Mode=OneWayToSource}"/>
....
<telerik:RadButton Content="Process" HorizontalAlignment="Right" Height="30" Width="80" Grid.Column="2" Click="ProcessButton_Click" />

A の XAML.cs:

private void ProcessButton_Click(object sender, RoutedEventArgs e)
{
    if (BObject.StateDataRequestedCommand.CanExecute(""))
        BObject.StateDataRequestedCommand.Execute("");

    if(ViewModel.ProcessInfoRequestedCommand.CanExecute(""))
        ViewModel.ProcessInfoRequestedCommand.Execute("");
}

A の ViewModel:

private void OnProcessInfoRequestedCommand(string anyValue)
{
    // read the value of PropInA and do some processing
}

Bのビューモデル:

private void OnStateDataRequestedCommand(string anyValue)
{
    // Bases on B's state do some calc and update DepenPropertyInB
}
4

2 に答える 2

2

後で詳細を追加しますが、基本的に必要だと思うことは次のとおりです。

クリックDelegateCommandには、A と B の両方のビュー モデルへの参照を含む型の実装が必要です。ビュー モデルをインスタンス化し、適切な参照をコマンド オブジェクトに渡すことができる、ある種の「コンダクター」クラスが必要です。


したがって、明らかにコマンドは A のビュー モデルに属します、B への参照が必要です。したがって、それを念頭に置いてコマンド クラスを設定します。

public MyCommand : ICommand
{
    private readonly ViewModelA _a, ViewModelB _b;

    public MyCommand(ViewModelA a, ViewModelB b)
    {
        _a = a;
        _b = b;
    }

    public bool CanExecute(object arg)
    {
        // can-execute logic here
    }

    public void Execute(object arg)
    {
        _b.StateDataRequestedCommand.Execute("");
        _a.ProcessInfoRequestedCommand.Execute("");
    }
}

さて、しかしMyCommandのインスタンスを A の View Model に...

public MyCommand StateRequestedCommand { get; set; }

そして、通常どおりバインドします...

<telerik:RadButton Command="{Binding StateRequestedCommand}" />

ここでの課題は、A のビュー モデル内でこのクラスを何らかの方法でインスタンス化することです。通常、NInject を使用して外部依存関係をクラスに注入しますが、それにはさまざまな方法があります。いずれにしても、ViewModelB への参照がないため、ViewModelA 自体よりも高いレベルで発生する必要があります。これは、App_Startup ロジック、IoC (NInject など) バインディング、またはビュー モデルの「ロケーター」 (使用している場合) にある可能性があります。

于 2012-09-10T01:04:52.650 に答える
2

Each command require CommandParameter and you use it but send "" instead of a real parameter. A parameter can be anytype because it decleared as object. So you can send any object as a parameter to any command.

class CommandA : ICommand
{
  void Execute(object param)
  {
    var commandB = param as CommandB;
    if(commandB != null)
    {
      commandB.Execute((int a) => {
          // continue your code here
        });
    }
  }

  bool CanExecute(object param)
  {
    return param is CommandB;
  }
}

class CommandB : ICommand
{
  void Execute(object param)
  {
    var action = param as Action<int>;
    if(action != null)
    {
      action(10);
    }
  }
}

class MVA
{
  CommandA CommandA{get;}
  CommandB CommandB{get;}
}

XAML:

<Control x:Name="A" Command="{Binding CommandA}" CommandParameter="{Binding Command, ElementName="B"}">
  <Control x:Name="B" Command="{Binding CommandB} />
</Control>
于 2012-09-10T01:57:12.523 に答える