gpt4 book ai didi

wpf - 文本框MVVM内的按键

转载 作者:行者123 更新时间:2023-12-03 23:31:22 26 4
gpt4 key购买 nike

我刚刚开始使用 MVVM,并且在弄清楚如何将文本框中的按键绑定(bind)到 View 模型中的 ICommand 时遇到问题。我知道我可以在代码隐藏中做到这一点,但我试图尽可能避免这种情况。

更新:到目前为止,如果您有 blend sdk 或者您没有遇到我所拥有的交互 dll 问题,那么到目前为止的解决方案都很好。除了必须使用 blend sdk 之外,还有其他更通用的解决方案吗?

最佳答案

首先,如果你想绑定(bind)一个 RoutedUICommand 很容易 - 只需添加到 UIElement.InputBindings 集合:

<TextBox ...>
<TextBox.InputBindings>
<KeyBinding
Key="Q"
Modifiers="Control"
Command="my:ModelAirplaneViewModel.AddGlueCommand" />

当您尝试设置 Command="{Binding AddGlueCommand}"以从 ViewModel 获取 ICommand 时,您的麻烦就开始了。由于 Command 不是 DependencyProperty,因此您无法在其上设置 Binding。

您的下一个尝试可能是创建一个附加属性 BindableCommand,该属性具有更新 Command 的 PropertyChangedCallback。这确实允许您访问绑定(bind),但由于 InputBindings 集合未设置 InheritanceContext,因此无法使用 FindAncestor 查找您的 ViewModel。

显然,您可以创建一个附加属性,您可以将其应用于 TextBox,该属性将贯穿所有 InputBindings 调用 BindingOperations.GetBinding 以查找命令绑定(bind)并使用显式源更新这些绑定(bind),从而允许您执行以下操作:
<TextBox my:BindingHelper.SetDataContextOnInputBindings="true">
<TextBox.InputBindings>
<KeyBinding
Key="Q"
Modifiers="Control"
my:BindingHelper.BindableCommand="{Binding ModelGlueCommand}" />

这个附加属性很容易实现:在 PropertyChangedCallback 上,它将在 DispatcherPriority.Input 安排“刷新”并设置一个事件,以便在每次 DataContext 更改时重新安排“刷新”。然后在刚才的“刷新”代码中,只需在每个InputBinding上设置DataContext:
...
public static readonly SetDataContextOnInputBindingsProperty = DependencyProperty.Register(... , new UIPropetyMetadata
{
PropertyChangedCallback = (obj, e) =>
{
var element = obj as FrameworkElement;
ScheduleUpdate(element);
element.DataContextChanged += (obj2, e2) =>
{
ScheduleUpdate(element);
};
}
});
private void ScheduleUpdate(FrameworkElement element)
{
Dispatcher.BeginInvoke(DispatcherPriority.Input, new Action(() =>
{
UpdateDataContexts(element);
})
}

private void UpdateDataContexts(FrameworkElement target)
{
var context = target.DataContext;
foreach(var inputBinding in target.InputBindings)
inputBinding.SetValue(FrameworkElement.DataContextProperty, context);
}

两个附加属性的替代方法是创建一个 CommandBinding 子类,它接收路由命令并激活绑定(bind)命令:
<Window.CommandBindings>
<my:CommandMapper Command="my:RoutedCommands.AddGlue" MapToCommand="{Binding AddGlue}" />
...

在这种情况下,每个对象中的 InputBindings 将引用路由命令,而不是绑定(bind)。然后,此命令将向上路由到 View 并进行映射。

CommandMapper 的代码比较简单:
public class CommandMapper : CommandBinding
{
... // declaration of DependencyProperty 'MapToCommand'

public CommandMapper() : base(Executed, CanExecute)
{
}
private void Executed(object sender, ExecutedRoutedEventArgs e)
{
if(MapToCommand!=null)
MapToCommand.Execute(e.Parameter);
}
private void CanExecute(object sender, CanExecuteRoutedEventArgs e)
{
e.CanExecute =
MapToCommand==null ? null :
MapToCommand.CanExecute(e.Parameter);
}
}

就我的口味而言,我更愿意使用附加属性解决方案,因为它的代码不多,并且使我不必两次声明每个命令(作为 RoutedCommand 和作为我的 ViewModel 的属性)。支持代码只出现一次,可以在您的所有项目中使用。

另一方面,如果您只做一个一次性的项目并且不期望重用任何东西,那么即使是 CommandMapper 也可能是矫枉过正。正如您所提到的,可以简单地手动处理事件。

关于wpf - 文本框MVVM内的按键,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1711038/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com