I have written a test program to get to know DynamicData
and Rx.Net.
The GUI framework is Avalonia.
I have an entity firmware and a repository with an async
function which loads the data and can take a long time:
namespace DynamicDataWithGui.Models;
public class Firmware
{
public Guid Id { get; set; }
public string Name { get; set; }
}
public class Repository
{
private readonly CompositeDisposable _subscription = new();
private ISourceCache<Firmware, Guid> _internalCache;
public IObservableCache<Firmware, Guid> LoadInitialData()
{
return ObservableChangeSet.Create<Firmware, Guid>(cache =>
{
var d = GetListAsync()
.ToObservable()
.Select(l =>
{
cache.Edit(edit => edit.AddOrUpdate(l));
_internalCache = cache;
return l;
})
.Subscribe()
.DisposeWith(_subscription);
return d;
}, t => t.Id)
.AsObservableCache();
}
private async Task<List<Firmware>> GetListAsync()
{
var result = new List<Firmware>();
for (int i = 0; i < 10; i++)
{
result.Add(new Firmware { Id = Guid.NewGuid(), Name = $"Firmware {i + 1}" });
}
await Task.Delay(5000);
return result;
}
}
Then I represent the firmware entity as a child in an ArticleViewModel
like so:
namespace DynamicDataWithGui.ViewModels;
public class FirmwareViewModel: ViewModelBase
{
[Reactive] public string Id { get; set; }
[Reactive] public string Name { get; set; }
public FirmwareViewModel(Firmware firmware)
{
Id = firmware.Id.ToString();
Name = firmware.Name;
}
}
public class ArticleViewModel: ViewModelBase
{
private readonly CompositeDisposable _disposables = new();
[Reactive] public string Name { get; set; }
[Reactive] public bool IsLoading { get; set; }
public ObservableCollectionExtended<FirmwareViewModel> FirmwareChildren { get; private set; } = new();
public ArticleViewModel()
{
var repository = new Repository();
var dummyFirmwareViewModel =
new FirmwareViewModel( new Firmware{ Id = Guid.Empty, Name = string.Empty });
FirmwareChildren.Add(dummyFirmwareViewModel);
this.WhenAnyValue(vm => vm.IsExpanded)
.Where(isExpanded => isExpanded)
.Select(b =>
{
if (FirmwareChildren.Contains(dummyFirmwareViewModel))
{
IsLoading = true;
FirmwareChildren.Remove(dummyFirmwareViewModel);
repository.LoadInitialData()
.Connect()
.Transform(firmware => new FirmwareViewModel(firmware))
.ObserveOn(RxApp.MainThreadScheduler)
.Bind(FirmwareChildren)
.LastAsync(_ => IsLoading = false)
.Subscribe()
.DisposeWith(_disposables);
}
else
{
FirmwareChildren.Remove(dummyFirmwareViewModel);
}
return b;
})
.Subscribe()
.DisposeWith(_disposables);
}
}
In the Gui I bind the properties of the ViewModels to a Treeview
. Everything works so far.
But I think I made mistakes especially in the LoadInitialData
function and the monitoring of the IsExpanded property.
Maybe you can point me in the right direction.
The question is, how can I improve the exposing of the _innerCache
in LoadInitalData
? And, is the subcription of the IsExpanded
property correct? Or can I improve here something.