bit*_*ise 15 silverlight xaml eventtrigger invoke-command
我想在a中按下ENTER时调用一个命令TextBox
.考虑以下XAML:
<UserControl
...
xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
...>
...
<TextBox>
<i:Interaction.Triggers>
<i:EventTrigger EventName="KeyUp">
<i:InvokeCommandAction Command="{Binding MyCommand}"
CommandParameter="{Binding Text}" />
</i:EventTrigger>
</i:Interaction.Triggers>
</TextBox>
...
</UserControl>
Run Code Online (Sandbox Code Playgroud)
并且MyCommand如下:
public ICommand MyCommand {
get { return new DelegateCommand<string>(MyCommandExecute); }
}
private void MyCommandExecute(string s) { ... }
Run Code Online (Sandbox Code Playgroud)
使用上面的命令,我会在每次按键时调用我的命令.如何将命令限制为仅在按下ENTER键时调用?
我理解使用Expression Blend我可以使用条件,但这些似乎仅限于元素,不能考虑事件参数.
我也遇到过SLEX,它提供了自己的InvokeCommandAction
实现,它构建在Systems.Windows.Interactivity
实现之上,可以满足我的需求.另一个考虑是编写我自己的触发器,但我希望有一种方法可以在不使用外部工具包的情况下完成.
Art*_*tru 21
表达式混合中有KeyTrigger.
<UserControl
xmlns:i="clr-namespace:System.Windows.Interactivity;
assembly=System.Windows.Interactivity"
xmlns:iex="clr-namespace:Microsoft.Expression.Interactivity.Input;
assembly=Microsoft.Expression.Interactions" ...>
<TextBox>
<i:Interaction.Triggers>
<iex:KeyTrigger Key="Enter">
<i:InvokeCommandAction Command="{Binding PasswordLoginCommand}" />
</iex:KeyTrigger>
</i:Interaction.Triggers>
</TextBox>
</UserControl>
Run Code Online (Sandbox Code Playgroud)
System.Windows.Interactivity
和Microsoft.Expression.Interactions
官方Nuget包中的WPF可以使用程序集.
bit*_*ise 16
我喜欢scottrudy的方法(我给了+1)使用自定义触发器方法,因为它坚持我的初始方法.我在下面包含了它的修改版本,以使用依赖属性而不是反射信息,这样就可以直接绑定到ICommand.我还包括一种使用附加属性的方法,以避免System.Windows.Interactivity
在需要时使用.对后一种方法的警告是,您失去了事件中多次调用的功能,但您可以更普遍地应用它.
自定义触发器方法
ExecuteCommandAction.cs
public class ExecuteCommandAction : TriggerAction<DependencyObject> {
#region Properties
public ICommand Command {
get { return (ICommand)base.GetValue(CommandProperty); }
set { base.SetValue(CommandProperty, value); }
}
public static ICommand GetCommand(DependencyObject obj) {
return (ICommand)obj.GetValue(CommandProperty);
}
public static void SetCommand(DependencyObject obj, ICommand value) {
obj.SetValue(CommandProperty, value);
}
// We use a DependencyProperty so we can bind commands directly rather
// than have to use reflection info to find them
public static readonly DependencyProperty CommandProperty =
DependencyProperty.Register("Command", typeof(ICommand), typeof(ExecuteCommandAction), null);
#endregion Properties
protected override void Invoke(object parameter) {
ICommand command = Command ?? GetCommand(AssociatedObject);
if (command != null && command.CanExecute(parameter)) {
command.Execute(parameter);
}
}
}
Run Code Online (Sandbox Code Playgroud)
TextBoxEnterKeyTrigger.cs
public class TextBoxEnterKeyTrigger : TriggerBase<UIElement> {
protected override void OnAttached() {
base.OnAttached();
TextBox textBox = this.AssociatedObject as TextBox;
if (textBox != null) {
this.AssociatedObject.KeyUp += new System.Windows.Input.KeyEventHandler(AssociatedObject_KeyUp);
}
else {
throw new InvalidOperationException("This behavior only works with TextBoxes");
}
}
protected override void OnDetaching() {
base.OnDetaching();
AssociatedObject.KeyUp -= new KeyEventHandler(AssociatedObject_KeyUp);
}
private void AssociatedObject_KeyUp(object sender, KeyEventArgs e) {
if (e.Key == Key.Enter) {
TextBox textBox = AssociatedObject as TextBox;
//This checks for an mvvm style binding and updates the source before invoking the actions.
BindingExpression expression = textBox.GetBindingExpression(TextBox.TextProperty);
if (expression != null)
expression.UpdateSource();
InvokeActions(textBox.Text);
}
}
}
Run Code Online (Sandbox Code Playgroud)
MyUserControl.xaml
<UserControl
...
xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
xmlns:b="clr-namespace:MyNameSpace.Interactivity"
...
<TextBox>
<i:Interaction.Triggers>
<b:TextBoxEnterKeyTrigger>
<b:ExecuteCommandAction Command="{Binding MyCommand}" />
</b:TextBoxEnterKeyTrigger>
</i:Interaction.Triggers>
</TextBox>
...
</UserControl>
Run Code Online (Sandbox Code Playgroud)
附属物方法
EnterKeyDown.cs
public sealed class EnterKeyDown {
#region Properties
#region Command
public static ICommand GetCommand(DependencyObject obj) {
return (ICommand)obj.GetValue(CommandProperty);
}
public static void SetCommand(DependencyObject obj, ICommand value) {
obj.SetValue(CommandProperty, value);
}
public static readonly DependencyProperty CommandProperty =
DependencyProperty.RegisterAttached("Command", typeof(ICommand), typeof(EnterKeyDown),
new PropertyMetadata(null, OnCommandChanged));
#endregion Command
#region CommandArgument
public static object GetCommandArgument(DependencyObject obj) {
return (object)obj.GetValue(CommandArgumentProperty);
}
public static void SetCommandArgument(DependencyObject obj, object value) {
obj.SetValue(CommandArgumentProperty, value);
}
public static readonly DependencyProperty CommandArgumentProperty =
DependencyProperty.RegisterAttached("CommandArgument", typeof(object), typeof(EnterKeyDown),
new PropertyMetadata(null, OnCommandArgumentChanged));
#endregion CommandArgument
#region HasCommandArgument
private static bool GetHasCommandArgument(DependencyObject obj) {
return (bool)obj.GetValue(HasCommandArgumentProperty);
}
private static void SetHasCommandArgument(DependencyObject obj, bool value) {
obj.SetValue(HasCommandArgumentProperty, value);
}
private static readonly DependencyProperty HasCommandArgumentProperty =
DependencyProperty.RegisterAttached("HasCommandArgument", typeof(bool), typeof(EnterKeyDown),
new PropertyMetadata(false));
#endregion HasCommandArgument
#endregion Propreties
#region Event Handling
private static void OnCommandArgumentChanged(DependencyObject o, DependencyPropertyChangedEventArgs e) {
SetHasCommandArgument(o, true);
}
private static void OnCommandChanged(DependencyObject o, DependencyPropertyChangedEventArgs e) {
FrameworkElement element = o as FrameworkElement;
if (element != null) {
if (e.NewValue == null) {
element.KeyDown -= new KeyEventHandler(FrameworkElement_KeyDown);
}
else if (e.OldValue == null) {
element.KeyDown += new KeyEventHandler(FrameworkElement_KeyDown);
}
}
}
private static void FrameworkElement_KeyDown(object sender, KeyEventArgs e) {
if (e.Key == Key.Enter) {
DependencyObject o = sender as DependencyObject;
ICommand command = GetCommand(sender as DependencyObject);
FrameworkElement element = e.OriginalSource as FrameworkElement;
if (element != null) {
// If the command argument has been explicitly set (even to NULL)
if (GetHasCommandArgument(o)) {
object commandArgument = GetCommandArgument(o);
// Execute the command
if (command.CanExecute(commandArgument)) {
command.Execute(commandArgument);
}
}
else if (command.CanExecute(element.DataContext)) {
command.Execute(element.DataContext);
}
}
}
}
#endregion
}
Run Code Online (Sandbox Code Playgroud)
MyUserControl.xaml
<UserControl
...
xmlns:b="clr-namespace:MyNameSpace.Interactivity"
...
<TextBox b:EnterKeyDown.Command="{Binding AddNewDetailCommand}"
b:EnterKeyDown.CommandArgument="{Binding Path=Text,RelativeSource={RelativeSource Self}}" />
...
</UserControl>
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
21205 次 |
最近记录: |