2

I'm developing an Avalonia Application and I'm trying to figure out how can I make a DataGrid cell editable, here's my DataGrid to make it more clear:

<DataGrid IsReadOnly="False" CanUserResizeColumns="False" ItemsSource="{Binding Employees}" Margin="10" CornerRadius="10">
    <DataGrid.Columns>
                <DataGridTextColumn Header="DIPENDENTE" Binding="{Binding dipendente}"/>
                
                <DataGridTemplateColumn Header="ATTIVO">
                    <DataTemplate>
                        <CheckBox IsChecked="{Binding attivo}"
                                  Command="{Binding $parent[DataGrid].((vm:AggiungiDipendenteViewModel)DataContext).ChangeStatusCommand}"
                                  CommandParameter="{Binding .}"/>
                    </DataTemplate>
                </DataGridTemplateColumn>

        <DataGridTextColumn Header="MAIL" Binding="{Binding mail}"/>
        <DataGridTextColumn Header="ASSUNZIONE" Binding="{Binding assunzione, StringFormat='{}{0:dd-MM-yyyy}'}"/>
        <DataGridTextColumn Header="RUOLO" Binding="{Binding tipo}"/>
        <DataGridTextColumn Header="SESSO" Binding="{Binding sex}"/>
    </DataGrid.Columns>
</DataGrid>

As I did for the ComboBox, that I made it clickable and behind it executes a query on db that changes the status from false to true and viceversa, Now I have to do the same thing for all the cells, I mean, every value of this DataGrid can be editable but after the edit(when the user press Enter), I have to put it on DB through a query, so in my ViewModel the public property takes the new value and it will show it up in the UI, then it will go as a parameter on a DB query but I don't know how to intercept the enter key when the user finishes to edit the cell. For example the user wants to edit the employee cell that contains name and surname because when he first added the employee he made a typo, so he will click on the cell and change the name, as he press enter (or he exits from editing the cell) I want it to go on a function that takes the new value of the cell and passes that value on an UPDATE query.

P.S. Of course the ItemSource of the DataGrid it's in the ViewModel and it is an ObservableCollection that inherits from a class.

I apologize if I repeated too many things, but I hope I explained everything clearly so that you can understand the real issue I'm facing.

5
  • What should happen if the user alters the data but did not press enter and moves to the next row? Commented Sep 24 at 18:32
  • @SirRufo it should modify the data anyway, but I'm not really sure about that, maybe it would be better to cancel the operation as the user exit the cell without pressing enter Commented Sep 25 at 6:55
  • You should clarify that use case. I personally write any changes to the db (as long as it is valid) after a timeperiod without changes. That is an very easy task with ReactiveUI Commented Sep 25 at 7:35
  • ok it should be better to make it modify it anyway, but I'm using the Community Toolkit instead of ReactiveUI, I find it better to use and quicker in terms of declarations exc... Commented Sep 25 at 8:43
  • With the new source generators reactiveui is as easy as the toolkit but has much more magic reactive powers like reactiveui.net/docs/getting-started/compelling-example.html Commented Sep 25 at 14:16

1 Answer 1

1

You can use UpdateSourceTrigger=LostFocus for your binding. Then the PropertyChanged event will only fire if the the cell loses focus. That happens if the user presses "return", "tab", or when they use the mouse to select something else. (documentation)

<DataGridTextColumn
    Header="Value"
    Binding="{Binding Value, UpdateSourceTrigger=LostFocus}" />

Below is a minimal example:

<!-- MainWindow.axaml -->
<Window xmlns="https://github.com/avaloniaui"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:AvaloniaApplication1"
        mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
        x:Class="AvaloniaApplication1.MainWindow"
        Title="AvaloniaApplication1"
        x:DataType="local:MainWindowViewModel">
    <DataGrid ItemsSource="{Binding Values}" BorderBrush="Gray" BorderThickness="1">
        <DataGrid.Columns>
            <DataGridTextColumn
                Header="Value"
                Binding="{Binding Value, UpdateSourceTrigger=LostFocus}" />
        </DataGrid.Columns>
    </DataGrid>
</Window>
// MainWindow.axaml.cs
public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();

        DataContext = new MainWindowViewModel()
        {
            Values = new([
                new ItemViewModel("A"),
                new ItemViewModel("B"),
                new ItemViewModel("C"),
            ]),
        };
    }
}

public partial class MainWindowViewModel : ObservableObject
{
    [ObservableProperty]
    private ObservableCollection<ItemViewModel>? _values;
}

public partial class ItemViewModel : ObservableObject
{
    public ItemViewModel(string initialValue)
    {
        _value = initialValue;
        PropertyChanged += OnPropertyChanged;
    }
    
    [ObservableProperty]
    private string? _value;

    private void OnPropertyChanged(object? sender, PropertyChangedEventArgs eventArgs)
    {
        if (eventArgs.PropertyName == nameof(Value))
            Console.WriteLine($"UPDATE {Value}");
    }
}
<!-- App.axaml -->
<Application xmlns="https://github.com/avaloniaui"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             x:Class="AvaloniaApplication1.App"
             RequestedThemeVariant="Default">

    <Application.Styles>
        <FluentTheme />
        <StyleInclude Source="avares://Avalonia.Controls.DataGrid/Themes/Fluent.xaml"/>
    </Application.Styles>
</Application>
Sign up to request clarification or add additional context in comments.

1 Comment

Oh yes, that's what I was looking for. You explained it well and went into detail, so I could understand how to use it on a real use-case thank you so much!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.