MvvmCross UITextField 自定义绑定 [英] MvvmCross UITextField custom binding

查看:29
本文介绍了MvvmCross UITextField 自定义绑定的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

所以我试图在 MvvmCross 中为 UITextField 实现自定义绑定,几乎与 在软件键盘上绑定GO"键 - 即尝试绑定文本字段以在键盘上点击完成按钮时自动触发事件(因此绑定到 ShouldReturn).我还需要绑定文本字段的 EditingDidBeginEditingDidEnd 事件.因为我绑定了多个事件,所以我创建了一个 MvxPropertyInfoTargetBinding 如下:

So I am trying to implement a custom binding for a UITextField in MvvmCross, pretty much along the lines of Binding 'GO' key on Software Keyboard - i.e. trying to bind a text field to automatically fire an event when the Done button is tapped on the keyboard (so binding to ShouldReturn). I also need to bind the text field's EditingDidBegin and EditingDidEnd events. Because I am binding more than one event, I have created a MvxPropertyInfoTargetBinding as follows:

public class MyTextFieldTargetBinding : MvxPropertyInfoTargetBinding<UITextField>
{
    private ICommand _command;

    protected UITextField TextField
    {
        get { return (UITextField)Target; }
    }

    public MyTextFieldTargetBinding(object target, PropertyInfo targetPropertyInfo) : base(target, targetPropertyInfo)
    {
        TextField.ShouldReturn += HandleShouldReturn;
        TextField.EditingDidBegin += HandleEditingDidBegin;
        TextField.EditingDidEnd += HandleEditingDidEnd;
    }

    private bool HandleShouldReturn(UITextField textField)
    {
        if (_command == null) {
            return false;
        }

        var text = textField.Text;
        if (!_command.CanExecute (text)) {
            return false;
        }

        textField.ResignFirstResponder();
        _command.Execute(text);

        return true;
    }

    private void HandleEditingDidBegin (object sender, EventArgs e)
    {
        // do something
    }

    private void HandleEditingDidEnd (object sender, EventArgs e)
    {
        // do something
    }

    public override MvxBindingMode DefaultMode
    {
        get { return MvxBindingMode.OneWay; }
    }

    public override void SetValue(object value)
    {
        var command = value as ICommand;
        _command = command;
    }

    public override Type TargetType
    {
        get { return typeof(ICommand); }
    }

    protected override void Dispose(bool isDisposing)
    {
        if (isDisposing)
        {
            if (TextField != null)
            {
                TextField.ShouldReturn -= HandleShouldReturn;
                TextField.EditingDidBegin -= HandleEditingDidBegin;
                TextField.EditingDidEnd -= HandleEditingDidEnd;
            }
        }

        base.Dispose(isDisposing);
    }

}

我的第一个问题是:我为所有事件创建一个 MvxPropertyInfoTargetBinding 是否正确?相关地,我不明白 MvxPropertyInfoTargetBindingMvxTargetBinding 之间的区别.根据 MVVMCross Binding decimal to UITextField 删除小数点 前者在替换现有绑定时使用,后者用于已知属性和事件对.那么我使用的是正确的吗?

My first question is: am I correct in creating one MvxPropertyInfoTargetBinding for all the events? Relatedly, I don't get the difference between MvxPropertyInfoTargetBinding and MvxTargetBinding. According to MVVMCross Binding decimal to UITextField removes decimal point the former is used when replacing an existing binding, the latter for known properties and event pairs. So am I using the correct one?

其次(也是我问题的真正症结),我的代码有效除了 SetValue - 它被触发,但 value 是<代码>空.这是我的 Setup 文件中的内容:

Secondly (and the real crux of my problem), my code works except for SetValue - it is fired, but the value is null. Here is what I have in my Setup file:

protected override void FillTargetFactories (IMvxTargetBindingFactoryRegistry registry)
{
    base.FillTargetFactories (registry);
    registry.RegisterPropertyInfoBindingFactory(typeof(MyTextFieldTargetBinding), typeof(UITextField), "Text");
}

我在 View 中没有做任何事情 - 也许这就是问题所在?

I don't do anything in my View - perhaps that is where the issue lies?

我的ViewModel:

public class LoginViewModel : MvxViewModel
{
    private string _username;
    public string Username
    { 
        get { return _username; }
        set { _username = value; RaisePropertyChanged(() => Username); }
    }

