gpt4 book ai didi

wpf - 键绑定(bind)问题

转载 作者:行者123 更新时间:2023-12-03 10:16:32 34 4
gpt4 key购买 nike

我有一个如下所示的用户控件,用于显示主详细信息。一个典型的 MVVM 架构,带有一个完整的 CloseCommand 基本 View 模型。

我正在尝试确定将在 TabItem 上执行关闭命令的 KeyBinding 的范围,但无法使其正常工作。

有趣的是,如果我将绑定(bind)放在 PersonDetailView(TabControl 可能显示的两个可能的 USerControl 之一,如下所示)上,我可以让它工作,但它应该在 TabControl 或包含它的 Border 上。

有什么建议么?

干杯,
绿柱石

用户控制

<Grid>

<ListBox Style="{StaticResource ListBoxStyle}" />

<GridSplitter
HorizontalAlignment="Right" VerticalAlignment="Stretch" Grid.Column="1"
ResizeBehavior="PreviousAndNext" Width="5" Background="#FFBCBCBC" KeyboardNavigation.IsTabStop="False"
/>

<Border Grid.Column="2" Background="{StaticResource headerBrush}">

// ** THIS is the scope I want, but it doesn't work
<Border.InputBindings>
<KeyBinding Key="F4" Modifiers="Control" Command="{Binding CloseCommand}"/>
</Border.InputBindings>

<TabControl Style="{StaticResource TabControlStyle}" >

<TabControl.Resources>
<DataTemplate DataType="{x:Type personVm:PersonDetailVm}">
<local:PersonDetailView />
</DataTemplate>
<DataTemplate DataType="{x:Type orgVm:OrganizationDetailVm}">
<local:OrganizationDetailView />
</DataTemplate>
</TabControl.Resources>

</TabControl>
</Border>

</Grid>

TabItem 样式
<Style x:Key="OrangeTabItemStyle" TargetType="{x:Type TabItem}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type TabItem}">
<Border AllowDrop="true" ToolTip="{Binding DisplayName}">
<Border Name="Border" Background="Transparent" BorderBrush="Transparent" BorderThickness="1,1,1,0" CornerRadius="2,2,0,0">
<DockPanel x:Name="TitlePanel" TextElement.Foreground="{StaticResource FileTabTextBrush}">
<ctrl:GlyphButton

// ** This works as expected
Command="{Binding CloseCommand}" CommandParameter="{Binding}"
>
</ctrl:GlyphButton>

</DockPanel>
</Border>

// ** Can't get it to work from here either **
<Border.InputBindings>
<KeyBinding Command="{Binding CloseCommand}" Key="F4" Modifiers="Control" />
</Border.InputBindings>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>

更新

我无法以我的风格设置 RoutedCommand
<Style x:Key="OrangeTabItemStyle" TargetType="{x:Type TabItem}">
<Setter Property="beh:RoutedCommandWire.RoutedCommand" Value="F4"/> **** ?? ****
<Setter Property="beh:RoutedCommandWire.ICommand" Value="{Binding CloseCommand}"/>
</Style>

这是我认为答案代码在 C# 中的样子
public class RoutedCommandWire
{

public static readonly DependencyProperty RoutedCommandProperty =
DependencyProperty.RegisterAttached("RoutedCommand", typeof(RoutedCommand), typeof(RoutedCommandWire), new PropertyMetadata(OnCommandChanged));

public static RoutedCommand GetRoutedCommand(DependencyObject d) { return (RoutedCommand) d.GetValue(RoutedCommandProperty); }
public static void SetRoutedCommand(DependencyObject d, RoutedCommand value) { d.SetValue(RoutedCommandProperty, value); }

public static readonly DependencyProperty ICommandProperty =
DependencyProperty.RegisterAttached("Iommand", typeof(ICommand), typeof(RoutedCommandWire));

public static ICommand GetICommand(DependencyObject d) { return (ICommand) d.GetValue(ICommandProperty); }
public static void SetICommand(DependencyObject d, ICommand value) { d.SetValue(ICommandProperty, value); }

private static void OnCommandChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) {
var fe = d as FrameworkElement;
if(fe==null) return;

if (e.OldValue != null) {
Detach(fe, (RoutedCommand) e.OldValue);
}
if (e.NewValue != null) {
Attach(fe, (RoutedCommand) e.NewValue, Execute, CanExecute);
}
}

private static void CanExecute(object sender, CanExecuteRoutedEventArgs e) {
var depObj = sender as DependencyObject;
if (depObj == null) return;

var command = GetICommand(depObj);
if (command == null) return;

e.CanExecute = command.CanExecute(e.Parameter);
e.Handled = true;
}

private static void Execute(object sender, ExecutedRoutedEventArgs e)
{
var depObj = sender as DependencyObject;
if (depObj == null) return;

var command = GetICommand(depObj);
if (command == null) return;

command.Execute(e.Parameter);
e.Handled = true;
}

public static void Detach(FrameworkElement fe, RoutedCommand command) {
var bindingCollection = fe.CommandBindings;
if (bindingCollection.Count == 0) return;

var matches = bindingCollection.Cast<CommandBinding>().Where(binding => binding.Equals(command));
foreach (var binding in matches) {
bindingCollection.Remove(binding);
}
}

public static void Attach(FrameworkElement fe, RoutedCommand command,
ExecutedRoutedEventHandler executedHandler, CanExecuteRoutedEventHandler canExecuteHandler, bool preview = false)
{
if (command == null || executedHandler == null) return;

var binding = new CommandBinding(command);
if (preview)
{
binding.PreviewExecuted += executedHandler;
if (canExecuteHandler != null)
{
binding.PreviewCanExecute += canExecuteHandler;
}
}
else
{
binding.Executed += executedHandler;
if (canExecuteHandler != null)
{
binding.CanExecute += canExecuteHandler;
}
}
fe.CommandBindings.Add(binding);
}
}

