How to two way bind a sourcecache to a datagrid in Avalonia so that the update event is triggered?

769 Views Asked by At

I would like to bind an Avalonia UI Datagrid with a dynamicdata sourcecache. I would like to be able to use a backend service that will be updated as soon as a change is made in the datagrid. So far I have been able to bind it in a way that Adds and Deletes are triggered. I haven't been able to trigger the update event. This is the code I use:

ViewModel

public class PersonVM:ViewModelBase
{
    private int _id;
    private string _lastName="";
    private string _firstName="";
    private int _age;
    
    public int Id { get => _id; set => this.RaiseAndSetIfChanged(ref _id, value); }
    public string LastName { get => _lastName; set => this.RaiseAndSetIfChanged(ref _lastName, value); }
    public string FirstName { get => _firstName; set => this.RaiseAndSetIfChanged(ref _firstName, value); }
    public int Age { get => _age; set => this.RaiseAndSetIfChanged(ref _age, value); }
}

Viewmodel for the main window

public class MainWindowViewModel : ViewModelBase
{        

    private SourceCache<PersonVM,int> _personsCache = new SourceCache<PersonVM,int>(x=>x.Id);
    
    private IObservableCollection<PersonVM> _persons = new ObservableCollectionExtended<PersonVM>();
    public IObservableCollection<PersonVM> Persons => _persons;
   
    public MainWindowViewModel()
    {
        _personsCache.AddOrUpdate(new PersonVM() { Id = 1, LastName = "Doe", FirstName = "John", Age = 24 });
        _personsCache.AddOrUpdate(new PersonVM() { Id = 2, LastName = "Doe", FirstName = "Jane", Age = 18 });
        _personsCache.AddOrUpdate(new PersonVM() { Id = 3, LastName = "Foo", FirstName = "Alice", Age = 20 });
        _personsCache.AddOrUpdate(new PersonVM() { Id = 4, LastName = "Bar", FirstName = "Bob", Age = 34 });
        _personsCache.
            Connect()
            .ForEachChange(x=>Debug.WriteLine($"{x.Reason}{x.Key}"))
            .ObserveOn(RxApp.MainThreadScheduler).Bind(_persons).Subscribe();
    }
// add a new line in the sourcecache
public void AddRow()
{
    int nextid = _personsCache.Keys.Max()+1;
    _personsCache.AddOrUpdate(new PersonVM() { Id=nextid,LastName="",FirstName="",Age=0} );
}

// delete a line in the sourcecache
public void DeleteRow(int id)
{
    _personsCache.RemoveKey(id);
}

// Tracker to check if the changes in the viewmodel have been correctly triggered.
public void ListItems()
{
    foreach(var v in _personsCache.Items)
    {
        Debug.WriteLine($"{v.Id}{v.LastName}{v.FirstName}{v.Age}");
    }
}

}

Main window XAML

<Window xmlns="https://github.com/avaloniaui"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:vm="using:DataGridBindingSourceCache.ViewModels"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
        x:Class="DataGridBindingSourceCache.Views.MainWindow"
        Icon="/Assets/avalonia-logo.ico"
        Title="DataGridBindingSourceCache">

    <Grid RowDefinitions="auto,1*,auto">
        <DataGrid Name="dgPersons" Items="{Binding Persons,Mode=TwoWay}" Grid.Row="1" IsReadOnly="False" >
            <DataGrid.Columns>
                <DataGridTextColumn Header="Id" Binding ="{Binding Id}"/>
                <DataGridTextColumn Header="Firstname" Binding ="{Binding FirstName, Mode=TwoWay}" IsReadOnly="False"/>
                <DataGridTextColumn Header="Lastname" Binding ="{Binding LastName, Mode=TwoWay}" IsReadOnly="False"/>
                <DataGridTextColumn Header="Age" Binding ="{Binding Age, Mode=TwoWay}" IsReadOnly="False"/>
                <DataGridTemplateColumn>
                    <DataTemplate>
                        <Button Content="Delete" Command="{Binding $parent[DataGrid].DataContext.DeleteRow}" CommandParameter="{Binding Id}"/>
                    </DataTemplate>
                </DataGridTemplateColumn>
            </DataGrid.Columns>
        </DataGrid>
        <StackPanel Grid.Row="2" Orientation="Horizontal">
            <Button Command="{Binding AddRow}">Add row</Button>
            <Button Command="{Binding ListItems}">List items</Button>
        </StackPanel>
    </Grid>

</Window>

The update I make in the Datagrid seems to be reported in the sourcecache (as can be ssen with the ListItems function), but the update event of the sourcecache is not triggered when I do a change in the Datagrid.

Could you please point me to what I am doing wrong? Thanks a lot.

0

There are 0 best solutions below