MvvmCross Monotouch C# - 绑定 Int 属性 - 模式:双向 [英] MvvmCross Monotouch C# - Binding Int Property - Mode: TwoWay
问题描述
我是 MvvmCross 的新手,我有一个问题.
I am new to MvvmCross and I have a question.
我注意到以下绑定代码仅以一种方式起作用:
I noticed that the following binding code works in one way only:
{ this, "{'CurrentIndex':{'Path':'CurrentIndex','Mode':'TwoWay'}}" }
- CurrentIndex 是视图中的一个 Int 属性
- CurrentIndex 也是 ViewModel 中的一个 Int 属性
- ViewModel => 视图
- 视图 => 视图模型
- 在您的活动 (MyActivity) 中声明一个事件 - CurrentIndexChanged,该事件在 CurrentIndex 更改时触发
- 为您的 MyActivity 声明一个自定义绑定,它以编程方式链接 CurrentIndex 和 CurrentIndexChanged
- 在安装过程中将自定义绑定添加到绑定注册表
这个方法行得通!
但不是这样!
我有一组 ViewController,我的目标是为 viewModel 中的 CurrentIndex 调用 DeleteCommand.
I have a collection of ViewControllers and my goal was to call a DeleteCommand for the CurrentIndex in the viewModel.
然而,
Android 和 Touch 2 方式绑定不完整"
"Android and Touch 2 way bindings are incomplete"
我的猜测是 TwoWay 模式仅适用于控件(UILabel、UITextfield 等)而不适用于属性.
My guess is the TwoWay mode only works for Controls (UILabel, UITextfield, ...) but not for Properties.
那么,有没有什么好办法让它在两种情况下都能正常工作?或者我的问题有什么替代方法吗?
So, is there a good way to make it works in both ways? Or Are there any alternatives to my problem?
帕特里克
推荐答案
为了让绑定在 View 和 ViewModel 之间传输任何值,当值发生变化时,它需要挂钩到某个事件.
In order for a binding to transfer any value between a View to a ViewModel, then it needs to hook into some event when the value changes.
在 ViewModel 中,此事件始终是 INotifyProperty 接口中的事件.
In the ViewModel, this event is always the event in the INotifyProperty interface.
在视图/活动中,使用了一种单一模式 - 因此每个绑定都必须挂钩到一个单独的事件中.例如,使用 TextChanged 事件连接 EditText 上的文本(参见 MvxEditTextTextTargetBinding.cs),而 SeekBar 中的值是使用 Listener 对象而不是事件连接的(请参阅 MvxSeekBarProgressTargetBinging.cs).
In the View/Activity, there is one single pattern employed - so each binding has to hook into a separate event. For example, the Text on EditText is hooked up using the TextChanged event (see MvxEditTextTextTargetBinding.cs) while the value in a SeekBar is hooked up using a Listener object rather than an event (see MvxSeekBarProgressTargetBinging.cs).
因此,如果您想为您的 Activity 实现这种双向绑定,那么您可以通过以下方式实现:
So if you wanted to implement this two-way binding for your activity, then you could do this by:
例如,您的活动可能包括:
For example, your activity might include:
public event EventHandler CurrentIndexChanged;
private int _currentIndex;
public int CurrentIndex
{
get { return _currentIndex; }
set { _currentIndex = value; if (CurrentIndexChanged != null) CurrentIndexChanged(this, EventArgs.Empty); }
}
然后你可以声明一个绑定类,如:
And you might then declare a binding class like:
public class MyBinding : MvxPropertyInfoTargetBinding<MyActivity>
{
public MyBinding (object target, PropertyInfo targetPropertyInfo)
: base(target, targetPropertyInfo)
{
View.CurrentIndexChanged += OnCurrentIndexChanged;
}
public override MvxBindingMode DefaultMode
{
get
{
return MvxBindingMode.TwoWay;
}
}
private void OnCurrentIndexChanged(object sender, EventArgs ignored)
{
FireValueChanged(View.CurrentIndex);
}
protected override void Dispose(bool isDisposing)
{
base.Dispose(isDisposing);
if (isDisposing)
{
View.CurrentIndexChanged -= OnCurrentIndexChanged;
}
}
}
并且您需要在设置中告诉绑定系统有关此绑定的信息,例如:
And you'd need to tell the binding system about this binding in setup like:
registry.RegisterFactory(new MvxSimplePropertyInfoTargetBindingFactory(typeof(MyBinding), typeof(MyActivity), "CurrentIndex"));
<小时>
但是……在实际层面上,如果您使用 C# 而不是 XML,那么在这种情况下,您最好使用 C# 来简单地更新 ViewModel,而不是在这种情况下使用声明式绑定.
However... at a practical level, if you are operating in C# rather than in XML, then you might be better off in this case using C# to simply update the ViewModel rather than using declarative binding in this case.
要清楚...在这种情况下,我很可能只是将 Activity 属性写为:
To be clear... in this case, I would most probably just write the Activity property as:
public int CurrentIndex
{
get { return _currentIndex; }
set { _currentIndex = value; ViewModel.CurrentIndex = value; }
}
或者...我会考虑在 Activity 中根本没有这个属性.
Or... I'd consider not having this property in the Activity at all.
如果有帮助,这里有一些关于自定义绑定的更多信息:
If it helps, there's some more information on custom bindings in:
希望这有帮助!恕我直言,绑定可以在您使用 XML 时为您提供帮助 - 您不必使用它们...
Hope this helps! IMHO the bindings are there to help you when you're working in XML - you don't have to use them...
斯图尔特
UPDATE 如果您要执行大量这些操作并遵循相同的名称模式 - 使用名为 X 的属性和名为 XChanged 的已更改 EventHandler 事件> 那么这样的事情可能会奏效——它使用反射来自动查找事件:
UPDATE If you are going to do lots of these and follow the same name pattern - using property named X with changed EventHandler event named XChanged then something like this might work - it uses reflection to find the event automagically:
public class MyBinding<T> : MvxPropertyInfoTargetBinding<T>
where T : class
{
private readonly PropertyInfo _propertyInfo;
private readonly EventInfo _eventInfo;
public MyBinding(object target, PropertyInfo targetPropertyInfo)
: base(target, targetPropertyInfo)
{
_propertyInfo = targetPropertyInfo;
var eventName = _propertyInfo.Name + "Changed";
_eventInfo = View.GetType().GetEvent(eventName);
if (_eventInfo == null)
{
throw new MvxException("Event missing " + eventName);
}
if (_eventInfo.EventHandlerType != typeof(EventHandler))
{
throw new MvxException("Event type mismatch for " + eventName);
}
var addMethod = _eventInfo.GetAddMethod();
addMethod.Invoke(View, new object[] { new EventHandler(OnChanged) });
}
public override MvxBindingMode DefaultMode
{
get
{
return MvxBindingMode.TwoWay;
}
}
private void OnChanged(object sender, EventArgs ignored)
{
var value = _propertyInfo.GetValue(View, null);
FireValueChanged(value);
}
protected override void Dispose(bool isDisposing)
{
base.Dispose(isDisposing);
if (isDisposing)
{
var removeMethod = _eventInfo.GetRemoveMethod();
removeMethod.Invoke(View, new object[] { new EventHandler(OnChanged) });
}
}
}
这篇关于MvvmCross Monotouch C# - 绑定 Int 属性 - 模式:双向的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!