我是MvvmCross的新手,我有一个问题。
我注意到以下绑定代码仅以一种方式工作:
{ this, "{'CurrentIndex':{'Path':'CurrentIndex','Mode':'TwoWay'}}" }
这种方式有效!
但不是这样!
我有一组ViewControllers,我的目标是为viewModel中的CurrentIndex调用DeleteCommand。
然而,
“Android和Touch 2路绑定不完整”
参考:MvvmCross experiences, hindsight, limitations?
我的猜测是TwoWay模式仅适用于Controls(UILabel,UITextfield,...),但不适用于属性。
那么,有没有一种方法可以让它以两种方式运作?或者我的问题还有其他选择吗?
帕特里克
答案 0 :(得分:4)
为了使绑定在View之间传递任何值到ViewModel,它需要在值改变时挂钩到某个事件。
在ViewModel中,此事件始终是INotifyProperty界面中的事件。
在View / Activity中,使用了一个单一模式 - 因此每个绑定都必须挂钩到一个单独的事件中。例如,EditText上的Text使用TextChanged事件(请参阅MvxEditTextTextTargetBinding.cs)连接,而SeekBar中的值使用Listener对象而不是事件(请参阅MvxSeekBarProgressTargetBinging.cs)连接。
因此,如果您想为您的活动实现此双向绑定,那么您可以通过以下方式执行此操作:
例如,您的活动可能包括:
public event EventHandler CurrentIndexChanged;
private int _currentIndex;
public int CurrentIndex
{
get { return _currentIndex; }
set { _currentIndex = value; if (CurrentIndexChanged != null) CurrentIndexChanged(this, EventArgs.Empty); }
}
然后你可以声明一个绑定类,如:
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;
}
}
}
您需要在设置中告诉绑定系统有关此绑定的信息,如:
registry.RegisterFactory(new MvxSimplePropertyInfoTargetBindingFactory(typeof(MyBinding), typeof(MyActivity), "CurrentIndex"));
但是......在实际层面上,如果你使用的是C#而不是XML,那么在这种情况下你可能会更好,使用C#来简单地更新ViewModel而不是在这种情况下使用声明性绑定。
要清楚......在这种情况下,我很可能只将Activity属性写为:
public int CurrentIndex
{
get { return _currentIndex; }
set { _currentIndex = value; ViewModel.CurrentIndex = value; }
}
或者......我认为在Activity中根本没有这个属性。
如果有帮助,可以在以下网站上找到有关自定义绑定的更多信息:
希望这有帮助!恕我直言,当您使用XML工作时,绑定可以帮助您 - 您不必使用它们......
斯图尔特
更新如果您打算执行大量这些操作并遵循相同的名称模式 - 使用名为 X 的属性更改名为 XChanged 那么像这样的东西可能会起作用 - 它使用反射来自动找到事件:
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) });
}
}
}