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
?
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;
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With