MvvmCross UITextField 自定义绑定 [英] MvvmCross UITextField custom binding
问题描述
所以我试图在 MvvmCross 中为 UITextField 实现自定义绑定,几乎与 在软件键盘上绑定GO"键 - 即尝试绑定文本字段以在键盘上点击完成按钮时自动触发事件(因此绑定到 ShouldReturn
).我还需要绑定文本字段的 EditingDidBegin
和 EditingDidEnd
事件.因为我绑定了多个事件,所以我创建了一个 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
是否正确?相关地,我不明白 MvxPropertyInfoTargetBinding
和 MvxTargetBinding
之间的区别.根据 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 删除小数点 - 给出了 MvxTargetBinding
和 MvxPropertyInfoTargetBinding
之间区别的关键:
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 附带的绑定
- 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
- 请注意,其中大多数使用 MvxPropertyInfoTargetBinding 或 MvxConvertingTargetBinding 作为基类
- 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...
- 确定您想要绑定到的内容 - 它是 ICommand(例如和 MvxCommand)还是
string
? - 更改视图和绑定以反映这一点.
这篇关于MvvmCross UITextField 自定义绑定的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!