Search code examples
c#wpfmvvmdatagrid

Datagrid save value in Database when cell change


Hi I create this test code:

<Button x:Name="b_Delete" Content="Delete" Margin="10" Grid.Row="1"/>
<Button x:Name="b_Save" Content="Save" Margin="10" Grid.Row="1"
    Grid.Column="1" Command="{Binding Path=SaveCommand}"/>
<DataGrid x:Name="dataGrid" Margin="10" Grid.ColumnSpan="2"
          ItemsSource="{Binding Path=Books, Mode=TwoWay,
          UpdateSourceTrigger=PropertyChanged}"
          AutoGenerateColumns="False" CanUserAddRows="False">
    <DataGrid.Columns>
        <DataGridTextColumn x:Name="Author" Header="Author"
                            Width="*" Binding="{Binding author, Mode=TwoWay,
                            UpdateSourceTrigger=PropertyChanged}">
            <DataGridTextColumn.ElementStyle>
                <Style TargetType="TextBlock">
                    <Setter Property="HorizontalAlignment" Value="Center"/>
                    <Setter Property="VerticalAlignment" Value="Center"/>
                </Style>
            </DataGridTextColumn.ElementStyle>
        </DataGridTextColumn>
        <DataGridTextColumn x:Name="Title" Header="Title"
                            Width="*" Binding="{Binding title}">
            <DataGridTextColumn.ElementStyle>
                <Style TargetType="TextBlock">
                    <Setter Property="HorizontalAlignment" Value="Left"/>
                    <Setter Property="VerticalAlignment" Value="Center"/>
                </Style>
            </DataGridTextColumn.ElementStyle>
        </DataGridTextColumn>
        <DataGridTextColumn x:Name="Price" Header="Price"
                            Width="*" Binding="{Binding price}">
            <DataGridTextColumn.ElementStyle>
                <Style TargetType="TextBlock">
                    <Setter Property="HorizontalAlignment" Value="Left"/>
                    <Setter Property="VerticalAlignment" Value="Center"/>
                </Style>
            </DataGridTextColumn.ElementStyle>
        </DataGridTextColumn>
        <DataGridTemplateColumn x:Name="Delete_Row" Header="Delete" Width="0.2*">
            <DataGridTemplateColumn.CellTemplate>
                <DataTemplate>
                    <Button Content="X"/>
                </DataTemplate>
            </DataGridTemplateColumn.CellTemplate>
        </DataGridTemplateColumn>
    </DataGrid.Columns>
</DataGrid>

I have create two button and a DataGrid. To DataGrid is fill with values read into database, now if the user change the text into the cell, the new value is saved into the database (the button X delete into the row is not implemented for now).

My idea is make one ObservableCollection where I add the information of row changed (another ObservableCollectfor row deleted) and When the button Save is clicked, I save the value into Database taking the value intoObservableCollect`. What do you think?

How can I intercept the change of value in the cell of the DataGrid?

private ObservableCollection<Book> books = null;
public ObservableCollection<Book> Books
{
    get { return books; }
    set
    {
        books = value;
        NotifyPropertyChanged();
    }
}

This point is not call if I change the cell value?

Thank for the help.


Solution

  • There are a couple ways to handle this, but I wouldn't necessarily recommend "intercepting" the changes to track them (especially if you're using a "Save" button). Instead, when you load the Books list from the database, I would make two copies: Books and BooksOriginal (or some similar name). Books would be an ObservableCollection<T>, but BooksOriginal can just be a normal List<T> since it won't be used in binding.

    Bind the DataGrid to Books and let the user add, delete or update any records they want. Then, when they click "Save", you compare Books to BooksOriginal to decide what to do with each item:

    • If the item from Books isn't in BooksOriginal, it's new and needs to be inserted into the database.
    • If the item from Books is in BooksOriginal, compare the two versions to see if they're different. If so, changes were made and you need to update the record in the database.
    • Finally, check for items in BooksOriginal that aren't in Books, those will be records that have been deleted from the DataGrid.

    This way databinding can just do its job, you only have to worry about two variables (Books and BooksOriginal), and all the logic/code gets kept in one method: Save.

    A couple notes:
    This assumes each record has a unique identifier.

    Make sure, if you use the two collections idea as above, that you make two separate objects for each "book". Don't make one book object and add it to both collections or you won't be able to compare for changes.

    You also have the option of only making one list (Books) when the program loads, and then loading the second list (BooksOriginal) when they click save. This has the advantage of making sure the you have the most current data from the database when checking for changes.