首页 > 解决方案 > 带有 XF 的 ReactiveUI:如何为自定义控件创建命令绑定器?

问题描述

我正在使用Xamarin FormsReactiveUI并尝试将自定义命令从自定义 XF 控件绑定到我的视图模型。

this.BindCommand(ViewModel, vm => vm.HasChangesCommand, view => view.socket1);

我的控制 socket1 有一个 ICommand 类型的依赖属性命令。但是,我收到了错误:

“System.Exception:找不到 [ControlName] 的命令绑定器”

我想我必须为我的控件创建一个命令绑定器,但我找不到任何关于如何执行此操作的提示。是否有关于如何为Xamarin Forms
上的自定义控件创建命令活页夹的文档?

编辑:我已经看到添加第三个参数“eventName”它正在工作。但是我想知道是否有任何方法可以构建该命令绑定器,因此您无需在该调用中指定事件。

标签: xamarin.formsreactiveui

解决方案


如果您希望能够BindCommand与自定义视图一起使用,最简单的方法是在ICommand名为 的视图上拥有类型属性CommandOneWayBind按照Daniel 的建议执行 a也很容易,尽管当您习惯使用BindCommandfor 命令绑定时也很容易忘记这样做。

如果您想使用其他任何东西(事件、手势识别器等),您可以创建一个ICreatesCommandBinding定义命令如何连接到目标对象的实现。因此,您可以执行以下操作:

public class SocketControl : ContentView
{
    public static readonly BindableProperty MyCustomCommandProperty = BindableProperty.Create(
        nameof(MyCustomCommand),
        typeof(ICommand),
        typeof(SocketControl));

    public ICommand MyCustomCommand
    {
        get => (ICommand)GetValue(MyCustomCommandProperty);
        set => SetValue(MyCustomCommandProperty, value);
    }

    //...
}

public sealed class SocketControlCommandBinder : ICreatesCommandBinding
{
    public IDisposable BindCommandToObject(ICommand command, object target, IObservable<object> commandParameter)
    {
        var socket = (SocketControl)target;

        // get the original value so we can restore it when the binding is disposed...
        var originalValue = socket.GetValue(SocketControl.MyCustomCommandProperty);
        var disposable = Disposable.Create(() => socket.SetValue(SocketControl.MyCustomCommandProperty, originalValue));

        // set the control's command to the view-model's command
        socket.SetValue(SocketControl.MyCustomCommandProperty, command);

        return disposable;
    }

    public IDisposable BindCommandToObject<TEventArgs>(ICommand command, object target, IObservable<object> commandParameter, string eventName)
    {
        /// not shown here ...
        return Disposable.Empty;
    }

    /// <summary>
    /// Returns a positive integer when this class supports BindCommandToObject for this
    /// particular Type. If the method isn't supported at all, return a non-positive integer.
    /// When multiple implementations return a positive value, the host will use the one which
    /// returns the highest value. When in doubt, return '2' or '0'
    /// </summary>
    /// <param name="type">The type to query for.</param>
    /// <param name="hasEventTarget">If true, the host intends to use a custom event target.</param>
    /// <returns>A positive integer if BCTO is supported, zero or a negative value otherwise</returns>
    public int GetAffinityForObject(Type type, bool hasEventTarget)
    {
        return type.GetTypeInfo().IsAssignableFrom(typeof(SocketControl).GetTypeInfo()) ? 2 : 0;
    }
}

一旦你创建了命令绑定器,你需要注册它以便 ReactiveUI 知道如何使用它。在您的 app.xaml.cs(或您创建应用程序的任何位置)中:

Splat.Locator.CurrentMutable.Register(
    () => new SocketControlCommandBinder(),
    typeof(ReactiveUI.ICreatesCommandBinding));

推荐阅读