How to execute a command only once using ReactiveUI in Xamarin.Forms?

Using RxUI for Xamarin.Forms, how would you create a command that should be executed only once automatically (when the page first appears), but this user can request its execution later (for example, from pull to refresh kind events)?

I connected my command to the event Appearingusing FromEventPattern, but when I return to the page, it will be executed again, which is an undesirable behavior.

This is my scenario: I need the list to be automatically populated when the user opens the page containing it. Then the user can select the item and view its data on a separate page (using NavigationPage), but when the user returns to the list page, he will be populated, which should not happen. The user should be able to request new data on the button or pull to update, however.

Thank.

+4
source share
3 answers

This is how I dealt with this scenario. You will need a behavior like this that will only call your command for a given specific value.

// Only invoke the command when the property matches a known value that can't happen through normal execution
this.WhenAnyValue(vm => vm.SomeProperty)
                .Where(sp => sp == null)
                .Throttle(TimeSpan.FromSeconds(.25), TaskPoolScheduler.Default)
                .Do(_ => Debug.WriteLine($"Refresh the List"))
                .InvokeCommand(GetList)
                .DisposeWith(SubscriptionDisposables);

SomeProperty

this.SomeProperty = null; // or some value that makes sense

OnAppearing - , ViewModel , ViewModel . , , , , RxUI, .

OnAppearing , , canExecute ReactiveCommand ReactiveCommand PullToRefresh ( ). makeExecute , , , .

var isInitialized = this.WhenAnyValue(vm => vm.IsInit).Select( _ => _ == false).DistinctUntilChanged();

InitList = ReactiveCommand.CreateFromTask( _ => 
{ 
    // get list 
}, isInitialized);

RefreshList = ReactiveCommand.CreateFromTask( _ =>
{
    // essentially the same as InitList, but with different/no canExecute parameters
});

InitList.ObserveOn(RxApp.MainThreadScheduler).Subscribe(result =>
{
    this.IsInit = false
}).DisposeWith(SubscriptionDisposables);

, , ,

+1

Dorus: consturctor , Take :

Observable.FromEventPattern(ev => Appearing += ev, ev => Appearing -= ev)
            .Select(e => Unit.Default)
            .Take(1)
            .InvokeCommand(ViewModel.InitialCollectionLoad);
+2

, , , , .

I just use virtual machine creation as a trigger for the initial execution of the command. Then I associate the same command with the pull-to-refresh function in XF.

So my virtual machine looks like this:

public class MyVM
{
    public MYVM()
    {
        this.refreshCommand = ...;

        this
            .refreshCommand
            .Execute()
            .Subscribe()
                _ => {},
                _ => {});
    }

    public ReactiveCommand<...> RefreshCommand => this.refreshCommand;
}

Thus, the command is executed as soon as the virtual machine is created, so the data is retrieved as soon as possible. But it will not be re-executed again unless the virtual machine is recreated or the user tries to upgrade.

0
source

Source: https://habr.com/ru/post/1683966/


All Articles