C + Ctrl KeyBinding不会导致复制发生

时间:2011-02-18 12:29:19

标签: wpf xaml .net-3.5

我设置了ListBox,如此:

<ListBox ItemsSource="{Binding Logs, Mode=OneWay}" x:Name="logListView">
    <ListBox.ItemTemplate>
        <DataTemplate>
            <TextBlock Text="{Binding Path=.}">
                <TextBlock.InputBindings>
                    <KeyBinding Key="C"
                                Modifiers="Ctrl"
                                Command="Copy"/>
                </TextBlock.InputBindings>
                <TextBlock.CommandBindings>
                    <CommandBinding Command="Copy"
                                    Executed="KeyCopyLog_Executed"
                                    CanExecute="CopyLog_CanExecute"/>
                </TextBlock.CommandBindings>
                <TextBlock.ContextMenu>
                    <ContextMenu>
                        <MenuItem Command="Copy">
                            <MenuItem.CommandBindings>
                                <CommandBinding Command="Copy"
                                                Executed="MenuCopyLog_Executed"
                                                CanExecute="CopyLog_CanExecute"/>
                            </MenuItem.CommandBindings>
                        </MenuItem>
                    </ContextMenu>
                </TextBlock.ContextMenu>
            </TextBlock>
        </DataTemplate>
    </ListBox.ItemTemplate>
</ListBox>

如您所见,在模板中,每个TextBlock都有一个上下文菜单,允许用户复制文本。这很有效。

同样在TextBlock中有一个KeyBinding ctrl + c 和一个CommandBinding要复制。当我按 ctrl + c 时,不执行方法KeyCopyLog_Executed。我已经检查过调试器。

我应该如何将密钥绑定到TextBlock

2 个答案:

答案 0 :(得分:11)

这里有几个问题。

首先,KeyBindings仅在当前关注元素位于内部定义KeyBindings的元素时才有效。在您的情况下,您有一个ListBoxItem焦点,但KeyBindings是在子元素TextBlock上定义的。因此,在KeyBindings上定义TextBlock在任何情况下都不起作用,因为TextBlock无法获得焦点。

其次,您可能需要知道要复制的内容,因此需要将当前选定的日志项作为参数传递给Copy命令。

此外,如果您在ContextMenu元素上定义TextBlock,只有右键单击TextBlock时才会打开它。如果单击列表项的任何其他部分,它将无法打开。因此,您需要在列表框项目本身上定义ContextMenu

考虑到所有这些,我认为你想要做的事情可以通过以下方式完成:

<ListBox ItemsSource="{Binding Logs, Mode=OneWay}"
         x:Name="logListView"
         IsSynchronizedWithCurrentItem="True">
    <ListBox.InputBindings>
        <KeyBinding Key="C"
                    Modifiers="Ctrl"
                    Command="Copy"
                    CommandParameter="{Binding Logs/}" />
    </ListBox.InputBindings>

    <ListBox.CommandBindings>
        <CommandBinding Command="Copy"
                        Executed="CopyLogExecuted"
                        CanExecute="CanExecuteCopyLog" />
    </ListBox.CommandBindings>

    <ListBox.ItemContainerStyle>
        <Style TargetType="{x:Type ListBoxItem}">
            <Setter Property="ContextMenu">
                <Setter.Value>
                    <ContextMenu>
                        <MenuItem Command="Copy"
                                  CommandParameter="{Binding}" />
                    </ContextMenu>
                </Setter.Value>
            </Setter>
        </Style>
    </ListBox.ItemContainerStyle>

    <ListBox.ItemTemplate>
        <DataTemplate>
            <TextBlock Text="{Binding}" />
        </DataTemplate>
    </ListBox.ItemTemplate>
</ListBox>

我们在KeyBinding本身定义ListBox,并指定为CommandParameter当前选中的列表框项(日志条目)。

CommandBinding也在ListBox级别定义,它是右键单击菜单和键盘快捷键的单一绑定。

我们在ContextMenu的样式中定义ListBoxItem,并将CommandParameter绑定到此ListBoxItem(日志条目)所代表的数据项。

DataTemplate只声明绑定到当前数据项的TextBlock

最后,代码隐藏中的Copy命令只有一个处理程序:

private void CopyLogExecuted(object sender, ExecutedRoutedEventArgs e) {
    var logItem = e.Parameter;

    // Copy log item to the clipboard
}

private void CanExecuteCopyLog(object sender, CanExecuteRoutedEventArgs e) {
    e.CanExecute = true;
}

答案 1 :(得分:0)

感谢Pavlov Glazkov解释密钥和命令绑定需要进入ListBox级别,而不是项目模板级别。

这是我现在的解决方案:

<ListBox ItemsSource="{Binding Logs, Mode=OneWay}">
    <ListBox.InputBindings>
        <KeyBinding Key="C"
                    Modifiers="Ctrl"
                    Command="Copy"/>
    </ListBox.InputBindings>
    <ListBox.CommandBindings>
        <CommandBinding Command="Copy"
                        Executed="KeyCopyLog_Executed"
                        CanExecute="CopyLog_CanExecute"/>
    </ListBox.CommandBindings>
    <ListBox.ItemTemplate>
        <DataTemplate>
            <TextBlock Text="{Binding Path=.}">
                <TextBlock.ContextMenu>
                    <ContextMenu>
                        <MenuItem Command="Copy">
                            <MenuItem.CommandBindings>
                                <CommandBinding Command="Copy"
                                                Executed="MenuCopyLog_Executed"
                                                CanExecute="CopyLog_CanExecute"/>
                            </MenuItem.CommandBindings>
                        </MenuItem>
                    </ContextMenu>
                </TextBlock.ContextMenu>
            </TextBlock>
        </DataTemplate>
    </ListBox.ItemTemplate>
</ListBox>

KeyCopyLog_Executed的位置:

private void KeyCopyLog_Executed(object sender, System.Windows.Input.ExecutedRoutedEventArgs e)
{
    if ((sender as ListBox).SelectedItem != null)
    {
        LogItem item = (LogItem) (sender as ListBox).SelectedItem;
        Clipboard.SetData("Text", item.ToString());
    }
}

MenuCopyLog_Executed是:

private void MenuCopyLog_Executed(object sender, System.Windows.Input.ExecutedRoutedEventArgs e)
{
    LogItem item = (LogItem) ((sender as MenuItem).TemplatedParent as ContentPresenter).DataContext;
    Clipboard.SetData("Text", item.ToString());
}