Roxy'Pro
Roxy'Pro

Reputation: 4444

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;
}

Upvotes: 0

Views: 2197

Answers (3)

Rekshino
Rekshino

Reputation: 7325

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;
}

Upvotes: 2

dstreissi
dstreissi

Reputation: 269

hi you can set a flag on the binding at the checkboxcolumn. There is a NotifyOnTargetUpdated with fires an TargetUpdated event when the target (your checkbox) changes.

With NotifyOnTargetUpdated=True on your binding you activate them. Your DataGridCheckBoxColumn looks then like this:

<DataGridCheckBoxColumn x:Name="colSelektiraj" Binding="{Binding IsChecked, NotifyOnTargetUpdated=True}" Header="" Width="10*" />

On the Datagrid use the TargetUpdated="DataGrid_TargetUpdated"event to get notified. Your datagrid looks then like this:

<DataGrid Name="dtgTest" IsReadOnly="True" TargetUpdated="DataGrid_TargetUpdated" ...>

To get notified when the selection changed use the SelectionChanged event as you did it already.

Upvotes: 0

Prateek Shrivastava
Prateek Shrivastava

Reputation: 1937

If you have a ViewModel (MVVM) which represents the Data for each row. You should/could have a bool property there which represents the CheckBox state (rather than doing so from code behind).

Next, you can Bind DataGrid's SelectedItem to an Object (of relevant type) and test whether that gets fired even when you click same item multiple times. If it does (at least in DevExpress gridControls) - You should Flip the bool property in the Setter for the SelectedItem.

Upvotes: 0

Related Questions