11

I am trying to retrieve row info from a datagrid after a double click event. I have the event setup, but now I just need to setup the function to retrieve the data from the row.

XAML:

    <DataGrid 
        Width="Auto" 
        SelectionMode="Extended" 
        IsReadOnly="True" 
        Name="ListDataGrid"
        AutoGenerateColumns="False"
        ItemsSource="{Binding ListFieldObject.MoviesList}"
        DataContext="{StaticResource MovieAppViewModel}"
        cal:Message.Attach="[Event MouseDoubleClick] = [Action RowSelect()]">

        <DataGrid.Columns>
            <DataGridTextColumn Width="200" IsReadOnly="True" Header="Title" Binding="{Binding Title}"/>
            <DataGridTextColumn Width="100" IsReadOnly="True" Header="Rating" Binding="{Binding Rating}"/>
            <DataGridTextColumn Width="100" IsReadOnly="True" Header="Stars" Binding="{Binding Stars}"/>
            <DataGridTextColumn Width="93" IsReadOnly="True" Header="Release Year" Binding="{Binding ReleaseYear}"/>
        </DataGrid.Columns>
    </DataGrid>

C# (MVVM ViewModel):

     public void RowSelect()
     {
         //now how to access the selected row after the double click event?
     }

Thanks Much!

Josh
  • 657
  • 3
  • 15
  • 30
  • From what I can tell it's very difficult if not impossible. Plenty of web sites discuss this, e.g. http://www.scottlogic.co.uk/blog/colin/2008/12/wpf-datagrid-detecting-clicked-cell-and-row/ and this http://stackoverflow.com/questions/5808616/how-to-bind-a-command-to-double-click-on-a-row-in-datagrid – Phil Feb 28 '12 at 20:29

5 Answers5

27

You can alternatively do this:

<DataGrid>
    <DataGrid.RowStyle>
        <Style TargetType="DataGridRow">
            <Setter Property="cal:Message.Attach" Value="[MouseDoubleClick] = [Action RowSelect($dataContext)]"/>
        </Style>
    </DataGrid.RowStyle>
</DataGrid>

Then

public void RowSelect(MoviesListItem movie)
{
     //now how to access the selected row after the double click event?
}
David Kiff
  • 1,200
  • 2
  • 11
  • 24
  • 3
    This is much better solution then accepted answer since it catch only double clicks on rows but not on headers. – Sevenate Jan 22 '14 at 09:56
  • 1
    This is the answer I've been looking for, and should be marked as the answer. – Teslo. Nov 12 '15 at 09:51
  • This is the correct answer! I'll also add that if you want to call a method on the DataGrid's DataContext, you can also add the following Setter: `` – Shahin Dohan Nov 06 '18 at 13:57
9

You can just pass $dataContext on your XAML:

 cal:Message.Attach="[Event MouseDoubleClick] = [Action RowSelect($dataContext)]">

And change your method to:

public void RowSelect(MoviesListItem movie)
{
     //now how to access the selected row after the double click event?
}

//EDIT Sorry, the above solution will work only if the action is on the datatemplate itself... another solution would be to have a SelectedItem bind and just use it on your method:

<DataGrid 
    SelectedItem="{Binding SelectedMovie,Mode=TwoWay}"
    cal:Message.Attach="[Event MouseDoubleClick] = [Action RowSelect()]">

and on your code:

public void RowSelect()
{
   //SelectedMovie is the item where the user double-cliked
}
Leo
  • 7,379
  • 6
  • 28
  • 44
  • This is how I ended up doing it. Thanks for the help! – Josh Feb 29 '12 at 19:05
  • This solution is viable, but from experience, it has the downside of having unpredictable behavior if the user is rapidly clicking areas of your data grid. The most notable example: the user likes to rapidly click the down-arrow or thumb track in the vertical scrollbar if they are scrolling through a large list. Many users don't click-and-drag the thumb to scroll; instead, they hammer away at the arrow or thumb track. This solution will invariably cause the double-click to execute since it's handled by the data grid and not the data row. – Adrian Mar 01 '12 at 16:47
  • @Josh, this solution will also handle double clicks on column headers, that hardly necessary. To prevent this, please consider solution from *David Kiff* bellow. – Sevenate Jan 22 '14 at 10:02
1

(hope it will help) I am not sure about your case, but this is what I do in winforms:

            int index = dataGridView2.CurrentRow.Index; //determine which item is selected
            textBox8.Text = dataGridView2.Rows[index].Cells[0].Value.ToString(); //add login
Andrew
  • 7,619
  • 13
  • 63
  • 117
  • you input is appreciated but I am using the MVVM pattern and cant have the calls in the code behind. I will edit the original post to reflect the fact that the C# is in the ViewModel. – Josh Feb 28 '12 at 18:06
1

