Caliburn Micro'进入'关键事件

spu*_*1r3 17 wpf mvvm caliburn.micro

我试图绑定一个事件与Caliburn Micro,我有一些问题得到正确的消息到该方法.我想添加在更改文本框中的值后按"Enter"键的功能,并执行与旁边的按钮绑定的方法相同的方法.但是,无论按哪个键,我都会遇到以下例外情况:

MyApp.exe中出现"System.InvalidCastException"类型的第一次机会异常

mscorlib.dll中发生了'System.Reflection.TargetInvocationException'类型的第一次机会异常

WindowsBase.dll中出现类型为"System.Reflection.TargetInvocationException"的第一次机会异常

在另一个类似问题绑定KeyDown事件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>
Run Code Online (Sandbox Code Playgroud)

方法:

 public void ExecuteFilterView(ActionExecutionContext context)
    {
        //Do stuff...
    }
Run Code Online (Sandbox Code Playgroud)

我明白我可能会为自己省去一些麻烦,只是在后面的代码中做一个标准的事件处理程序,但这个应用程序是MVVM中的一个练习并学习使用Caliburn.Micro,所以我想坚持使这个特定的方法工作.

我只是想从活动中发送错误的信息吗?我的xaml编码不正确得到我想要的吗?或者我完全错过了其他的东西?

Cha*_*leh 51

刚刚把测试放在一起,这些都适合我:

使用完整语法:

    <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>
Run Code Online (Sandbox Code Playgroud)

使用CM语法(更喜欢这个,因为它更具可读性)

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

这是测试VM:

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

你能发布完整的代码 - 你确定你的框架设置正确吗?(你有没有跟上入门的例子?

http://caliburnmicro.codeplex.com/wikipage?title=Basic%20Configuration%2c%20Actions%20and%20Conventions&referringTitle=Documentation

编辑:

在你澄清之后我可以给你一些如何做到这一点的例子 - 我会告诉你我的个人喜好和原因,但选择最适合你的那个

  1. 使用ActionExecutionContext和转换eventargs:
    cal:Message.Attach="[Event KeyDown] = [Action ExecuteFilterView($executionContext)]"
Run Code Online (Sandbox Code Playgroud)
    public void ExecuteFilterView(ActionExecutionContext context)
    {
        var keyArgs = context.EventArgs as KeyEventArgs;

        if (keyArgs != null && keyArgs.Key == Key.Enter)
        {
            // Do Stuff
        }
    }
Run Code Online (Sandbox Code Playgroud)
  1. EventArgs直接使用
    cal:Message.Attach="[Event KeyDown] = [Action ExecuteFilterView($eventArgs)]"
Run Code Online (Sandbox Code Playgroud)
    public void ExecuteFilterView(KeyEventArgs keyArgs)
    {
        if (keyArgs.Key == Key.Enter)
        {
            // Do Stuff
        }
    }
Run Code Online (Sandbox Code Playgroud)
  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;
});
Run Code Online (Sandbox Code Playgroud)

你的行动:

cal:Message.Attach="[Event KeyDown] = [Action ExecuteFilterView($pressedKey)]"
Run Code Online (Sandbox Code Playgroud)

和代码:

public void ExecuteFilterView(Key key)
{
    if (key == Key.Enter)
    {
        // Do Stuff
    }
}
Run Code Online (Sandbox Code Playgroud)

这是我最喜欢的原因?这意味着你的虚拟机只会收到你想要的值(大多数时候你并不关心其他很多参数)而且你不需要知道如何或者费心去投射事件 - 你可以只是操作在价值上.显然使用最适合你的东西

值得注意的是,如果您有其他类型的控件,那么子类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;
});
Run Code Online (Sandbox Code Playgroud)