Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ArgumentNullException error #3094

Closed
papafe opened this issue Nov 14, 2022 Discussed in #3093 · 8 comments · Fixed by #3097
Closed

ArgumentNullException error #3094

papafe opened this issue Nov 14, 2022 Discussed in #3093 · 8 comments · Fixed by #3097
Assignees

Comments

@papafe
Copy link
Contributor

papafe commented Nov 14, 2022

Discussed in #3093

Originally posted by Unreal852 November 13, 2022
Hello, i'm making an application with AvaloniaUI and i decided to use Realm as my database but when i bind my view to fields that belongs to an IRealmObject it throws ArgumentNullException. I created a separate project to replicate the issue https://github.com/Unreal852/RealmAvalonia
I did not create an issue because i don't know if i'm doing things wrong or not.

@Unreal852
Copy link

I'll give more details about this.

I have my AvaloniaUI app using MVVM pattern, so i got 3 components, the View, the ViewModel and the Model

Here is the View :

 <Grid RowDefinitions="Auto *">
        <Button Content="Add" Command="{Binding AddPlayer}"/>
        <ListBox Grid.Row="1" Items="{Binding Players}">
            <ListBox.ItemTemplate>
                <DataTemplate DataType="{x:Type models:Player}">
                    <StackPanel Orientation="Vertical">
                        <TextBlock Text="{Binding Name}" />
                        <Label Content="{Binding Experience}" />
                    </StackPanel>
                </DataTemplate>
            </ListBox.ItemTemplate>
        </ListBox> 
    </Grid>

Here is the ViewModel :

public class MainWindowViewModel : ReactiveObject
{
    public ObservableCollection<Player> Players { get; } = new();

    public void AddPlayer()
    {
        Players.Add(new Player { Name = "Unreal", Experience = 15.2 });
    }
}

And here is the Model :

public partial class Player : IRealmObject
{
    public string? Name       { get; set; }
    public double  Experience { get; set; }
}

I'm using Realm source generator so i implemented IRealmObject to my Model.
When i run this and then add a new Player instance to in my ViewModel it throws System.ArgumentNullException: Value cannot be null. (Parameter 'source')

realm_avalonia

Now if i remove the IRealmObject interface from my model, everything runs fine.

realm_avalonia_2

Also, you can try by yourself with this Github Repo, just clone and run it.

@papafe
Copy link
Contributor Author

papafe commented Nov 14, 2022 via email

@goldindan
Copy link

The same issue, if i go back to 10.17 and using RealObject instead of IReactObject is working good

@papafe papafe self-assigned this Nov 16, 2022
@papafe
Copy link
Contributor Author

papafe commented Nov 17, 2022

@Unreal852 and @goldindan I think I found the reason for the issue, and I'm working on a solution.
This is happening only with unmanaged objects, when a Realm object is used in bindings before it has been added to a realm.

I can also see that in your code you are using ObservableCollection. When using Realm you actually don't need it, as you can bind directly to queries, and the UI will be changed automatically.
For example, you can do something like this for your MainViewModel:

public class MainWindowViewModel : ReactiveObject
{
    private Realm _realm;
    public IQueryable<Player> Players { get; }

    public MainWindowViewModel()
    {
        _realm = Realm.GetInstance();
        Players = _realm.All<Player>();
    }

    public void AddPlayer()
    {
        _realm.Write(() =>
        {
            _realm.Add(new Player { Name = "Unreal", Experience = 15.2 });
        });
    }
}

With this approach you don't need to worry about the Players collection as before, you just need to update the database and the UI will reflect the changes. You can also make more complicated queries, for instance:

Players = _realm.All<Player>().Where( p => p.Age > 25);

This is the approach that we generally recommend developers, as it is the most idiomatic one, and developers don't need to worry about keeping collections updated.
Another note. In order to make the code that I've shown work with Avalonia you need to use ItemsControl instead of ListBox in the view, as ListBox needs to be bound to a collection that implements IList, but Players does not. I am not an expert of Avalonia, so I am not sure of what would be the best approach, and why they need the collection to implement IList necessarily, but I hope this will be of help.

@Unreal852
Copy link

Hi, thanks for the quick fix. I didn't know we could bind directly on Realm collections this is nice.

@papafe
Copy link
Contributor Author

papafe commented Nov 17, 2022

@Unreal852 just as an additional note, you can take look at our example project if you want to have some other examples of how to use bindings with Realm. The project uses Xamarin, but I think you can get the idea

@goldindan
Copy link

How can we fix the problem of binding an unmanaged IRealmObject to the view?

@papafe
Copy link
Contributor Author

papafe commented Nov 18, 2022

@goldindan this will be fixed in the next version (the fix is in review in PR #3097)

@github-actions github-actions bot locked as resolved and limited conversation to collaborators Mar 14, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants