c# - How do you use RoutingState.NavigateCommandFor<T> properly -


i trying follow view model navigation pattern established in xamforms playground ran troubles getting work properly.

given following code, can see problem is:

// router = new routingstate(); // navigate = router.navigatecommandfor<myviewmodel>();  this.whenanyvalue(x => x.viewmodel.navigate)     //.do(x => x.canexecuteobservable.subscribe())     .bindto(this, x => x.navigatebutton.command);  this.whenanyvalue(x => x.viewmodel.router)     .bindto(this, x => x.viewhost.router); 

if bind navigate command button's command object, it's initial canexecute state false , there never adjustment initial state. if uncomment do code above force initial state computed , button enables appropriately.

obviously, not correct me, expect initial canexecute state true (at least after ui loaded).

what worse, appears heisenbug because if ever check canexecute state of routingstate.navigate or myviewmodel.navigate commands (with canexecute(null)), return true , button display enabled upon continuation (note have check view model command enable button).

i want apply pattern correctly quite confused why seemingly simple pattern failing scenario. can confirm or deny correct approach?

doing more research on question able clear confusion, still not quite answer question. below discoveries:

first, proper way bind command according online documentation, is

this.bindcommand(viewmodel, x => x.navigate, x => x.navigatebutton); 

the code sample posted above should this, if in proper (current) reactiveui framework:

this.bindcommand(viewmodel, x => x.navigate, x => x.navigatebutton); // note used "hack" binding router above, correct binding strategy this.onewaybind(viewmodel, x => x.router, x => x.viewhost.router); 

in order (as seamlessly possible) create navigation commands routable view models, have created extensions methods (temporarily suffixed numbers) perform canexecuteobservable subscribe before returning command. @ time i'm not sure best choice extension method be, i'm leaning towards numbers 3 , 4 produce typed generic command (which give automatic observability, compared ireactivecommand).

// navigatecommandfor extensions provide ability inject navigate command (the default navigate, or navigateandreset),  // dependency resolver (still defaults locator.current), , type resolution contract public static partial class extensionmethods {     // simple extension inline subscription     public static t subscribetocommand<t>(this t this)         t : ireactivecommand     {         this.canexecuteobservable.subscribe();          return this;     }      // first attempt without analyzing current navigatecommandfor source     public static ireactivecommand<object> navigatecommandfor1<t>(this routingstate this, ireactivecommand<object> navigationcommand = null, idependencyresolver dependencyresolver = null, string contract = null)         t : iroutableviewmodel     {         navigationcommand = navigationcommand ?? this.navigate;          var ret = reactivecommand.createasyncobservable(navigationcommand.canexecuteobservable, _ => navigationcommand.executeasync((dependencyresolver ?? locator.current).getservice<t>(contract)));          return ret.subscribetocommand();     }      // after looking @ navigatecommandfor source, minimalistic adaptation      // except ajusting return value generic interface object type param     public static ireactivecommand<object> navigatecommandfor2<t>(this routingstate this, ireactivecommand<object> navigationcommand = null, idependencyresolver dependencyresolver = null, string contract = null)         t : iroutableviewmodel     {         navigationcommand = navigationcommand ?? this.navigate;          var ret = new reactivecommand<object>(navigationcommand.canexecuteobservable, x => observable.return(x));          ret.select(_ => (dependencyresolver ?? locator.current).getservice<t>(contract)).invokecommand(navigationcommand);          return ret.subscribetocommand();     }      // attempt optimize return value typed     // i'm not sure if has implications     public static ireactivecommand<t> navigatecommandfor3<t>(this routingstate this, ireactivecommand<object> navigationcommand = null, idependencyresolver dependencyresolver = null, string contract = null)         t : iroutableviewmodel     {         navigationcommand = navigationcommand ?? this.navigate;          var ret = new reactivecommand<t>(navigationcommand.canexecuteobservable, _ => observable.return((dependencyresolver ?? locator.current).getservice<t>(contract)));          ret.invokecommand(navigationcommand);          return ret.subscribetocommand();     }      // original source allows un-registered view models new()'d     // extension provides same ability, again typed return value     public static ireactivecommand<t> navigatecommandfor4<t>(this routingstate this, ireactivecommand<object> navigationcommand = null, idependencyresolver dependencyresolver = null, string contract = null)         t : iroutableviewmodel, new()     {         navigationcommand = navigationcommand ?? this.navigate;          var ret = new reactivecommand<t>(navigationcommand.canexecuteobservable, _ => observable.return((t)((iroutableviewmodel)(dependencyresolver ?? locator.current).getservice<t>(contract) ?? new t())));          ret.invokecommand(navigationcommand);          return ret.subscribetocommand();     } } 

i'm still not sure of these extensions appropriate, or why subscribing canexecuteobservable necessary (i assume bug in reactivecommand), above considered viable work-around problem posted (however not answer question still think not proper usage of navigatecommandfor).


Comments

Popular posts from this blog

python - Healpy: From Data to Healpix map -

c - Bitwise operation with (signed) enum value -

xslt - Unnest parent nodes by child node -