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

发布于 2024-10-18 07:32:34 字数 1852 浏览 1 评论 0原文

我已经设置了一个 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 中,还有一个用于 ctrl+cKeyBinding 和一个要复制的 CommandBinding。当我按 ctrl+c 时,不会执行 KeyCopyLog_Executed 方法。我已经用调试器检查过。

我应该如何将按键绑定到 TextBlock

I have set up a ListBox like so:

<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>

As you can see, in the template, each TextBlock has a context menu that allows the user to copy the text. This works.

Also in the TextBlock there is an KeyBinding to ctrl+c and a CommandBinding to copy. When I press ctrl+c the method KeyCopyLog_Executed is not executed. I've checked with the debugger.

How should I be binding the keys to the TextBlock?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

天气好吗我好吗 2024-10-25 07:32:34

这里有几个问题。

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

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

此外,如果您在 TextBlock 元素上定义 ContextMenu,则仅当您右键单击 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>

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

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

我们以 ListBoxItem 的样式定义 ContextMenu,并将 CommandParameter 绑定到此 ListBoxItem 表示的数据项(log入口)。

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;
}

There are a couple of problems here.

First of all, KeyBindings will work only if currently focused element is located inside the element where KeyBindings are defined. In your case you have a ListBoxItem focused, but the KeyBindings are defined on the child element - TextBlock. So, defining a KeyBindings on a TextBlock will not work in any case, since a TextBlock cannot receive focus.

Second of all, you probably need to know what to copy, so you need to pass the currently selected log item as parameter to the Copy command.

Furthermore, if you define a ContextMenu on a TextBlock element it will be opened only if your right-click exactly on the TextBlock. If you click on any other part of the list item, it will not open. So, you need to define the ContextMenu on the list box item itself.

Considering all of that, what I believe you are trying to do can be done in the following way:

<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>

Here we define a KeyBinding on the ListBox itself and specify as a CommandParameter currently selected list box item (log entry).

CommandBinding is also defined at the ListBox level and it is a single binding for both right click menu and the keyboard shortcut.

The ContextMenu we define in the style for ListBoxItem and bind CommandParameter to the data item represented by this ListBoxItem (log entry).

The DataTemplate just declares a TextBlock with binding to current data item.

And finally, there is only one handler for the Copy command in the code-behind:

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;
}
孤者何惧 2024-10-25 07:32:34

感谢 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());
}

Thanks to Pavlov Glazkov for explaining that the key and command bindings need to go at the ListBox level, rather than the item template level.

This is the solution I now have:

<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>

Where KeyCopyLog_Executed is:

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());
    }
}

and MenuCopyLog_Executed is:

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());
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文