我有一个如下所示的用户控件,用于显示主详细信息。一个典型的 MVVM 架构,带有一个完整的 CloseCommand 基本视图模型。
我正在尝试确定将在 TabItem 上执行关闭命令的 KeyBinding 的范围,但无法使其正常工作。
有趣的是,如果我将绑定放在 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);
}
}