最佳答案

KeyBindings 仅适用于接受键盘输入的控件。边框没有。一般来说,InputBindings 与 CommandBindings 的不同之处在于您可以在父元素上定义 CommandBinding,以便在子元素具有焦点时处理命令,但您不能在父元素上定义 InputBindings 以使它们对子元素有效.

您可以做的是将默认 InputGesture 添加到命令的 InputGestures 集合中。这似乎使命令可以在每个接受键盘输入的控件中使用该键盘快捷键(这比必须在任何地方指定 InputBindings 好得多,不是吗?)。为了利用这一点,您必须使用 RoutedCommand 来调用您的 MVVM-ICommand。您可以使用附加属性将两者结合起来,这种模式我称之为“粘性命令”,它与附加行为非常相似。

此代码定义了附加属性:

    Public Class Close

Public Shared ReadOnly CommandProperty As DependencyProperty = DependencyProperty.RegisterAttached("Command", GetType(RoutedCommand), GetType(Close), New PropertyMetadata(AddressOf OnCommandChanged))
Public Shared Function GetCommand(ByVal d As DependencyObject) As RoutedCommand
Return d.GetValue(CommandProperty)
End Function
Public Shared Sub SetCommand(ByVal d As DependencyObject, ByVal value As RoutedCommand)
d.SetValue(CommandProperty, value)
End Sub

Public Shared ReadOnly MVVMCommandProperty As DependencyProperty = DependencyProperty.RegisterAttached("MVVMCommand", GetType(ICommand), GetType(Close))
Public Shared Function GetMVVMCommand(ByVal d As DependencyObject) As ICommand
Return d.GetValue(MVVMCommandProperty)
End Function
Public Shared Sub SetMVVMCommand(ByVal d As DependencyObject, ByVal value As ICommand)
d.SetValue(MVVMCommandProperty, value)
End Sub


Private Shared Sub OnCommandChanged(ByVal d As DependencyObject, ByVal e As DependencyPropertyChangedEventArgs)
If e.OldValue IsNot Nothing Then
Detach(d, DirectCast(e.OldValue, RoutedCommand))
End If
If e.NewValue IsNot Nothing Then
Attach(d, DirectCast(e.NewValue, RoutedCommand), AddressOf DoCloseCommand, AddressOf CanDoCloseCommand)
End If
End Sub

Private Shared Sub CanDoCloseCommand(ByVal sender As Object, ByVal e As CanExecuteRoutedEventArgs)
If sender IsNot Nothing Then
Dim com As ICommand = GetMVVMCommand(sender)
If com IsNot Nothing Then
e.CanExecute = com.CanExecute(e.Parameter)
e.Handled = True
End If
End If
End Sub

Private Shared Sub DoCloseCommand(ByVal sender As Object, ByVal e As ExecutedRoutedEventArgs)
If sender IsNot Nothing Then
Dim com As ICommand = GetMVVMCommand(sender)
If com IsNot Nothing Then
com.Execute(e.Parameter)
e.Handled = True
End If
End If
End Sub

Public Shared Sub Detach(ByVal base As FrameworkElement, ByVal command As RoutedCommand)
Dim commandBindings As CommandBindingCollection = base.CommandBindings
If commandBindings IsNot Nothing Then
Dim bindings = From c As CommandBinding In commandBindings
Where c.Command Is command
Select c
Dim bindingList As New List(Of CommandBinding)(bindings)
For Each c As CommandBinding In bindingList
commandBindings.Remove(c)
Next
End If
End Sub

Public Shared Sub Attach(ByVal base As FrameworkElement, ByVal command As RoutedCommand, ByVal executedHandler As ExecutedRoutedEventHandler, ByVal canExecuteHandler As CanExecuteRoutedEventHandler, Optional ByVal preview As Boolean = False)
If command IsNot Nothing And executedHandler IsNot Nothing Then
Dim b As CommandBinding = New CommandBinding(command)
If preview Then
AddHandler b.PreviewExecuted, executedHandler
If canExecuteHandler IsNot Nothing Then
AddHandler b.PreviewCanExecute, canExecuteHandler
End If
Else
AddHandler b.Executed, executedHandler
If canExecuteHandler IsNot Nothing Then
AddHandler b.CanExecute, canExecuteHandler
End If
End If
base.CommandBindings.Add(b)
'For Each i As InputGesture In command.InputGestures
' GetInputBindings(base).Add(New InputBinding(command, i))
'Next
End If
End Sub

我猜你会在你的 TabItems 上同时使用它们,因为这是你想要处理关闭命令的地方,你可以将 Close.Command 设置为一个 RoutedCommand,它在 InputGestures 中有键盘快捷键,并且 Close.MVVMCommand= “{绑定(bind)关闭命令}”。

更新

您可以在 ViewModel 中定义这样的 RoutedCommand:

Public Shared ReadOnly TestCommand As New RoutedUICommand("Test", "TestCommand", GetType(ViewModel))
Shared Sub New()
TestCommand.InputGestures.Add(New KeyGesture(Key.T, ModifierKeys.Control))
End Sub

静态构造函数设置命令的默认键位。如果您想在 XAML 中执行此操作,您也可以使用自定义附加属性来执行此操作。无论如何,您会在 XAML 中像这样引用 RoutedCommand:
Close.Command="{x:Static my:ViewModel.TestCommand}"

关于wpf - 键绑定(bind)问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10958235/

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