问题描述
我正在尝试将事件与Caliburn Micro绑定在一起,但是在将正确的消息发送给该方法时遇到了一些问题.我想增加在文本框中更改值后按"Enter"键的功能,它执行与旁边的按钮绑定到的方法相同的方法.但是,无论按下哪个键,我都会遇到以下异常:
I am attempting to bind an event with Caliburn Micro and I am having some issues getting the right messages to the method. I would like to add the ability to press the 'Enter' key after changing the value in a text box and it execute the same method that the button next to is bound to. However, regardless of which key is pressed, I get the following exceptions:
类型的第一次机会异常 mscorlib.dll中发生了'System.Reflection.TargetInvocationException'
A first chance exception of type 'System.Reflection.TargetInvocationException' occurred in mscorlib.dll
类型的第一次机会异常 "System.Reflection.TargetInvocationException"发生在 WindowsBase.dll
A first chance exception of type 'System.Reflection.TargetInvocationException' occurred in WindowsBase.dll
在另一个类似的问题绑定KeyDown事件Silverlight 的建议下,我尝试了使用ActionExecutionContext,但无济于事.
At the suggestion of another, similar question Binding KeyDown Event Silverlight, I've tried using ActionExecutionContext, but to no avail.
这是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,因此,我坚持这样做特殊的方法工作.
I understand that I could probably save myself some headaches and simply do a standard event handler in the code behind, but this app is an exercise in MVVM and learning to utilize Caliburn.Micro, so I would like to stick with making this particular approach work.
我只是想从事件中发送错误的信息吗?我的xaml是否没有正确编码才能得到我想要的东西?还是我完全错过了其他东西?
Am I just trying to send the wrong information from the event? Is my xaml not coded properly to get what I want? Or I have missed something else entirely?
推荐答案
只需一起进行测试,这两项对我都有效:
Just threw a test together, both of these work for me:
使用完整语法:
<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语法(建议使用此语法,因为它更具可读性)
Using CM syntax (prefer this as it's way more readable)
<TextBox Name="Threshold"
Margin="5"
Grid.Column="1"
cal:Message.Attach="[Event KeyDown] = [Action ExecuteFilterView($executionContext)]" />
这是测试虚拟机:
public class MainWindowViewModel
{
public void ExecuteFilterView(ActionExecutionContext context)
{
// This method is hit and the context is present and correct
}
}
您可以发布完整的代码-您确定框架设置正确吗? (您是否遵循了入门示例?
Can you post your full code - are you sure you have the framework setup correctly? (have you followed the getting started example?
好的,在您澄清之后,我可以为您提供一些有关如何执行此操作的示例-我会告诉您我的个人偏好和原因,但是请选择最适合您的
Ok after your clarification I can give you some examples of how to do this - I'll tell you my personal preference and why, but choose the one that fits you best
- 使用
ActionExecutionContext
并投射eventargs:
- Using
ActionExecutionContext
and casting the eventargs:
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
}
}
- 直接使用
EventArgs
cal:Message.Attach="[Event KeyDown] = [Action ExecuteFilterView($eventArgs)]"
public void ExecuteFilterView(KeyEventArgs keyArgs)
{
if (keyArgs.Key == Key.Enter)
{
// Do Stuff
}
}
- 我个人的最爱,创建了自己的
SpecialValues
词典条目:
- My personal fave, creating your own
SpecialValues
dictionary entry:
在您的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-您可以进行操作的价值.显然使用最适合您的东西
The reason this is my favourite? It means that your VM just receives the value you want (most of the time you don't care about a lot of the other parameters) and you don't need to know how to or bother to cast the eventargs - you can just operate on the value. Obviously use whatever is best for you
还值得注意的是,如果您具有子类KeyEventArgs
的其他类型的控件,则它们将对它们起作用.如果他们不继承KeyEventArgs
的子类,但是它们仍然返回类型Key
的值,那么它也仍然可以工作,因为如果第一个失败,则可以向委托添加另一个强制类型转换:
It's also worth noting, that if you have other types of controls that subclass KeyEventArgs
this will work for them. If they don't subclass KeyEventArgs
but they still return a value of type Key
this will still work too as you can just add another cast to the delegate if the first one fails:
例如
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;
});
这篇关于Caliburn Micro"Enter"键事件的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!