Caliburn Micro'进入'关键事件

时间:2013-05-23 16:45:39

标签: wpf mvvm caliburn.micro

我正在尝试将事件与Caliburn Micro捆绑在一起,并且我在向该方法获取正确消息时遇到了一些问题。我想添加在更改文本框中的值后按“Enter”键的功能,并执行与旁边的按钮绑定的方法相同的方法。但是,无论按哪个键,我都会遇到以下例外情况:

  

“System.InvalidCastException”类型的第一次机会异常   发生在MyApp.exe

中      

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

     

类型的第一次机会异常   发生'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编码不正确得到我想要的吗?或者我完全错过了其他的东西?

2 个答案:

答案 0 :(得分:47)

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

使用完整语法:

    <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=Documentation

修改

好的澄清之后我可以举几个例子来说明 - 我会告诉你我的个人喜好和原因,但选择最适合你的那个

  1. 使用ActionExecutionContext并投射eventargs:
  2.     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
    2.     cal:Message.Attach="[Event KeyDown] = [Action ExecuteFilterView($eventArgs)]"
      
          public void ExecuteFilterView(KeyEventArgs keyArgs)
          {
              if (keyArgs.Key == Key.Enter)
              {
                  // Do Stuff
              }
          }
      
      1. 我的个人喜欢,创建自己的SpecialValues词典条目:
      2. 使用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
            }
        }
        

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

        值得注意的是,如果你有其他类型的控件,那么它们将继承KeyEventArgs。如果它们不是KeyEventArgs的子类但它们仍然返回类型为Key的值,那么它仍然可以正常工作,因为如果第一个失败,您可以向委托添加另一个强制转换:

        e.g。

        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;
        });
        

答案 1 :(得分:3)

如果使用keyeventargs作为参数类型,并且它返回null,那么看看这个: 您可以使用System.Windows.Forms.KeyEventArgsKeyEventArgs,因为参数类型引用了这个,请尝试使用System.Windows.Input.KeyEventArgs(它适用于我)。

public void ExecuteFilterView(System.Windows.Input.KeyEventArgs context)
{
     if(context.Key==System.Windows.Input.Key.Return)
     {
         //action here
     }      
}