Search code examples
c#wpfxamldatagridselectionchanged

How can I detect in a DataGrid if row is clicked and change its column from true to false and vice versa?


I'm working on a small WPF application, when I click on a row I'm making my checkbox column selected/unselected. This is how my rows look:

enter image description here

And here is my code:

private void dtgTest_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
    if (dtgTest.SelectedItem != null)
    {
        CheckBox checkbocColumn = (dtgTest.Columns[3].GetCellContent(dtgTest.SelectedItem) as CheckBox);
        checkbocColumn.IsChecked = !checkbocColumn.IsChecked;


        var selectedItem = (BillItemInSerie)dtgTest.SelectedItem;
        var obj = serialNumbersIn.FirstOrDefault(sn => selectedItem.DocumentItemInSeriesId == sn.DocumentItemInSeriesId);
        obj.IsChecked= (bool)checkbocColumn.IsChecked;

    }
}

Here is how I'm filling DataGrid:

public Test_Window()
   : this()
{
    databaseValues = Controller.Instance.GetById(Id);
    dtgTest.ItemsSource = null;
    dtgTest.ItemsSource = databaseValues;
}

So when form is generated I acctually get all items from DB

And here is my XAML:

<DataGrid Name="dtgTest"  IsReadOnly="True"  VirtualizingStackPanel.VirtualizationMode="Standard"  EnableColumnVirtualization = "True" EnableRowVirtualization ="True"  MaxWidth="4000" MaxHeight="2000" Background="White" Margin="5,5,5,0" AutoGenerateColumns="False" RowHeaderWidth="0"  HorizontalGridLinesBrush="#0091EA" VerticalGridLinesBrush="#0091EA" CanUserAddRows="False" RowHeight="30" Grid.ColumnSpan="2" Grid.Row="2" SelectionChanged="dtgTest_SelectionChanged">
    <DataGrid.CellStyle>
        <StaticResource ResourceKey="DataGridCentering"/>
    </DataGrid.CellStyle>
    <DataGrid.Resources>
        <Style TargetType="{x:Type DataGridColumnHeader}">
            <Setter Property="Background" Value="#0091EA"/>
            <Setter Property="Opacity" Value="1"/>
            <Setter Property="Foreground" Value="White"/>
            <Setter Property="HorizontalContentAlignment" Value="Center" />
            <Setter Property="FontSize" Value="{x:Static local:Globals.dataGridfontSizeHeader}"/>
            <Setter Property="FontFamily" Value="Arial"/>
            <Setter Property="Height" Value="40"/>
        </Style>
        <SolidColorBrush x:Key="{x:Static SystemColors.HighlightBrushKey}" 
           Color="LightBlue"/>
    </DataGrid.Resources>
    <DataGrid.Columns>
        <DataGridTextColumn         Binding="{Binding Value1}"          Header=""   Foreground="Black" FontSize="15" FontFamily="Verdana" Width="35*"  />
        <DataGridTextColumn         Binding="{Binding Value2}"          Header=""   Foreground="Black" FontSize="15" FontFamily="Verdana" Width="35*"   />
        <DataGridTextColumn         x:Name="colFormatedDate"            Binding="{Binding ExpireDate, StringFormat ={}{0:MM/yyyy}}"     Header=""   Foreground="Black"      FontSize="15" FontFamily="Verdana" Width="20*" />
        <DataGridCheckBoxColumn     x:Name="colSelektiraj"              Binding="{Binding IsChecked}"       Header=""  Width="10*" />
    </DataGrid.Columns>
</DataGrid>

But issue is here when I click on a row and make checkbox column selected (LIKE IN EXAMPLE IMAGE ABOVE) , and If I immediately change my mind and click again on selected row to change the state of checkbox column I won't be able to do it, because dtgTest_SelectionChanged won't trigger because I did not change selection..

So I guess detecting if a row is clicked might help me here? So I might execute similar code as it is in dtgTest_SelectionChanged event?

Any kind of help would be awesome! Thanks, guys

Cheers

EDIT AFTER Rekshino help:

