3

So I have a WPF data grid with about 8 cells in each row, I've only included the relevant one for simplicity but I'd like the user to be able to right click this cell and copy the contents into the windows clipboard without left clicking and selecting it first. I've tried many code snippets but can't seem to get anything to work. Each row is a binded item.

The majority of things I've been trying is with the MouseRightButtonDown event. Some have tried the to the XY position, some have used e.OriginalSource as FrameworkElement but I can't seem to get anything to work. Not sure if its because its a DataGridHyperlinkColumn as opposed to the other types used in the examples?

I'm a c# n00b! Any help would be greatly appreciated.

    <DataGrid x:Name="eventsDataGrid" AutoGenerateColumns="False" IsReadOnly="true" ItemsSource="{Binding}" HorizontalAlignment="Left" Margin="10,143,0,0" VerticalAlignment="Top" Height="295"  CanUserAddRows="False" CanUserReorderColumns="False" CanUserResizeColumns="True" CanUserSortColumns="False" BorderThickness="1" HorizontalScrollBarVisibility="Disabled"  FontSize="10" Width="1003" MouseRightButtonDown="eventsDataGrid_MouseRightButtonDown">

        <DataGrid.ContextMenu>
            <ContextMenu>
                <MenuItem Header="Copy URL" Click="CopyURL">
                </MenuItem>
            </ContextMenu>
        </DataGrid.ContextMenu>

        <DataGrid.Columns>

            <DataGridHyperlinkColumn Width="230" Header="URL" Binding="{Binding URL}"  CanUserResize="False">
                <DataGridHyperlinkColumn.HeaderStyle>
                    <Style TargetType="{x:Type DataGridColumnHeader}">
                        <Setter Property="ToolTip" Value="URL of website" />
                        <Setter Property="HorizontalContentAlignment" Value="Center"/>
                        <Setter Property="VerticalAlignment" Value="Center"/>
                    </Style>
                </DataGridHyperlinkColumn.HeaderStyle>

                <DataGridHyperlinkColumn.CellStyle>
                    <Style TargetType="{x:Type DataGridCell}">
                        <Setter Property="Foreground" Value="Black" />
                        <Setter Property="HorizontalAlignment" Value="Center"/>
                        <Setter Property="FontSize" Value="12"/>
                    </Style>
                </DataGridHyperlinkColumn.CellStyle>
            </DataGridHyperlinkColumn>

        </DataGrid.Columns>
    </DataGrid>
Mr J
  • 2,655
  • 4
  • 37
  • 58
  • 1
    You could assign your context menu to the cells instead of the `DataGrid` and use `Command` with `CommandParameter` instead of the `Click` event. By passing the cell content as command parameter, everything should be available to fill the clipboard in the code behind. – grek40 Jul 12 '16 at 13:07
  • Thanks man, that sounds like exactly what I need however I can't figure out how to assign my context menu to the cells, which part of the XAML would the now go in? I tried it inside DataGridHyperlinkColumn and DataGridHyperlinkColumn.CellStyle, didn't seem it like it and I can't find any web examples. Any idea? – Mr J Jul 12 '16 at 13:51
  • 1
    http://stackoverflow.com/questions/5200687/create-contextmenus-for-datagrid-rows Just a few modifications is needed to pass the item as a command parameter – michauzo Jul 12 '16 at 14:06

1 Answers1

3

The following example shows how to use a single context menu as resource for multiple target elements. Note that it might be a good idea to create a custom command instead of 'borrowing' ApplicationCommands.Copy for the purpose of demonstration, as I did here.

<Window x:Class="WpfApplication2.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525"
        Loaded="Window_Loaded">
    <Window.CommandBindings>
        <CommandBinding Command="ApplicationCommands.Copy"
                        Executed="CopyCommand_Executed"
                        CanExecute="CopyCommand_CanExecute"/>
    </Window.CommandBindings>
    <Window.Resources>
        <ContextMenu x:Key="ctMenu" DataContext="{Binding PlacementTarget,RelativeSource={RelativeSource Self}}">
            <MenuItem Header="Copy URL"
                      Command="ApplicationCommands.Copy"
                      CommandTarget="{Binding}"
                      CommandParameter="{Binding Text}"/>
        </ContextMenu>
    </Window.Resources>
    <StackPanel>
        <TextBlock Text="123" ContextMenu="{StaticResource ctMenu}"/>
        <TextBlock Text="456" ContextMenu="{StaticResource ctMenu}"/>
    </StackPanel>
</Window>

The command binding also needs some code behind (will be different with a custom command implementation)

private void CopyCommand_Executed(object sender, ExecutedRoutedEventArgs e)
{
    Clipboard.SetText(e.Parameter as string);
}

private void CopyCommand_CanExecute(object sender, CanExecuteRoutedEventArgs e)
{
    if (!string.IsNullOrEmpty(e.Parameter as string))
    {
        e.CanExecute = true;
        e.Handled = true;
    }
}
grek40
  • 13,113
  • 1
  • 24
  • 50
  • Thank you for your response but this code seems to behave in the same way as my original code. When I right click a row the copy menu appears but is grayed out and when I left click a row (so its selected) then right click it the copy menu appears and the content can be copied to the clipboard. Was the expected? Apologies if I didn't explain my desired outcome accurately :-) – Mr J Jul 12 '16 at 14:31
  • I'm adding ContextMenu="{StaticResource ctMenu}" to my . Is that correct? – Mr J Jul 12 '16 at 14:33
  • No, you should add it to the cells / cell contents via style or template. See comment from @michauzo for more details. – grek40 Jul 12 '16 at 14:34
  • But **Ctrl+C** not working. – Sandeep Jadhav May 25 '23 at 06:43
  • @SandeepJadhav since this whole thing is 7 years old, I suggest you create your own question with all relevant details, if you have a related problem that can't be solved with existing question/answer entries. – grek40 May 25 '23 at 06:51