ferroui_reactiveui/binding/interfaces/i_creates_command_binding.rs
1//! `ICreatesCommandBinding` (ReactiveUI.Binding, `Interfaces/ICreatesCommandBinding.cs`).
2
3use crate::reactive_command::ICommand;
4use ferroui_system::{IDisposable, IObservable};
5use std::any::{Any, TypeId};
6use std::rc::Rc;
7
8/// A command parameter (`object?`): the value the command is executed with, of any type, or none.
9/// A command receives it as `Option<&dyn Any>` (`parameter.as_deref()`).
10pub type CommandParameter = Option<Rc<dyn Any>>;
11
12/// Adds a handler to an event of a control and returns the disposable that removes it: the
13/// counterpart of the pair `addHandler` / `removeHandler` of `Action<EventHandler<TEventArgs>>`.
14pub type CommandEventSubscription = Rc<dyn Fn(Rc<dyn Fn()>) -> Rc<dyn IDisposable>>;
15
16/// A plugin that binds an [`ICommand`] to a control (`ICreatesCommandBinding`). The
17/// implementations are registered in the service locator (Splat) as `dyn ICreatesCommandBinding`,
18/// and the one with the highest affinity for the type of a control binds it
19/// ([`CommandBinderService`](crate::CommandBinderService)), as upstream.
20///
21/// The crate registers none: [`CreatesCommandBindingViaEvent`](crate::CreatesCommandBindingViaEvent)
22/// and [`CreatesCommandBindingViaCommandParameter`](crate::CreatesCommandBindingViaCommandParameter)
23/// bind the controls of one type, and a platform registers its own (the controls of FerroUI).
24///
25/// Deviation (DEVIATIONS.md, ReactiveUI): the trait is object safe. The type parameter `T` of the
26/// control is a `TypeId` in [`get_affinity_for_object`](Self::get_affinity_for_object) and the
27/// control an `Rc<dyn Any>` in the bindings; `TEventArgs` has no counterpart (the handler ignores
28/// the arguments of the event); the add and remove handlers are one
29/// [`CommandEventSubscription`]; the command parameter is an observable of [`CommandParameter`].
30pub trait ICreatesCommandBinding {
31 /// A positive number when this plugin can bind a command to an object of the type
32 /// `target_type`, the highest number winning among the plugins; zero or less when it cannot
33 /// (`GetAffinityForObject<T>(bool hasEventTarget)`). `has_event_target` says whether the caller
34 /// names the event to bind to.
35 fn get_affinity_for_object(&self, target_type: TypeId, has_event_target: bool) -> i32;
36
37 /// Binds `command` to `target` through the default event of the target (`Click`, ...), executed
38 /// with the latest value of `command_parameter`; `None` when no binding was made, as for a
39 /// missing command (`BindCommandToObject<T>`). Disposing the result unbinds the command.
40 fn bind_command_to_object(
41 &self,
42 command: Option<Rc<dyn ICommand>>,
43 target: Option<Rc<dyn Any>>,
44 command_parameter: Rc<dyn IObservable<CommandParameter>>,
45 ) -> Option<Rc<dyn IDisposable>>;
46
47 /// Binds `command` to the event named `event_name` of `target`
48 /// (`BindCommandToObject<T, TEventArgs>(..., string eventName)`).
49 fn bind_command_to_object_event(
50 &self,
51 command: Option<Rc<dyn ICommand>>,
52 target: Option<Rc<dyn Any>>,
53 command_parameter: Rc<dyn IObservable<CommandParameter>>,
54 event_name: &str,
55 ) -> Option<Rc<dyn IDisposable>>;
56
57 /// Binds `command` to the event that `subscription` adds a handler to
58 /// (`BindCommandToObject<T, TEventArgs>(..., addHandler, removeHandler)`).
59 fn bind_command_to_object_with_handlers(
60 &self,
61 command: Option<Rc<dyn ICommand>>,
62 target: Option<Rc<dyn Any>>,
63 command_parameter: Rc<dyn IObservable<CommandParameter>>,
64 subscription: CommandEventSubscription,
65 ) -> Option<Rc<dyn IDisposable>>;
66}