    private string _password;
    public string Password
    { 
        get { return _password; }
        set { _password = value; RaisePropertyChanged(() => Password); }
    }

    private MvxCommand _login;
    public ICommand Login
    {
        get {
            _login = _login ?? new MvxCommand(DoLogin);
            return _login;
        }
    }

    public LoginViewModel(ILoginManager loginManager)
    {
        _loginManager = loginManager;
    }

    private void DoLogin()
    {
        // call the login web service
    }
}

在我的视图"中,我没有做任何花哨的事情(我确实在 XIB 中创建了视图元素):

In my `View', I don't do anything fancy (I do create the View elements in a XIB):

public override void ViewDidLoad()
{
    base.ViewDidLoad ();

    this.NavigationController.SetNavigationBarHidden(true, false);

    var set = this.CreateBindingSet<LoginView, Core.ViewModels.LoginViewModel>();
    set.Bind(usernameTextField).To(vm => vm.Username);
    set.Bind(passwordTextField).To(vm => vm.Password);
    set.Bind (loginButton).To (vm => vm.Login);
    set.Apply();
}

没有有趣的 Trace 消息.

No interesting Trace messages.

推荐答案

1.PropertyInfoTargetBinding 有什么特别之处?

您参考的问题 - MVVMCross Binding decimal to UITextField 删除小数点 - 给出了 MvxTargetBindingMvxPropertyInfoTargetBinding 之间区别的关键:

1. What is special about PropertyInfoTargetBinding?

The question you reference - MVVMCross Binding decimal to UITextField removes decimal point - gives the key to the difference between MvxTargetBinding and MvxPropertyInfoTargetBinding:

  • TargetBinding 可用于任何任意绑定 - 例如对于一个非基于propertyInfo的绑定
  • PropertyInfoTargetBinding 继承自 TargetBinding,只能与实际的 C# 属性一起使用 - 因为它通过反射使用 PropertyInfo.

在您的情况下,由于您实际上并未通过反射使用 Text 属性,那么我很想使用 PropertyInfoTargetBinding 并避开Text 名称 - 而只是编写自定义 TargetBinding.

In your case, since you aren't actually using the Text property via Reflection, then I'd be tempted not to use a PropertyInfoTargetBinding and to steer clear of the Text name as well - instead just write a custom TargetBinding.

前者用于替换现有绑定

这绝对不是真的 - 相反,任何绑定都可以用来替换另一个绑定 - 正如另一个问题的答案所说

This is definitely not true - instead any binding can be used to replace another binding - as the answer on the other question says

MvvmCross 操作一个简单的最后注册的胜利"系统

MvvmCross operates a simple 'last registered wins' system

有关自定义绑定的更多信息,请查看:

For more on custom bindings, take a look at:

  • http://mvvmcross.blogspot.co.uk/ 中的 N=28 视频
  • 查看一些标准"MvvmCross 附带的绑定
    • the N=28 video in http://mvvmcross.blogspot.co.uk/
    • take a look through some of the "standard" bindings that ship with MvvmCross
      • Droid - https://github.com/MvvmCross/MvvmCross/tree/v3.1/Cirrious/Cirrious.MvvmCross.Binding.Droid/Target
      • iOS - https://github.com/MvvmCross/MvvmCross/tree/v3.1/Cirrious/Cirrious.MvvmCross.Binding.Touch/Target
      • note that most of these use either MvxPropertyInfoTargetBinding or MvxConvertingTargetBinding as a base class

      您当前的绑定代码要求 ICommand:

      Your current binding code is asking for an ICommand:

      public override Type TargetType
      {
          get { return typeof(ICommand); }
      }
      

      但是您的 View 代码当前正在将 View 绑定到 string:

      But your View code is currently binding the View to a string:

      // View
      set.Bind(usernameTextField).To(vm => vm.Username);
      
      // ViewModel
      private string _username;
      public string Username
      { 
          get { return _username; }
          set { _username = value; RaisePropertyChanged(() => Username); }
      }
      

      为了解决这个问题...

      To solve this...

      1. 确定您想要绑定到的内容 - 它是 ICommand(例如和 MvxCommand)还是 string?
      2. 更改视图和绑定以反映这一点.

      这篇关于MvvmCross UITextField 自定义绑定的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