更新时间:2023-10-06 23:24:34
为了使绑定在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上的Text(请参见 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).
因此,如果您想为您的活动实现这种双向绑定,则可以通过以下方式实现:
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...
斯图尔特
更新如果要执行许多操作并遵循相同的名称模式,请使用名为 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) });
}
}
}