Using CurrentCellEndEdit to update IRealObject or bind DataGrid to ViewModel

Hi,

in my Project (based on https://github.com/mongodb/template-app-maui-todo) I have a page (PartyItemsPage) with a datagrid showing the items in my model Partyitem, which is bound to a online Database via Realm/MongoDB. I would like to use the edit-feature of datagrid, which should then update the model and online databse. When ending the editing by pressing enter the following error message pops up:

Realms.Exceptions.RealmInvalidTransactionException: 'Cannot modify managed objects outside of a write transaction.'

I asked chatGPT for help and it recommended to either insert a new viewmodel in between the datagrid and the model  or use a event handler to triggers the Realms write command. I think "CurrentCellEndEdit" would be the one to go for, but I can't get it to run.

Hope you can help me and thanks in advance,

Toby


The Model PartyItems.cs:

public partial class Partyitem : IRealmObject
{
    [PrimaryKey]
    [MapTo("_id")]
    public ObjectId Id { get; set; } = ObjectId.GenerateNewId();

    [MapTo("owner_id")]
    [Required]
    public string OwnerId { get; set; }

    public bool IsMine => OwnerId == RealmService.CurrentUser.Id;

    [MapTo("partyname")]
    [Required]
    public string PartyName { get; set; }

The Viewmodel PartyItemsViewModel.cs:

public partial class PartyItemsViewModel : BaseViewModel
{
    [ObservableProperty]
    private string connectionStatusIcon = "wifi_on.png";


    [ObservableProperty]
    private bool isShowAllTasks;


    [ObservableProperty]
    private IQueryable<Partyitem> partyitems;


    [ObservableProperty]
    public string dataExplorerLink = RealmService.DataExplorerLink;


    private Realm realm;
    private string currentUserId;
    private bool isOnline = true;


    [RelayCommand]
    public void OnAppearing()
    {
        realm = RealmService.GetMainThreadRealm();
        currentUserId = RealmService.CurrentUser.Id;
        Partyitems = realm.All<Partyitem>().OrderBy(i => i.Id).Where(i => i.OwnerId == RealmService.CurrentUser.Id);


    }

The Page PartyItemsPage.xaml:

<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="MyApp.Views.PartyItemsPage"
             xmlns:toolkit="http://schemas.microsoft.com/dotnet/2022/maui/toolkit"
             xmlns:vm="clr-namespace:MyApp.ViewModels"
             xmlns:syncfusion="clr-namespace:Syncfusion.Maui.DataGrid;assembly=Syncfusion.Maui.DataGrid"
             xmlns:helpers="clr-namespace:MyApp.Helpers"
             x:Name="partyitemsPage">


    <ContentPage.Behaviors>
        <toolkit:EventToCommandBehavior
            EventName="Appearing"
            Command="{Binding AppearingCommand}" />
    </ContentPage.Behaviors>
    
    <ContentPage.BindingContext>
        <vm:PartyItemsViewModel />
    </ContentPage.BindingContext>


    <syncfusion:SfDataGrid
        x:Name="dataGrid"
        AutoGenerateColumnsMode="None"
        ItemsSource="{Binding Partyitems}"
        SortingMode="Single"
        AllowEditing="True"
        SelectionMode="Single"
        NavigationMode="Cell">


        <syncfusion:SfDataGrid.Columns>
            <syncfusion:DataGridTextColumn HeaderText="Name"
                                   MappingName="PartyName"/>
        </syncfusion:SfDataGrid.Columns>

</syncfusion:SfDataGrid>


The Realms Write command used in the example app to edit items:

 public partial class EditItemViewModel : BaseViewModel, IQueryAttributable
{
    [ObservableProperty]
    private Item initialItem;

    [ObservableProperty]
    private string summary; //summary is in my case the variable Partyname in Partyitems


    [ObservableProperty]
    private string pageHeader;


    public void ApplyQueryAttributes(IDictionary<string, object> query)
    {
        if (query.Count > 0 && query["item"] != null) // we're editing an Item
        {
            InitialItem = query["item"] as Item;
            Summary = InitialItem.Summary;
            PageHeader = $"Modify Item {InitialItem.Id}";
        }
        else // we're creating a new item
        {
            Summary = "";
            PageHeader = "Create a New Item";
        }
    }

    [RelayCommand]
    public async Task SaveItem()
    {
        var realm = RealmService.GetMainThreadRealm();
        await realm.WriteAsync(() =>
        {
            if (InitialItem != null) // editing an item
            {
                InitialItem.Summary = Summary;
            }
            else // creating a new item
            {
                realm.Add(new Item()
                {
                    OwnerId = RealmService.CurrentUser.Id,
                    Summary = summary
                });
            }
        });

        await Shell.Current.GoToAsync("..");
    }




4 Replies 1 reply marked as answer

TH Tobias Horn January 17, 2024 07:44 AM UTC

Hi, I created a example app recreating the error. maybe this helps with fxing it.


The dummy Login would be:


Email: [email protected]

Password: testtest


The datagrid shows the item Summary saying "Hello Syncfusion". When you edit the item and press enter to end the editing, the error occurs.


Thanks in advance,

Tobias


Attachment: RealmTodo2master_3bb90f94.zip


TP Tamilarasan Paranthaman Syncfusion Team January 22, 2024 01:29 PM UTC

Hi Tobias Horn,

Upon reviewing the provided sample on our end, we encountered the same issue you described. However, our investigation suggests that the problem you're facing may not be directly related to the DataGrid. Upon further examination, it appears that the issue may stem from the `realm`.


For more detailed information and assistance regarding this matter, we recommend checking the details provided in the following links and raising any queries in the corresponding pages.


https://www.mongodb.com/community/forums/t/error-cannot-update-obj-outside-of-write-transaction-while-in-a-write-transaction/188438

https://stackoverflow.com/questions/48886931/cannot-modify-managed-objects-outside-of-a-write-transaction-realm-android

Regards,

Tamilarasan


Marked as answer

TH Tobias Horn replied to Tamilarasan Paranthaman January 23, 2024 02:06 PM UTC

Hi,


thx for your reply. Indeed the issue was with Realm.

The workaround (if anyone faces the same issue) would be to create a dummyitem model. you bind the realm object to the dummy and feed the dummy to the datagrid. then, the endeditcell hook works to trigger the realm write task as the realm object is not changed by edit directly.



DG David Gerding replied to Tobias Horn May 4, 2024 09:46 PM UTC

Hi Tobias,

Would you be willing to give a little more detail about your solution? A code fragment? 

I also can't sorting to work in a datagrid bound to Realm and think your approach may be what I need.

Dave G


Loader.
Up arrow icon