20

イベントを Caliburn Micro にバインドしようとしていますが、メソッドに正しいメッセージを取得する際に問題が発生しています。テキストボックスの値を変更した後に「Enter」キーを押す機能を追加したいと思います。これにより、隣のボタンがバインドされているのと同じメソッドが実行されます。ただし、どのキーが押されても、次の例外が発生します。

タイプ 'System.InvalidCastException' の初回例外が MyApp.exe で発生しました

タイプ 'System.Reflection.TargetInvocationException' の初回例外が mscorlib.dll で発生しました

タイプ 'System.Reflection.TargetInvocationException' の初回例外が WindowsBase.dll で発生しました

別の同様の質問Binding KeyDown Event Silverlightの提案で、私は ActionExecutionContext を使用しようとしましたが、役に立ちませんでした。

xaml は次のとおりです。

<TextBox Name="Threshold"                     
              Margin="5"
              Grid.Column="1"
              >
     <i:Interaction.Triggers>
         <i:EventTrigger EventName="KeyDown">
             <cal:ActionMessage MethodName="ExecuteFilterView">
                 <cal:Parameter Value="$executionContext"/>
             </cal:ActionMessage>
         </i:EventTrigger>
     </i:Interaction.Triggers>
</TextBox>

そして方法:

 public void ExecuteFilterView(ActionExecutionContext context)
    {
        //Do stuff...
    }

おそらく頭の痛い問題を解決し、コード ビハインドで標準のイベント ハンドラーを実行するだけで済むことは理解していますが、このアプリは MVVM の演習であり、Caliburn.Micro の利用方法を学習しているため、この特定のアプローチを機能させることに固執したいと思います。 .

イベントから間違った情報を送信しようとしているだけですか? 私のxamlは、私が望むものを得るために適切にコーディングされていませんか? または、何か他のものを完全に見逃していますか?

4

3 に答える 3

55

一緒にテストを投げただけで、これらは両方とも私にとってはうまくいきます:

完全な構文を使用する:

    <TextBox Name="Threshold"                     
          Margin="5"
          Grid.Column="1">
        <i:Interaction.Triggers>
            <i:EventTrigger EventName="KeyDown">
                <cal:ActionMessage MethodName="ExecuteFilterView">
                    <cal:Parameter Value="$executionContext"/>
                </cal:ActionMessage>
            </i:EventTrigger>
        </i:Interaction.Triggers>
    </TextBox>

CM 構文を使用する (読みやすいため、これをお勧めします)

    <TextBox Name="Threshold"                     
          Margin="5"
          Grid.Column="1"
          cal:Message.Attach="[Event KeyDown] = [Action ExecuteFilterView($executionContext)]" />            

これはテスト VM でした。

public class MainWindowViewModel
{
    public void ExecuteFilterView(ActionExecutionContext context)
    { 
        // This method is hit and the context is present and correct
    }
}

完全なコードを投稿できますか - フレームワークが正しくセットアップされていると確信していますか? (開始例に従っていますか?

http://caliburnmicro.codeplex.com/wikipage?title=Basic%20Configuration%2c%20Actions%20and%20Conventions&referringTitle=ドキュメント

編集:

あなたの明確化の後、私はあなたにこれを行う方法のいくつかの例を与えることができます.私の個人的な好みとその理由をお話しします.

  1. ActionExecutionContexteventargs の使用とキャスト:
    cal:Message.Attach="[Event KeyDown] = [Action ExecuteFilterView($executionContext)]"
    public void ExecuteFilterView(ActionExecutionContext context)
    {
        var keyArgs = context.EventArgs as KeyEventArgs;

        if (keyArgs != null && keyArgs.Key == Key.Enter)
        {
            // Do Stuff
        }
    }
  1. EventArgs直接使用する
    cal:Message.Attach="[Event KeyDown] = [Action ExecuteFilterView($eventArgs)]"
    public void ExecuteFilterView(KeyEventArgs keyArgs)
    {
        if (keyArgs.Key == Key.Enter)
        {
            // Do Stuff
        }
    }
  1. 私の個人的なお気に入りは、独自のSpecialValues辞書エントリを作成することです。

あなたのBootstrapper.Configure方法では...

MessageBinder.SpecialValues.Add("$pressedkey", (context) =>
{
    // NOTE: IMPORTANT - you MUST add the dictionary key as lowercase as CM
    // does a ToLower on the param string you add in the action message, in fact ideally
    // all your param messages should be lowercase just in case. I don't really like this
    // behaviour but that's how it is!
    var keyArgs = context.EventArgs as KeyEventArgs;

    if (keyArgs != null)
        return keyArgs.Key;

    return null;
});

あなたの行動:

cal:Message.Attach="[Event KeyDown] = [Action ExecuteFilterView($pressedKey)]"

そしてコード:

public void ExecuteFilterView(Key key)
{
    if (key == Key.Enter)
    {
        // Do Stuff
    }
}

これが私のお気に入りの理由は?これは、VM が必要な値を受け取るだけであることを意味し (ほとんどの場合、他の多くのパラメーターは気にしません)、eventargs をキャストする方法を知る必要も、わざわざキャストする必要もありません。操作するだけで済みます。値について。明らかにあなたに最適なものを使用してください

また、サブクラス化する他のタイプのコントロールがある場合、KeyEventArgsこれが機能することにも注意してください。それらがサブクラス化されていないKeyEventArgsが、型の値を返すKey場合でも、最初のキャストが失敗した場合に別のキャストをデリゲートに追加できるため、これも機能します。

例えば

MessageBinder.SpecialValues.Add("$pressedkey", (context) =>
{
    var keyArgs = context.EventArgs as KeyEventArgs;

    if (keyArgs != null)
        return keyArgs.Key;

    // Ok so it wasn't KeyEventArgs... check for some other type - maybe a 3rd party implementation
    var thirdPartyKeyArgs = context.EventArgs as ThirdPartyKeyArgs;

    if (thirdPartyKeyArgs != null)
        return thirdPartyKeyArgs.KeyProperty;

    return null;
});
于 2013-05-24T09:35:04.513 に答える