Here's how I've handled this scenario. You'll need a behavior similar to this one, which will invoke your command only when a specific, known value is set.
// 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);
At the end of your constructor, set SomeProperty to match the known value
this.SomeProperty = null; // or some value that makes sense
In this case, you don't need to fire the command manually in OnAppearing - it happens when your ViewModel is constructed for the first time and will not be executed again until the ViewModel is disposed and recreated.
It seems a little hack-ey to me, so I'm hoping wiser, more seasoned RxUI wizards will chime in, but it gets the job done.
If you prefer to leave the OnAppearing call in place, you could also potentially handle this by setting the canExecute property of your ReactiveCommand and using an entirely different ReactiveCommand for your PullToRefresh action (even though both commands would behave the same otherwise). In this scenario, you'd want to make the canExecute always false after the list is populated initially, so even when the user return to the page the initial population isn't triggered.
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);
The disadvantage here is, obviously, you have some logic duplicated