I'm really starting to dig this rx thing... Basically, I am following along with this video just to teach myself more about ReactiveUI before I start using it for real!
I am trying to create a situation when we use WhenAnyValue to perform a throttled search-as-you-type. And, if the search function throws an exception, I want to set a property on the view model called IsError
(so I can show an X or something). This the important parts of the ViewModel I have working:
public ReactiveCommand<string, IEnumerable<DictItem>> SearchCmmand;
... in vm constructor:
//create our command async from task. executes on worker thread
SearchCmmand = ReactiveCommand.CreateFromTask<string, IEnumerable<DicItem>>(async x => {
this.IsError = false;
//this may throw an exception:
return await GetFilteredAsync(this.SearchText);
});
//SearchCommand is subscribable.
//set the Filtered Items property. executes on main thread
SearchCmmand.Subscribe(filteredItems => {
this.FilteredItems = filteredItems;
});
//any unhandled exceptions that are thown in SearchCommand will bubble up through the ThrownExceptions observable
SearchCmmand.ThrownExceptions.Subscribe(ex=> {
this.IsError = true;
//but after this, then the WhenAnyValue no longer continues to work.
//how to get it back?
});
//invoke the command when SearchText changes
this.WhenAnyValue(v => v.SearchText)
.Throttle(TimeSpan.FromMilliseconds(500))
.InvokeCommand(SearchCmmand);
And this works. When my GetFilteredAsync
throws an exception, the SearchCmmand.ThrownExceptions
gets called and I can set my IsError
property.
However, when SearchCmmand.ThrownExceptions
happens the first time, the this.WhenAnyValue(v => v.SearchText)
stops working. I can see that it gets disposed. Subsequent changes to SearchText do not invoke the command. (though the command still works if I have a button bound to it)
It seems this is intended behaviour, but how can we get the observable working again? I realize that I could just wrap it all in a try/catch and return something that is not an exception, however, I see in the video (around 39:03) that in his case the searchtext continues to work after the exception is thrown? (the source code for that vid is here).
i also see here something about UserError
, but that's now marked as Legacy.
Ok so I have got something working, i though i'd post it. There were a couple issues i had to deal with. One was the fact that i was setting my
IsError=false
property inside my command async task code, (which fires on the background thread and hence throws an exception) and the other was dealing with how to re-subscribe the observable after the ThrownExceptions bubbles up. There are 2 approaches/workarounds that I found worked:here is the entire view model code that seems to work. WARNING: being new to rx/rxui myself, i don't know if this is the best way to do all of this! I'm imaginging there could be better ways!
you can use
interactions
Look at this : https://docs.reactiveui.net/en/user-guide/interactions/index.html