<DataGrid Name="dtgTest" IsReadOnly="True"  VirtualizingStackPanel.VirtualizationMode="Standard"  EnableColumnVirtualization = "True" EnableRowVirtualization ="True"  MaxWidth="4000" MaxHeight="2000" Background="White" Margin="5,5,5,0" AutoGenerateColumns="False" RowHeaderWidth="0"  HorizontalGridLinesBrush="#0091EA" VerticalGridLinesBrush="#0091EA" CanUserAddRows="False" RowHeight="30" Grid.ColumnSpan="2" Grid.Row="2" SelectionChanged="dtgTest_SelectionChanged" PreviewMouseDown="dtgTest_PreviewMouseDown">
    <DataGrid.CellStyle>
        <StaticResource ResourceKey="DataGridCentering"/>
    </DataGrid.CellStyle>
    <DataGrid.Resources>
        <Style TargetType="{x:Type DataGridColumnHeader}">
            <Setter Property="Background" Value="#0091EA"/>
            <Setter Property="Opacity" Value="1"/>
            <Setter Property="Foreground" Value="White"/>
            <Setter Property="HorizontalContentAlignment" Value="Center" />
            <Setter Property="FontSize" Value="{x:Static local:Globals.dataGridfontSizeHeader}"/>
            <Setter Property="FontFamily" Value="Arial"/>
            <Setter Property="Height" Value="40"/>
        </Style>
        <SolidColorBrush x:Key="{x:Static SystemColors.HighlightBrushKey}" Color="LightBlue"/>
        <Style TargetType="DataGridCell">
            <EventSetter Event="PreviewMouseLeftButtonDown" Handler="dtgTest_PreviewMouseDown"/>
        </Style>
    </DataGrid.Resources>
    <DataGrid.Columns>
        <DataGridTextColumn         Binding="{Binding Value1}"          Foreground="Black" FontSize="15" FontFamily="Verdana" Width="35*"  />
        <DataGridTextColumn         Binding="{Binding Value2}"          Foreground="Black" FontSize="15" FontFamily="Verdana" Width="35*"   />
        <DataGridTextColumn         x:Name="colFormatedDate"            Binding="{Binding ExpireDate, StringFormat ={}{0:MM/yyyy}}"   Foreground="Black"      FontSize="15" FontFamily="Verdana" Width="20*" />
        <DataGridCheckBoxColumn     x:Name="colSelektiraj"              Binding="{Binding IsChecked, NotifyOnTargetUpdated=True}"     Header=""  Width="10*" />
    </DataGrid.Columns>
</DataGrid>

C# :

private void dtgTest_PreviewMouseDown(object sender, MouseButtonEventArgs e)
{

    var cell = sender as DataGridCell;

    if (cell == null)
    {
        return;
    }

    DataGridRow parGridRow = null;
    var visParent = VisualTreeHelper.GetParent(cell);
    while (parGridRow == null && visParent != null)
    {
        parGridRow = visParent as DataGridRow;
        visParent = VisualTreeHelper.GetParent(visParent);
    }
    if (parGridRow == null) { return; }

    var selectedItem = (parGridRow.DataContext as BillItemInSerie);
    var obj = serialNumbersIn.FirstOrDefault(sn => selectedItem.DocumentItemInSeriesId == sn.DocumentItemInSeriesId);
    obj.IsChecked = (bool)!obj.IsChecked;
}

Solution

  • You can set mouse event handler for the cell, get the row and make what you want with it. I have removed event handler for SelectionChanged, because you don't need it in this solution.

    <DataGrid Name="dtgTest"  IsReadOnly="True"  VirtualizingStackPanel.VirtualizationMode="Standard"  EnableColumnVirtualization = "True" EnableRowVirtualization ="True"  MaxWidth="4000" MaxHeight="2000" Background="White" Margin="5,5,5,0" AutoGenerateColumns="False" RowHeaderWidth="0"  HorizontalGridLinesBrush="#0091EA" VerticalGridLinesBrush="#0091EA" CanUserAddRows="False" RowHeight="30" Grid.ColumnSpan="2" Grid.Row="2">
        <DataGrid.Resources>
            <Style TargetType="DataGridCell">
            <!-- If you have to apply another style, then use BasedOn-->
            <!--<Style TargetType="DataGridCell" BasedOn="{StaticResource DataGridCentering}">-->
                <EventSetter Event="PreviewMouseLeftButtonDown" Handler="PreviewMouseDown"/>
            </Style>
        </DataGrid.Resources>
        ...
    </DataGrid>
    
    private void PreviewMouseDown(object sender, MouseButtonEventArgs e)
    {
        var cell = sender as DataGridCell; if (cell == null) { return; }
        DataGridRow parGridRow = null;
        var visParent = VisualTreeHelper.GetParent(cell);
        while (parGridRow == null && visParent != null)
        {
            parGridRow = visParent as DataGridRow;
            visParent = VisualTreeHelper.GetParent(visParent);
        }
        if (parGridRow == null) { return; }
        var selectedItem = (parGridRow.DataContext as BillItemInSerie);
        var obj = serialNumbersIn.FirstOrDefault(sn => selectedItem.DocumentItemInSeriesId == sn.DocumentItemInSeriesId);
        obj.IsChecked= (bool)!obj.IsChecked;
    
        //e.Handled = true;
    }