You can do this by modifying the control template for the DataGridRows exposed by the DataGrid. The example below uses WPF and the Aero theme.

The only thing I've done is removed your previous cal:Message.Attach call and move it to a new "placeholder" ContentControl that surrounds the Border (x:Name=DGR_Border) in the "default" control template. (I used ContentControl because it has no visuals of its own and it exposes a MouseDoubleClick event.)

<DataGrid Width="Auto" 
          SelectionMode="Extended" 
          IsReadOnly="True" 
          Name="ListDataGrid"
          AutoGenerateColumns="False"
          ItemsSource="{Binding ListFieldObject.MoviesList}"
          DataContext="{StaticResource MovieAppViewModel}">

    <DataGrid.Columns>
        <DataGridTextColumn Width="200" IsReadOnly="True" Header="Title" Binding="{Binding Title}"/>
        <DataGridTextColumn Width="100" IsReadOnly="True" Header="Rating" Binding="{Binding Rating}"/>
        <DataGridTextColumn Width="100" IsReadOnly="True" Header="Stars" Binding="{Binding Stars}"/>
        <DataGridTextColumn Width="93" IsReadOnly="True" Header="Release Year" Binding="{Binding ReleaseYear}"/>
    </DataGrid.Columns>
    <DataGrid.RowStyle>
        <Setter Property="Background" Value="{DynamicResource {x:Static SystemColors.WindowBrushKey}}"/>
        <Setter Property="SnapsToDevicePixels" Value="true"/>
        <Setter Property="Validation.ErrorTemplate" Value="{x:Null}"/>
        <Setter Property="ValidationErrorTemplate">
            <Setter.Value>
                <ControlTemplate>
                    <TextBlock Foreground="Red" Margin="2,0,0,0" Text="!" VerticalAlignment="Center"/>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
        <Setter Property="Template">
            <Setter.Value>                                      
                <ControlTemplate TargetType="{x:Type DataGridRow}">
                    <ContentControl cal:Message.Attach="[Event MouseDoubleClick] = [Action RowSelect($datacontext)]">
                        <Border x:Name="DGR_Border" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" SnapsToDevicePixels="True">
                            <SelectiveScrollingGrid>
                                <SelectiveScrollingGrid.ColumnDefinitions>
                                    <ColumnDefinition Width="Auto"/>
                                    <ColumnDefinition Width="*"/>
                                </SelectiveScrollingGrid.ColumnDefinitions>
                                <SelectiveScrollingGrid.RowDefinitions>
                                    <RowDefinition Height="*"/>
                                    <RowDefinition Height="Auto"/>
                                </SelectiveScrollingGrid.RowDefinitions>
                                <DataGridCellsPresenter Grid.Column="1" ItemsPanel="{TemplateBinding ItemsPanel}" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/>
                                <DataGridDetailsPresenter Grid.Column="1" Grid.Row="1" SelectiveScrollingGrid.SelectiveScrollingOrientation="{Binding AreRowDetailsFrozen, ConverterParameter={x:Static SelectiveScrollingOrientation.Vertical}, Converter={x:Static DataGrid.RowDetailsScrollingConverter}, RelativeSource={RelativeSource AncestorType={x:Type DataGrid}}}" Visibility="{TemplateBinding DetailsVisibility}"/>
                                <DataGridRowHeader Grid.RowSpan="2" SelectiveScrollingGrid.SelectiveScrollingOrientation="Vertical" Visibility="{Binding HeadersVisibility, ConverterParameter={x:Static DataGridHeadersVisibility.Row}, Converter={x:Static DataGrid.HeadersVisibilityConverter}, RelativeSource={RelativeSource AncestorType={x:Type DataGrid}}}"/>
                            </SelectiveScrollingGrid>
                        </Border>
                    </ContentControl>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </DataGrid.RowStyle>
</DataGrid>

The only other thing you'll have to do is modify your RowSelect() method to accept a parameter of whatever type you're using here (I just assumed it was a 'Movie' type).

public void RowSelect(Movie movie)
{
   // do something with 'movie'
}
Adrian
  • 1,338
  • 8
  • 17
0

My example there is a column with NAME "service_id". But you can use int32 column offset as well. There is even an ItemArray in the DataRowView TYPE to run and and down. See System.Data namespace. Your Datagrid itemssource / context will impact the "objects" you see inside the Datagrid. But if you check in debug the types, then you can Cast them and use them.

private void DataGridServiceRegistry_MouseDoubleClick(object sender, MouseButtonEventArgs e)
{
    DataGrid DGSR = (DataGrid) sender;
    var SR = (DataRowView) DGSR.CurrentItem;
    var service_id = SR.Row["SERVICE_ID"];
}
H.Muster
  • 9,297
  • 1
  • 35
  • 46
phil soady
  • 11,043
  • 5
  • 50
  • 95