我有一个用户控件,如下所示,用于主细节类型的显示。一个典型的MVVM体系结构,其基本视图模型与CloseCommand一起完成。
我试图对一个KeyBinding进行定位,它将在TabItem上执行close命令,但无法使它工作。
有趣的是,如果我将绑定放在PersonDetailView ( TabControl可能显示的两种可能的USerControls之一,如下所示)上,那么它就可以工作,但是它应该在包含它的TabControl或边框上。
有什么建议吗?
干杯,
贝瑞尔
UserControl
<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);
}
}发布于 2012-06-09 08:30:12
KeyBindings只在接受键盘输入的控件上工作。通常,InputBindings与CommandBindings的不同之处在于,您可以在父元素上定义CommandBinding,以便在子元素有焦点时处理命令,但不能在父元素上定义InputBindings以使它们对子元素有效。
您可以做的是将默认的InputGesture添加到命令的InputGestures集合中。这似乎使命令可以使用来自每个接受键盘输入的控件的键盘快捷方式(这比在任何地方指定InputBindings要好得多,不是吗?)为了利用这一点,您必须使用RoutedCommand来调用RoutedCommand。您可以使用附加属性组合这两个属性,这种模式我称之为“粘性命令”,非常类似于附加行为。
此代码定义附加属性:
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设置为在InputGestures中具有键盘快捷方式的RoutedCommand,以及Close.MVVMCommand="{Binding CloseCommand}“。
更新
您可以在您的RoutedCommand中定义这样的ViewModel:
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}"https://stackoverflow.com/questions/10958235
复制相似问题