diff --git a/src/ReactiveUI/Bindings/Command/CommandBinder.cs b/src/ReactiveUI/Bindings/Command/CommandBinder.cs
index 36c1fffe5b..0c5a8cefa8 100644
--- a/src/ReactiveUI/Bindings/Command/CommandBinder.cs
+++ b/src/ReactiveUI/Bindings/Command/CommandBinder.cs
@@ -32,26 +32,30 @@ static CommandBinder() => _binderImplementation = AppLocator.Current.GetService<
///
/// Binds a command from the view model to a control on the view, enabling the control to execute the command with a
- /// parameter when triggered.
+ /// specified parameter when an event is raised.
///
- /// This method uses reflection to dynamically observe events and properties on the control,
- /// which may be affected by trimming in some deployment scenarios. The binding remains active until the returned
- /// IReactiveBinding is disposed.
- /// The type of the view implementing the IViewFor interface.
- /// The type of the view model containing the command property.
- /// The type of the command property, which must implement ICommand.
+ ///
+ /// The binding enables the control to execute the command when the specified event is raised,
+ /// and automatically manages the enabled state of the control based on the command's CanExecute state.
+ /// This method uses reflection to observe events and properties on the control, which may be
+ /// affected by trimming in some deployment scenarios.
+ ///
+ /// The type of the view that implements the IViewFor interface.
+ /// The type of the view model containing the command to bind.
+ /// The type of the command property on the view model. Must implement ICommand.
/// The type of the control on the view to which the command will be bound.
- /// The type of the parameter passed to the command when it is executed.
- /// The view instance to which the command will be bound. Cannot be null.
- /// The view model instance containing the command property. May be null if the view is not currently bound to a
- /// view model.
+ /// The type of the parameter passed to the command when the event is raised.
+ /// The view instance containing the control to which the command will be bound. Cannot be null.
+ /// The view model instance containing the command to bind. Used for type inference.
+ /// Can be null if the binding should be established without an initial view model.
/// An expression identifying the command property on the view model to bind. Cannot be null.
/// An expression identifying the control on the view to which the command will be bound. Cannot be null.
/// An observable that provides the parameter to pass to the command when it is executed. Cannot be null.
- /// The name of the event on the control that triggers the command. If null, a default event is used based on the
- /// control type.
+ /// The name of the event on the control that triggers the command execution. If null, a default event is used based
+ /// on the control type. If the specified event does not exist on the control, an exception may be thrown at runtime.
/// NOTE: If this parameter is used inside WhenActivated, it's important to dispose the binding when the view is deactivated.
- /// An IReactiveBinding instance representing the active binding between the command and the control.
+ /// An IReactiveBinding{TView, TProp} representing the established binding between the command and the control.
+ /// It will remain active until disposed.
[RequiresUnreferencedCode("Dynamic observation uses reflection over members that may be trimmed.")]
public static IReactiveBinding BindCommand<
TView,
@@ -79,25 +83,29 @@ public static IReactiveBinding BindCommand<
}
///
- /// Binds a command from the view model to a control on the view, enabling the control to execute the specified
- /// command when triggered.
+ /// Binds a command from the view model to a control on the view, enabling the control to execute the command with a
+ /// specified parameter when an event is raised.
///
- /// This method uses reflection to observe events and properties on the control and may be
- /// affected by trimming in environments that remove unused members. The binding enables the control to execute the
- /// command when the specified event is raised, and automatically manages the enabled state of the control based on
- /// the command's CanExecute state.
- /// The type of the view implementing the IViewFor interface.
- /// The type of the view model containing the command property.
- /// The type of the command property to bind, implementing ICommand.
+ ///
+ /// The binding enables the control to execute the command when the specified event is raised,
+ /// and automatically manages the enabled state of the control based on the command's CanExecute state.
+ /// This method uses reflection to observe events and properties on the control, which may be
+ /// affected by trimming in some deployment scenarios.
+ ///
+ /// The type of the view that implements the IViewFor interface.
+ /// The type of the view model containing the command to bind.
+ /// The type of the command property on the view model. Must implement ICommand.
/// The type of the control on the view to which the command will be bound.
- /// The view instance to which the control belongs. Cannot be null.
- /// The view model instance containing the command property. Can be null if the view's ViewModel property is used.
+ /// The view instance containing the control to which the command will be bound. Cannot be null.
+ /// The view model instance containing the command to bind. Used for type inference.
+ /// Can be null if the binding should be established without an initial view model.
/// An expression identifying the command property on the view model to bind. Cannot be null.
- /// An expression identifying the control on the view to bind the command to. Cannot be null.
- /// The name of the event on the control that triggers the command. If null, a default event is used based on the
- /// control type.
+ /// An expression identifying the control on the view to which the command will be bound. Cannot be null.
+ /// The name of the event on the control that triggers the command execution. If null, a default event is used based
+ /// on the control type. If the specified event does not exist on the control, an exception may be thrown at runtime.
/// NOTE: If this parameter is used inside WhenActivated, it's important to dispose the binding when the view is deactivated.
- /// An object representing the binding between the command and the control, which can be disposed to unbind.
+ /// An IReactiveBinding{TView, TProp} representing the established binding between the command and the control.
+ /// It will remain active until disposed.
[RequiresUnreferencedCode("Dynamic observation uses reflection over members that may be trimmed.")]
public static IReactiveBinding BindCommand<
TView,
@@ -123,26 +131,30 @@ public static IReactiveBinding BindCommand<
///
/// Binds a command from the view model to a control on the view, enabling the control to execute the command with a
- /// specified parameter when triggered.
+ /// specified parameter when an event is raised.
///
- /// This method uses reflection to observe events and properties on the control and view model,
- /// which may be affected by trimming in some deployment scenarios. The binding remains active until the returned
- /// IReactiveBinding is disposed.
- /// The type of the view implementing the IViewFor interface.
- /// The type of the view model containing the command property.
- /// The type of the command property, typically implementing ICommand.
+ ///
+ /// The binding enables the control to execute the command when the specified event is raised,
+ /// and automatically manages the enabled state of the control based on the command's CanExecute state.
+ /// This method uses reflection to observe events and properties on the control, which may be
+ /// affected by trimming in some deployment scenarios.
+ ///
+ /// The type of the view that implements the IViewFor interface.
+ /// The type of the view model containing the command to bind.
+ /// The type of the command property on the view model. Must implement ICommand.
/// The type of the control on the view to which the command will be bound.
- /// The type of the parameter passed to the command when it is executed.
- /// The view instance containing the control to bind the command to. Cannot be null.
- /// The view model instance containing the command property. May be null if the view is not currently bound to a
- /// view model.
+ /// The type of the parameter passed to the command when the event is raised.
+ /// The view instance containing the control to which the command will be bound. Cannot be null.
+ /// The view model instance containing the command to bind. Used for type inference.
+ /// Can be null if the binding should be established without an initial view model.
/// An expression identifying the command property on the view model to bind. Cannot be null.
/// An expression identifying the control on the view to which the command will be bound. Cannot be null.
/// An expression specifying the parameter to pass to the command when it is executed. Cannot be null.
/// The name of the event on the control that triggers the command execution. If null, a default event is used based
- /// on the control type.
+ /// on the control type. If the specified event does not exist on the control, an exception may be thrown at runtime.
/// NOTE: If this parameter is used inside WhenActivated, it's important to dispose the binding when the view is deactivated.
- /// An IReactiveBinding{TView, TProp} representing the established binding between the command and the control.
+ /// An IReactiveBinding{TView, TProp} representing the established binding between the command and the control.
+ /// It will remain active until disposed.
[RequiresUnreferencedCode("Dynamic observation uses reflection over members that may be trimmed.")]
public static IReactiveBinding BindCommand<
TView,
diff --git a/src/ReactiveUI/Bindings/Command/CommandBinderImplementation.cs b/src/ReactiveUI/Bindings/Command/CommandBinderImplementation.cs
index 5c973baadf..9b19cb5195 100644
--- a/src/ReactiveUI/Bindings/Command/CommandBinderImplementation.cs
+++ b/src/ReactiveUI/Bindings/Command/CommandBinderImplementation.cs
@@ -25,29 +25,7 @@ namespace ReactiveUI;
///
public class CommandBinderImplementation : ICommandBinderImplementation
{
- ///
- /// Binds a command from the view model to a control on the view, enabling the control to execute the command with
- /// an optional parameter when triggered by a specified event.
- ///
- /// This method uses reflection to observe properties and events, which may be affected by
- /// trimming in some deployment scenarios. The binding is one-way, from the view model command to the view control.
- /// If the specified event is not found on the control, an exception may be thrown at runtime.
- /// The type of the view implementing the IViewFor interface.
- /// The type of the view model containing the command property.
- /// The type of the command property to bind, implementing ICommand.
- /// The type of the control on the view to which the command will be bound.
- /// The type of the parameter passed to the command when it is executed.
- /// The view model instance containing the command to bind. Can be null if the binding should be established without
- /// an initial view model.
- /// The view instance containing the control to which the command will be bound. Cannot be null.
- /// An expression specifying the command property on the view model to bind. Cannot be null.
- /// An expression specifying the control on the view to which the command will be bound. Cannot be null.
- /// An expression specifying the parameter to pass to the command when it is executed. Can be null if the command
- /// does not require a parameter.
- /// The name of the event on the control that triggers the command execution. If null, a default event is used based
- /// on the control type.
- /// An IReactiveBinding{TView, TProp} representing the established command binding. Disposing the returned object
- /// will remove the binding.
+ ///
[RequiresUnreferencedCode("Dynamic observation uses reflection over members that may be trimmed.")]
public IReactiveBinding BindCommand<
TView,
@@ -68,17 +46,20 @@ public IReactiveBinding BindCommand<
{
ArgumentExceptionHelper.ThrowIfNull(vmProperty);
ArgumentExceptionHelper.ThrowIfNull(controlProperty);
+ ArgumentExceptionHelper.ThrowIfNull(withParameter);
var vmExpression = Reflection.Rewrite(vmProperty.Body);
var controlExpression = Reflection.Rewrite(controlProperty.Body);
+ var parameterExpression = Reflection.Rewrite(withParameter.Body);
var source = Reflection.ViewModelWhenAnyValue(viewModel, view, vmExpression).Cast();
+ var parameterObservable = Reflection.ViewModelWhenAnyValue(viewModel, view, parameterExpression).Cast();
var bindingDisposable = BindCommandInternal(
source,
view,
controlExpression,
- withParameter.ToObservable(viewModel),
+ parameterObservable,
toEvent);
return new ReactiveBinding(
@@ -90,31 +71,7 @@ public IReactiveBinding BindCommand<
bindingDisposable);
}
- ///
- /// Binds a command from the view model to a control on the view, enabling the control to execute the command with
- /// an optional parameter stream and event trigger.
- ///
- /// This method uses reflection to observe and bind to members, which may be affected by trimming
- /// in some environments. The binding is one-way, from the view model command to the view control. If the control or
- /// command property is not found, the binding will not be established. The method is suitable for scenarios where
- /// commands need to be dynamically bound to controls with support for parameter streams and custom event
- /// triggers.
- /// The type of the view implementing the IViewFor interface.
- /// The type of the view model containing the command property.
- /// The type of the command property, which must implement ICommand.
- /// The type of the control on the view to which the command will be bound.
- /// The type of the parameter passed to the command when it is executed.
- /// The view model instance containing the command to bind. Can be null if the view model is not available at
- /// binding time.
- /// The view instance containing the control to which the command will be bound.
- /// An expression specifying the command property on the view model to bind.
- /// An expression specifying the control on the view that will trigger the command.
- /// An observable sequence providing the parameter to pass to the command when it is executed. The latest value is
- /// used for each command invocation.
- /// The name of the event on the control that triggers the command. If null, a default event is used based on the
- /// control type.
- /// An IReactiveBinding{TView, TProp} representing the established binding between the command and the control.
- /// Disposing the binding will remove the command association.
+ ///
[RequiresUnreferencedCode("Dynamic observation uses reflection over members that may be trimmed.")]
public IReactiveBinding BindCommand<
TView,
@@ -197,7 +154,9 @@ private static IDisposable BindCommandInternal<
var isInitialBind = true;
// Check for optional platform-specific command rebinding customization
- var rebindingCustomizer = AppLocator.Current.GetService();
+ var rebindingCustomizer = string.IsNullOrEmpty(toEvent)
+ ? AppLocator.Current.GetService()
+ : null;
// Cache boxing of parameter values once to avoid rebuilding the Select pipeline on every rebind.
var boxedParameter = withParameter.Select(static p => (object?)p);
diff --git a/src/ReactiveUI/Bindings/Command/CommandBinderImplementationMixins.cs b/src/ReactiveUI/Bindings/Command/CommandBinderImplementationMixins.cs
index 73e95d7c53..23ece67f1c 100644
--- a/src/ReactiveUI/Bindings/Command/CommandBinderImplementationMixins.cs
+++ b/src/ReactiveUI/Bindings/Command/CommandBinderImplementationMixins.cs
@@ -13,26 +13,30 @@ namespace ReactiveUI;
internal static class CommandBinderImplementationMixins
{
///
- /// Binds an ICommand property on the view model to a control on the view, wiring the command to the specified event
- /// on the control.
+ /// Binds a command from the view model to a control on the view, enabling the control to execute the command with a
+ /// specified parameter when an event is raised.
///
- /// This method uses reflection to observe events and properties on the control and may not be
- /// compatible with all trimming scenarios. The binding will automatically enable or disable the control based on
- /// the command's CanExecute state.
- /// The type of the view, which must implement IViewFor.
- /// The type of the view model.
- /// The type of the ICommand property on the view model.
+ ///
+ /// The binding enables the control to execute the command when the specified event is raised,
+ /// and automatically manages the enabled state of the control based on the command's CanExecute state.
+ /// This method uses reflection to observe events and properties on the control, which may be
+ /// affected by trimming in some deployment scenarios.
+ ///
+ /// The type of the view that implements the IViewFor interface.
+ /// The type of the view model containing the command to bind.
+ /// The type of the command property on the view model. Must implement ICommand.
/// The type of the control on the view to which the command will be bound.
/// The command binder implementation used to perform the binding.
- /// The view model instance containing the ICommand property to bind. Can be null if the view is not currently
- /// associated with a view model.
- /// The view instance containing the control to which the command will be bound.
- /// An expression identifying the ICommand property on the view model to bind.
- /// An expression identifying the control on the view to which the command will be bound.
- /// The name of the event on the control that will trigger the command. If null, a default event is used based on
- /// the control type.
- /// An IReactiveBinding{TView, TProp} representing the established binding between the command and the control
- /// event.
+ /// The view model instance containing the command to bind. Used for type inference.
+ /// Can be null if the binding should be established without an initial view model.
+ /// The view instance containing the control to which the command will be bound. Cannot be null.
+ /// An expression identifying the command property on the view model to bind. Cannot be null.
+ /// An expression identifying the control on the view to which the command will be bound. Cannot be null.
+ /// The name of the event on the control that triggers the command execution. If null, a default event is used based
+ /// on the control type. If the specified event does not exist on the control, an exception may be thrown at runtime.
+ /// NOTE: If this parameter is used inside WhenActivated, it's important to dispose the binding when the view is deactivated.
+ /// An IReactiveBinding{TView, TProp} representing the established binding between the command and the control.
+ /// It will remain active until disposed.
[RequiresUnreferencedCode("Dynamic observation uses reflection over members that may be trimmed.")]
public static IReactiveBinding BindCommand(
this ICommandBinderImplementation @this,
@@ -46,49 +50,4 @@ internal static class CommandBinderImplementationMixins
where TProp : ICommand
where TControl : class =>
@this.BindCommand(viewModel, view, propertyName, controlName, Observable