David Specht David Specht - 2 months ago 17
Vb.net Question

ReactiveUI - Multiple InvokeCommand is not working for a single observable

My DetailsViewModel watches for changes in a selected EnvelopeViewModel and updates the AgendaItemId of the DetailsViewModel.

MessageBus.Current.Listen(Of EnvelopeViewModel) _
.Where(Function(x) x IsNot Nothing) _
.Select(Function(x) x.AgendaItemID) _
.ToPropertyEx(Me, Function(vm) vm.AgendaItemId)


I update the DetailsViewModel using the AgendaItem returned from _agendaItemService. I believe this is causing issues.

UpdateViewModel = ReactiveCommand.CreateAsyncTask(Function(x) _agendaItemService.FindAsync(AgendaItemId))
UpdateViewModel.SubscribeOn(RxApp.MainThreadScheduler).Subscribe(Sub(agendaItem) UpdateDetails(agendaItem))
UpdateViewModel.ThrownExceptions.Subscribe(Sub(ex) Log.ErrorException("LoadViewModel", ex))

WhenAnyValue(Function(vm) vm.AgendaItemId) _
.Where(Function(agendaItemId) agendaItemId > 0) _
.InvokeCommand(UpdateViewModel)

Private Sub UpdateDetails(agendaItem As AgendaItem)

_agendaItem = agendaItem

PrimaryAgendaCategoryId = _agendaItem.AgendaCategory.ParentId

PrimaryAmount = agendaItem.Amounts.Where(Function(x) x.AmountType = AmountType.Primary).Sum(Function(x) x.Value)
SecondaryAmount = agendaItem.Amounts.Where(Function(x) x.AmountType = AmountType.Secondary).Sum(Function(x) x.Value)
LocalMatchAmount = agendaItem.Amounts.Where(Function(x) x.AmountType = AmountType.LocalMatch).Sum(Function(x) x.Value)
ChangeOrderTotalAmount = agendaItem.Amounts.Where(Function(x) x.AmountType = AmountType.ChangeOrder).Sum(Function(x) x.Value)
ProjectTotalAmount = agendaItem.Amounts.Sum(Function(x) x.Value)

Mapper.Map(_agendaItem, Me)

'TODO fix this attempt at getting save button to refresh when amounts are changed and saved.
Name = ""
Name = _agendaItem.Name

End Sub


This actually appears to work. The DetailsView is updated with the new values. Where things fail is when I try update DepartmentContacts.

GetDepartmentContacts = ReactiveCommand.CreateAsyncTask(Function(x) _departmentService.GetDepartmentContactsAsync(AgendaItemId))
GetDepartmentContacts.ToPropertyEx(Me, Function(x) x.DepartmentContacts, New BindingList(Of PersonContactViewModel))
GetDepartmentContacts.ThrownExceptions.Subscribe(Sub(ex) Log.ErrorException("GetDepartmentContacts", ex))

WhenAnyValue(Function(vm) vm.AgendaItemId) _
.Where(Function(id) id > 0) _
.InvokeCommand(GetDepartmentContacts)


The ObservableAsPropertyHelper DepartmentContacts fails to update the View.

If, however, I comment out the invoke of the UpdateViewModel Command, DepartmentContacts is updated without issue.

There must be a better way in ReactiveUI to update my ViewModel.

Answer

I believe I found the answer with Combining Commands.

I think the issue is that I can't use InvokeCommand twice on the same observable. ReactiveCommand.CreateCombined let me combine the two commands into one command that could be invoked and it would handle invoking both commands assigned to it.

UpdateViewModel = ReactiveCommand.CreateAsyncTask(Function(x) _agendaItemService.FindAsync(AgendaItemId))
UpdateViewModel.SubscribeOn(RxApp.MainThreadScheduler).Subscribe(Sub(agendaItem) UpdateDetails(agendaItem))
UpdateViewModel.ThrownExceptions.Subscribe(Sub(ex) Log.ErrorException("LoadViewModel", ex))

GetDepartmentContacts = ReactiveCommand.CreateAsyncTask(Function(x) _departmentService.GetDepartmentContactsAsync(AgendaItemId))
GetDepartmentContacts.ToPropertyEx(Me, Function(x) x.DepartmentContacts, New BindingList(Of PersonContactViewModel))
GetDepartmentContacts.ThrownExceptions.Subscribe(Sub(ex) Log.ErrorException("GetDepartmentContacts", ex))

RefreshAgendaItemValues = ReactiveCommand.CreateCombined(RefreshViewModel, RefreshDepartmentContacts)

WhenAnyValue(Function(vm) vm.AgendaItemId) _
    .Where(Function(id) id > 0) _
    .InvokeCommand(RefreshAgendaItemValues)