Reputation: 176
I have a ListBox of TextBlock(s) that I would like the end user to be able to copy the text from the display and then they can paste it to where they like. I am able to get a single line copy with the right click-> copy, and with a user's ctrl+c key press. I am also able to get a multiple line copy with a user's ctrl+c key press. I would like to be able to do a multiple line copy with the right click->copy feature as well as from a Menu drop down call.
My ListBox:
<!--Progress Window-->
<ListBox x:Name="Progress_Window" ItemsSource="{Binding _displayString}" ScrollViewer.ScrollChanged="Progress_Window_ScrollChanged" KeyDown="Progress_Window_KeyDown" SelectionMode="Extended">
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding _string}" Foreground="{Binding _color}" FontSize="{Binding _fontSize}">
<TextBlock.ContextMenu>
<ContextMenu>
<MenuItem Command="Copy">
<MenuItem.CommandBindings>
<CommandBinding Command="ApplicationCommands.Copy" CanExecute="RightClickCopyCmdCanExecute" Executed="RightClickCopyCmdExecuted" />
</MenuItem.CommandBindings>
</MenuItem>
</ContextMenu>
</TextBlock.ContextMenu>
</TextBlock>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
The code behind:
[DllImport("user32.dll", SetLastError = true)]
static extern void keybd_event(byte bVk, byte bScan, int dwFlags, int dwExtraInfo);
[DllImport("kernel32.dll")]
static extern bool GenerateConsoleCtrlEvent(uint dwCtrlEvent, uint dwProcessGroupId);
public const int KEYEVENTF_EXTENDEDKEY = 0x0001; //Key down flag
public const int KEYEVENTF_KEYUP = 0x0002; //Key up flag
public const int VK_LCONTROL = 0xA3; //0xA2; //Left Control key code
public const int C = 0x43; //A Control key code
private void Progress_Window_KeyDown(object sender, KeyEventArgs e)
{
if (e.Key == Key.C && (Keyboard.Modifiers & ModifierKeys.Control) == ModifierKeys.Control)
{
try
{
ListBox lb = (ListBox)(sender);
string collectedText = "";
foreach (DisplayData dd in lb.SelectedItems)
{
collectedText += dd._string + "\r\n";
}
if (lb.SelectedItems != null)
{
Clipboard.SetText(collectedText);
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
}
private void RightClickCopyCmdExecuted(object sender, ExecutedRoutedEventArgs e)
{
MenuItem mi = (MenuItem)sender;
DisplayData selected = (DisplayData)mi.DataContext;
if (selected != null)
{
Clipboard.SetText(selected._string);
}
}
private void RightClickCopyCmdCanExecute(object sender, CanExecuteRoutedEventArgs e)
{
e.CanExecute = true;
}
public void CallKeyDown()
{
//Progress_Window.Focus();
//// Hold Control down and press C
//keybd_event(VK_LCONTROL, 0, 0, 0);
//keybd_event(C, 0, 0, 0);
//keybd_event(C, 0, KEYEVENTF_KEYUP, 0);
//keybd_event(VK_LCONTROL, 0, KEYEVENTF_KEYUP, 0);
System.Windows.Forms.SendKeys.SendWait("^{c}");
var key = Key.C; // Key to send
var target = Progress_Window; // Target element
var routedEvent = Keyboard.KeyDownEvent; // Event to send
target.RaiseEvent(new KeyEventArgs(Keyboard.PrimaryDevice, PresentationSource.FromVisual(target), 0, key) { RoutedEvent = routedEvent });
}
}
From the Menu drop down:
<Grid>
<Menu>
<!--File-->
<MenuItem Header="_File">
<MenuItem Header="_Close" Command="{Binding Close}" />
</MenuItem>
<!--Edit-->
<MenuItem Header="_Edit">
<MenuItem Header="_Copy Ctrl+C" Command="{Binding CtrlC}" />
</MenuItem>
CtrlC command calls an Action that triggers CallKeyDown().
I have tried to move my ContextMenu from the TextBlock to the ListBox, but that gave me the DataContext of my ViewModel instead of giving me the _displayString data.
As you can see in CallKeyDown() I am trying to simulate a ctrl+c key press from code behind with no success. I don't know if that is the best approach to this problem. I also tried to use SendKeys.Send("^{c}") but that only works with Window Forms.
Upvotes: 2
Views: 5109
Reputation: 176
I just need to copy my code in RightClickCopyCmdExecuted
into CallKeyDown()
, and all is well. Then I will call CallKeyDown
from RightClickCopyCmdExecuted
.
I got the multiple lines for the right click->copy on the list box. So my ListBox becomes:
<!--Progress Window-->
<ListBox x:Name="Progress_Window" ItemsSource="{Binding _displayString}" ScrollViewer.ScrollChanged="Progress_Window_ScrollChanged" KeyDown="Progress_Window_KeyDown" SelectionMode="Extended">
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding _string}" Foreground="{Binding _color}" FontSize="{Binding _fontSize}" />
</DataTemplate>
</ListBox.ItemTemplate>
<ListBox.ContextMenu>
<ContextMenu>
<MenuItem Command="Copy">
<MenuItem.CommandBindings>
<CommandBinding Command="ApplicationCommands.Copy" CanExecute="RightClickCopyCmdCanExecute" Executed="RightClickCopyCmdExecuted" />
</MenuItem.CommandBindings>
</MenuItem>
</ContextMenu>
</ListBox.ContextMenu>
</ListBox>
and the code behind becomes:
private void RightClickCopyCmdExecuted(object sender, ExecutedRoutedEventArgs e)
{
string collectedText = "";
foreach (DisplayData dd in Progress_Window.SelectedItems)
{
collectedText += dd._string + "\r\n";
}
if (Progress_Window.SelectedItems != null)
{
Clipboard.SetText(collectedText);
}
}
Upvotes: 3