@@ -346,6 +346,293 @@ public async Task BasicNoParam_DoubleDispose_DoesNotThrow()
346346 await Assert . That ( action ) . ThrowsNothing ( ) ;
347347 }
348348
349+ // ── EventEnabled (Click + Enabled, no Command property) ─────────────
350+
351+ /// <summary>
352+ /// Verifies that clicking executes the command via event+Enabled binding.
353+ /// </summary>
354+ /// <returns>A task representing the asynchronous test operation.</returns>
355+ [ Test ]
356+ public async Task EventEnabled_ClickExecutesCommand ( )
357+ {
358+ var vm = new SharedScenarios . BindCommand . EventEnabled . MyViewModel ( ) ;
359+ var view = new SharedScenarios . BindCommand . EventEnabled . MyView ( ) ;
360+ var command = new TrackingCommand ( ) ;
361+ vm . Save = command ;
362+
363+ using var binding = BindCommandScenarios . EventEnabled ( vm , view ) ;
364+ view . SaveButton . PerformClick ( ) ;
365+
366+ await Assert . That ( command . ExecuteCount ) . IsEqualTo ( 1 ) ;
367+ }
368+
369+ /// <summary>
370+ /// Verifies that the Enabled property is synchronized with CanExecute.
371+ /// </summary>
372+ /// <returns>A task representing the asynchronous test operation.</returns>
373+ [ Test ]
374+ public async Task EventEnabled_EnabledSyncedWithCanExecute ( )
375+ {
376+ var vm = new SharedScenarios . BindCommand . EventEnabled . MyViewModel ( ) ;
377+ var view = new SharedScenarios . BindCommand . EventEnabled . MyView ( ) ;
378+ var command = new TrackingCommand { CanExecuteResult = false } ;
379+ vm . Save = command ;
380+
381+ using var binding = BindCommandScenarios . EventEnabled ( vm , view ) ;
382+
383+ await Assert . That ( view . SaveButton . Enabled ) . IsFalse ( ) ;
384+ }
385+
386+ /// <summary>
387+ /// Verifies that the Enabled property becomes false when the command is null.
388+ /// </summary>
389+ /// <returns>A task representing the asynchronous test operation.</returns>
390+ [ Test ]
391+ public async Task EventEnabled_NullCommand_DisablesControl ( )
392+ {
393+ var vm = new SharedScenarios . BindCommand . EventEnabled . MyViewModel ( ) ;
394+ var view = new SharedScenarios . BindCommand . EventEnabled . MyView ( ) ;
395+
396+ using var binding = BindCommandScenarios . EventEnabled ( vm , view ) ;
397+
398+ await Assert . That ( view . SaveButton . Enabled ) . IsFalse ( ) ;
399+ }
400+
401+ /// <summary>
402+ /// Verifies that disposing the binding stops command execution.
403+ /// </summary>
404+ /// <returns>A task representing the asynchronous test operation.</returns>
405+ [ Test ]
406+ public async Task EventEnabled_Dispose_StopsExecution ( )
407+ {
408+ var vm = new SharedScenarios . BindCommand . EventEnabled . MyViewModel ( ) ;
409+ var view = new SharedScenarios . BindCommand . EventEnabled . MyView ( ) ;
410+ var command = new TrackingCommand ( ) ;
411+ vm . Save = command ;
412+
413+ var binding = BindCommandScenarios . EventEnabled ( vm , view ) ;
414+ view . SaveButton . PerformClick ( ) ;
415+ await Assert . That ( command . ExecuteCount ) . IsEqualTo ( 1 ) ;
416+
417+ binding . Dispose ( ) ;
418+ view . SaveButton . PerformClick ( ) ;
419+
420+ await Assert . That ( command . ExecuteCount ) . IsEqualTo ( 1 ) ;
421+ }
422+
423+ /// <summary>
424+ /// Verifies that CanExecute=false prevents execution via event+Enabled binding.
425+ /// </summary>
426+ /// <returns>A task representing the asynchronous test operation.</returns>
427+ [ Test ]
428+ public async Task EventEnabled_CanExecuteFalse_DoesNotExecute ( )
429+ {
430+ var vm = new SharedScenarios . BindCommand . EventEnabled . MyViewModel ( ) ;
431+ var view = new SharedScenarios . BindCommand . EventEnabled . MyView ( ) ;
432+ var command = new TrackingCommand { CanExecuteResult = false } ;
433+ vm . Save = command ;
434+
435+ using var binding = BindCommandScenarios . EventEnabled ( vm , view ) ;
436+ view . SaveButton . PerformClick ( ) ;
437+
438+ await Assert . That ( command . ExecuteCount ) . IsEqualTo ( 0 ) ;
439+ }
440+
441+ /// <summary>
442+ /// Verifies event+Enabled binding with an expression parameter.
443+ /// </summary>
444+ /// <returns>A task representing the asynchronous test operation.</returns>
445+ [ Test ]
446+ public async Task EventEnabledExprParam_PassesParameter ( )
447+ {
448+ var vm = new SharedScenarios . BindCommand . EventEnabledExprParam . MyViewModel
449+ {
450+ CurrentItem = "TestItem" ,
451+ } ;
452+ var view = new SharedScenarios . BindCommand . EventEnabledExprParam . MyView ( ) ;
453+ var command = new TrackingCommand ( ) ;
454+ vm . Save = command ;
455+
456+ using var binding = BindCommandScenarios . EventEnabledExprParam ( vm , view ) ;
457+ view . SaveButton . PerformClick ( ) ;
458+
459+ await Assert . That ( command . ExecuteCount ) . IsEqualTo ( 1 ) ;
460+ await Assert . That ( command . LastParameter ) . IsEqualTo ( "TestItem" ) ;
461+ }
462+
463+ /// <summary>
464+ /// Verifies event+Enabled binding with an observable parameter.
465+ /// </summary>
466+ /// <returns>A task representing the asynchronous test operation.</returns>
467+ [ Test ]
468+ public async Task EventEnabledObsParam_PassesParameter ( )
469+ {
470+ var vm = new SharedScenarios . BindCommand . EventEnabledObsParam . MyViewModel ( ) ;
471+ var view = new SharedScenarios . BindCommand . EventEnabledObsParam . MyView ( ) ;
472+ var command = new TrackingCommand ( ) ;
473+ var paramSubject = new System . Reactive . Subjects . BehaviorSubject < string > ( "obs-param" ) ;
474+ vm . Save = command ;
475+
476+ using var binding = BindCommandScenarios . EventEnabledObsParam ( vm , view , paramSubject ) ;
477+ view . SaveButton . PerformClick ( ) ;
478+
479+ await Assert . That ( command . ExecuteCount ) . IsEqualTo ( 1 ) ;
480+ await Assert . That ( command . LastParameter ) . IsEqualTo ( "obs-param" ) ;
481+ }
482+
483+ /// <summary>
484+ /// Verifies event+Enabled binding with observable parameter updates reactively.
485+ /// </summary>
486+ /// <returns>A task representing the asynchronous test operation.</returns>
487+ [ Test ]
488+ public async Task EventEnabledObsParam_ParameterUpdates ( )
489+ {
490+ var vm = new SharedScenarios . BindCommand . EventEnabledObsParam . MyViewModel ( ) ;
491+ var view = new SharedScenarios . BindCommand . EventEnabledObsParam . MyView ( ) ;
492+ var command = new TrackingCommand ( ) ;
493+ var paramSubject = new System . Reactive . Subjects . BehaviorSubject < string > ( "initial" ) ;
494+ vm . Save = command ;
495+
496+ using var binding = BindCommandScenarios . EventEnabledObsParam ( vm , view , paramSubject ) ;
497+
498+ paramSubject . OnNext ( "updated" ) ;
499+ view . SaveButton . PerformClick ( ) ;
500+
501+ await Assert . That ( command . LastParameter ) . IsEqualTo ( "updated" ) ;
502+ }
503+
504+ // ── CommandProperty (Command + CommandParameter, no event) ──────────
505+
506+ /// <summary>
507+ /// Verifies that binding sets the Command property on the control.
508+ /// </summary>
509+ /// <returns>A task representing the asynchronous test operation.</returns>
510+ [ Test ]
511+ public async Task CommandProperty_SetsCommandOnControl ( )
512+ {
513+ var vm = new SharedScenarios . BindCommand . CommandProperty . MyViewModel ( ) ;
514+ var view = new SharedScenarios . BindCommand . CommandProperty . MyView ( ) ;
515+ var command = new TrackingCommand ( ) ;
516+ vm . Save = command ;
517+
518+ using var binding = BindCommandScenarios . CommandProperty ( vm , view ) ;
519+
520+ await Assert . That ( view . SaveButton . Command ) . IsEqualTo ( command ) ;
521+ }
522+
523+ /// <summary>
524+ /// Verifies that setting the command after binding updates the control.
525+ /// </summary>
526+ /// <returns>A task representing the asynchronous test operation.</returns>
527+ [ Test ]
528+ public async Task CommandProperty_CommandSetAfterBinding_UpdatesControl ( )
529+ {
530+ var vm = new SharedScenarios . BindCommand . CommandProperty . MyViewModel ( ) ;
531+ var view = new SharedScenarios . BindCommand . CommandProperty . MyView ( ) ;
532+ var command = new TrackingCommand ( ) ;
533+
534+ using var binding = BindCommandScenarios . CommandProperty ( vm , view ) ;
535+
536+ vm . Save = command ;
537+
538+ await Assert . That ( view . SaveButton . Command ) . IsEqualTo ( command ) ;
539+ }
540+
541+ /// <summary>
542+ /// Verifies that changing the command updates the control's Command property.
543+ /// </summary>
544+ /// <returns>A task representing the asynchronous test operation.</returns>
545+ [ Test ]
546+ public async Task CommandProperty_CommandChanges_ControlUpdated ( )
547+ {
548+ var vm = new SharedScenarios . BindCommand . CommandProperty . MyViewModel ( ) ;
549+ var view = new SharedScenarios . BindCommand . CommandProperty . MyView ( ) ;
550+ var first = new TrackingCommand ( ) ;
551+ var second = new TrackingCommand ( ) ;
552+ vm . Save = first ;
553+
554+ using var binding = BindCommandScenarios . CommandProperty ( vm , view ) ;
555+ await Assert . That ( view . SaveButton . Command ) . IsEqualTo ( first ) ;
556+
557+ vm . Save = second ;
558+ await Assert . That ( view . SaveButton . Command ) . IsEqualTo ( second ) ;
559+ }
560+
561+ /// <summary>
562+ /// Verifies that null command results in null on the control.
563+ /// </summary>
564+ /// <returns>A task representing the asynchronous test operation.</returns>
565+ [ Test ]
566+ public async Task CommandProperty_NullCommand_SetsControlCommandNull ( )
567+ {
568+ var vm = new SharedScenarios . BindCommand . CommandProperty . MyViewModel ( ) ;
569+ var view = new SharedScenarios . BindCommand . CommandProperty . MyView ( ) ;
570+
571+ using var binding = BindCommandScenarios . CommandProperty ( vm , view ) ;
572+
573+ await Assert . That ( view . SaveButton . Command ) . IsNull ( ) ;
574+ }
575+
576+ /// <summary>
577+ /// Verifies that expression parameter sets CommandParameter on the control.
578+ /// </summary>
579+ /// <returns>A task representing the asynchronous test operation.</returns>
580+ [ Test ]
581+ public async Task CommandPropertyExprParam_SetsCommandParameter ( )
582+ {
583+ var vm = new SharedScenarios . BindCommand . CommandPropertyExprParam . MyViewModel
584+ {
585+ CurrentItem = "TestItem" ,
586+ } ;
587+ var view = new SharedScenarios . BindCommand . CommandPropertyExprParam . MyView ( ) ;
588+ var command = new TrackingCommand ( ) ;
589+ vm . Save = command ;
590+
591+ using var binding = BindCommandScenarios . CommandPropertyExprParam ( vm , view ) ;
592+
593+ await Assert . That ( view . SaveButton . Command ) . IsEqualTo ( command ) ;
594+ await Assert . That ( view . SaveButton . CommandParameter ) . IsEqualTo ( "TestItem" ) ;
595+ }
596+
597+ /// <summary>
598+ /// Verifies that observable parameter sets CommandParameter on the control.
599+ /// </summary>
600+ /// <returns>A task representing the asynchronous test operation.</returns>
601+ [ Test ]
602+ public async Task CommandPropertyObsParam_SetsCommandParameter ( )
603+ {
604+ var vm = new SharedScenarios . BindCommand . CommandPropertyObsParam . MyViewModel ( ) ;
605+ var view = new SharedScenarios . BindCommand . CommandPropertyObsParam . MyView ( ) ;
606+ var command = new TrackingCommand ( ) ;
607+ var paramSubject = new System . Reactive . Subjects . BehaviorSubject < string > ( "obs-param" ) ;
608+ vm . Save = command ;
609+
610+ using var binding = BindCommandScenarios . CommandPropertyObsParam ( vm , view , paramSubject ) ;
611+
612+ await Assert . That ( view . SaveButton . Command ) . IsEqualTo ( command ) ;
613+ await Assert . That ( view . SaveButton . CommandParameter ) . IsEqualTo ( "obs-param" ) ;
614+ }
615+
616+ /// <summary>
617+ /// Verifies that the observable parameter updates CommandParameter reactively.
618+ /// </summary>
619+ /// <returns>A task representing the asynchronous test operation.</returns>
620+ [ Test ]
621+ public async Task CommandPropertyObsParam_ParameterUpdates ( )
622+ {
623+ var vm = new SharedScenarios . BindCommand . CommandPropertyObsParam . MyViewModel ( ) ;
624+ var view = new SharedScenarios . BindCommand . CommandPropertyObsParam . MyView ( ) ;
625+ var command = new TrackingCommand ( ) ;
626+ var paramSubject = new System . Reactive . Subjects . BehaviorSubject < string > ( "initial" ) ;
627+ vm . Save = command ;
628+
629+ using var binding = BindCommandScenarios . CommandPropertyObsParam ( vm , view , paramSubject ) ;
630+
631+ paramSubject . OnNext ( "updated" ) ;
632+
633+ await Assert . That ( view . SaveButton . CommandParameter ) . IsEqualTo ( "updated" ) ;
634+ }
635+
349636 /// <summary>
350637 /// A simple <see cref="ICommand"/> implementation that tracks invocations for testing.
351638 /// </summary>
0 commit comments