Getting row information after a doubleclick
Asked Answered
I

5

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!

Inoculum answered 28/2, 2012 at 17:48 Comment(1)
From what I can tell it's very difficult if not impossible. Plenty of web sites discuss this, e.g. scottlogic.co.uk/blog/colin/2008/12/… and this #5809116Ensiform
E
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
}
Emory answered 29/2, 2012 at 3:59 Comment(3)
This is how I ended up doing it. Thanks for the help!Inoculum
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.J
@Josh, this solution will also handle double clicks on column headers, that hardly necessary. To prevent this, please consider solution from David Kiff bellow.Andesite
M
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?
}
Mcardle answered 25/6, 2013 at 13:22 Comment(3)
This is much better solution then accepted answer since it catch only double clicks on rows but not on headers.Andesite
This is the answer I've been looking for, and should be marked as the answer.Donley
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: <Setter Property="cal:Action.TargetWithoutContext" Value="{Binding DataContext, RelativeSource={RelativeSource AncestorType=DataGrid}}" />Discontinuity
E
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
}
Emory answered 29/2, 2012 at 3:59 Comment(3)
This is how I ended up doing it. Thanks for the help!Inoculum
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.J
@Josh, this solution will also handle double clicks on column headers, that hardly necessary. To prevent this, please consider solution from David Kiff bellow.Andesite
I
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
Illness answered 28/2, 2012 at 17:59 Comment(1)
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.Inoculum
J
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'
}
J answered 29/2, 2012 at 18:35 Comment(0)
K
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"];
}
Kragh answered 14/8, 2012 at 8:35 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.