将 KeyBinding Command 绑定到 WPF DatePicker (MVVM)



我一直在上下寻找一种以 MVVM 方式将 Return 键绑定到 DatePicker 控件的方法,但无济于事。

我当前的 XAML 标记:

<DatePicker x:Name="DateFilter" SelectedDate="{Binding SearchDate, UpdateSourceTrigger=PropertyChanged}">
<DatePicker.InputBindings>
<KeyBinding Key="Return" Command="{Binding SearchCommand}"></KeyBinding>
</DatePicker.InputBindings>
</DatePicker>

我发现最接近的事情是重写整个控件模板,但这既需要大量标记又搞砸了原始控件外观。

现在,我已经通过从表单代码隐藏中强制将DatePicker InputBindings添加到底层的DatePickerTextBox来破解一个解决方案,但它很糟糕,因为它需要编写代码隐藏并使用反射:

表单代码隐藏(绑定到视图的 Loaded 事件(:

private void UserControl_Loaded(object sender, RoutedEventArgs e)
{
var fiTextBox = typeof(DatePicker)
.GetField("_textBox", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic);
if (fiTextBox?.GetValue(DateFilter) is System.Windows.Controls.Primitives.DatePickerTextBox textBox)
{
textBox.InputBindings.AddRange(DateFilter.InputBindings);
}
}

有没有更好的方法可以做到这一点?

(注意:我无法将命令的执行绑定到绑定 SearchDate 属性的更改,因为该操作非常昂贵,并且我不希望每次用户选择新日期时都会触发它。但是,我需要立即刷新该属性,因为命令的 CanExecute 也与所述日期不为空相关联。

您可以使用可重用的附加行为:

public static class ReturnKeyBehavior
{
public static ICommand GetCommand(UIElement UIElement) =>
(ICommand)UIElement.GetValue(CommandProperty);
public static void SetCommand(UIElement UIElement, ICommand value) =>
UIElement.SetValue(CommandProperty, value);
public static readonly DependencyProperty CommandProperty =
DependencyProperty.RegisterAttached(
"Command",
typeof(ICommand),
typeof(ReturnKeyBehavior),
new UIPropertyMetadata(null, OnCommandChanged));
private static void OnCommandChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
UIElement uie = (UIElement)d;
ICommand oldCommand = e.OldValue as ICommand;
if (oldCommand != null)
uie.RemoveHandler(UIElement.PreviewKeyDownEvent, (KeyEventHandler)OnMouseLeftButtonDown);
ICommand newCommand = e.NewValue as ICommand;
if (newCommand != null)
uie.AddHandler(UIElement.PreviewKeyDownEvent, (KeyEventHandler)OnMouseLeftButtonDown, true);
}
private static void OnMouseLeftButtonDown(object sender, KeyEventArgs e)
{
if(e.Key == Key.Enter)
{
UIElement uie = (UIElement)sender;
ICommand command = GetCommand(uie);
if (command != null)
command.Execute(null);
}
}
}

。可以附加到 XAML 中的任何 UIElement:

<DatePicker local:ReturnKeyBehavior.Command="{Binding ListViewItemMouseLeftButtonDownCommand}" />

然后,您不必处理视图模型中的任何键。

我可能会使用交互触发器,或者您的框架用来将事件转换为命令的任何其他内容,然后捕获 PreviewKeyDown:

<DatePicker x:Name="DateFilter" SelectedDate="{Binding SearchDate, UpdateSourceTrigger=PropertyChanged}"
xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
xmlns:cmd ="http://www.galasoft.ch/mvvmlight">
<i:Interaction.Triggers>
<i:EventTrigger EventName="PreviewKeyDown">
<cmd:EventToCommand Command="{Binding KeyDownCommand}" PassEventArgsToCommand="True"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</DatePicker>

然后在您的视图模型中:

private ICommand _KeyDownCommand;
public ICommand KeyDownCommand => this._KeyDownCommand ?? (this._KeyDownCommand = new RelayCommand<KeyEventArgs>(OnKeyDown));
private void OnKeyDown(KeyEventArgs args)
{
if (args.Key == Key.Return)
{
// do something
}
}

最新更新