MvvmCross Monotouch C#-绑定Int属性-模式:双向

MvvmCross Monotouch C#-绑定Int属性-模式:双向,mvvm,xamarin.ios,mvvmcross,Mvvm,Xamarin.ios,Mvvmcross,我是MvvmCross的新手,我有一个问题 我注意到以下绑定代码仅以一种方式工作: { this, "{'CurrentIndex':{'Path':'CurrentIndex','Mode':'TwoWay'}}" } CurrentIndex是视图中的一个Int属性 CurrentIndex也是ViewModel中的一个Int属性 这条路行得通 ViewModel=>View 但不是这样 视图=>ViewModel 我有一个ViewController集合,我的目标是为view

我是MvvmCross的新手,我有一个问题

我注意到以下绑定代码仅以一种方式工作:

{ this, "{'CurrentIndex':{'Path':'CurrentIndex','Mode':'TwoWay'}}" }
  • CurrentIndex是视图中的一个Int属性
  • CurrentIndex也是ViewModel中的一个Int属性
这条路行得通

  • ViewModel=>View
但不是这样

  • 视图=>ViewModel
我有一个ViewController集合,我的目标是为viewModel中的CurrentIndex调用DeleteCommand

但是,

“Android和Touch双向绑定不完整”

参考:

我猜双向模式只适用于控件(UILabel、UITextfield等),而不适用于属性

那么,有没有一个好方法可以让它在两方面都起作用呢?或者有什么办法可以解决我的问题


Patrick

为了让绑定在视图和ViewModel之间传输任何值,那么当值发生变化时,它需要挂接到某个事件中

在ViewModel中,此事件始终是INotifyProperty界面中的事件

在视图/活动中,使用了一种模式,因此每个绑定都必须挂接到一个单独的事件中。例如,EditText上的文本使用TextChanged事件连接(请参阅),而SeekBar中的值使用侦听器对象而不是事件连接(请参阅)

因此,如果您想为您的活动实现这种双向绑定,那么您可以通过以下方式实现:

  • 在活动(MyActivity)中声明一个事件-CurrentIndexChanged,该事件在CurrentIndex更改时触发
  • 为MyActivity声明自定义绑定,该绑定以编程方式链接CurrentIndex和CurrentIndexChanged
  • 在安装过程中将自定义绑定添加到绑定注册表
例如,您的活动可能包括:

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;
        }
    }
}

然而。。。在实际层面上,如果您是在C#而不是在XML中操作,那么在本例中最好使用C#来简单地更新ViewModel,而不是在本例中使用声明性绑定

说清楚。。。在这种情况下,我很可能只将Activity属性写为:

public int CurrentIndex
{ 
   get { return _currentIndex; } 
   set { _currentIndex = value; ViewModel.CurrentIndex = value; } 
}
或者。。。我认为在活动中没有这个属性。


如果有帮助的话,下面是有关自定义绑定的更多信息:


希望这有帮助!当您使用XML时,有哪些绑定可以帮助您-您不必使用它们

斯图尔特


更新如果要执行很多操作并遵循相同的名称模式-使用名为X的属性和名为XChanged的已更改EventHandler事件,则类似的操作可能会起作用-它使用反射自动查找事件:

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) });
        }
    }
}
公共类MyBinding:MvxPropertyInfoTargetBinding
T:在哪里上课
{
私有只读属性yinfo_PropertyInfo;
私有只读事件信息\u事件信息;
公共MyBinding(对象目标,PropertyInfo目标PropertyInfo)
:base(目标、targetPropertyInfo)
{
_propertyInfo=目标propertyInfo;
var eventName=_propertyInfo.Name+“已更改”;
_eventInfo=View.GetType().GetEvent(eventName);
如果(_eventInfo==null)
{
抛出新的MvxException(“事件丢失”+eventName);
}
if(_eventInfo.EventHandlerType!=typeof(EventHandler))
{
抛出新的MvxException(“事件类型与“+eventName”不匹配);
}
var addMethod=_eventInfo.GetAddMethod();
Invoke(视图,新对象[]{neweventhandler(OnChanged)});
}
公共覆盖MvxBindingMode默认模式
{
得到
{
返回MvxBindingMode.TwoWay;
}
}
私有void一旦更改(对象发送方,事件参数被忽略)
{
var value=_propertyInfo.GetValue(视图,null);
FireValueChanged(值);
}
受保护的覆盖无效处置(bool isDisposing)
{
基础处理(isDisposing);
if(isDisposing)
{
var removeMethod=_eventInfo.GetRemoveMethod();
调用(视图,新对象[]{neweventhandler(OnChanged)});
}
}
}

@Stuart,在上面的示例中,CurrentIndex是int类型,MyBinding要求T是引用类型。如何使用更新的答案?@Stuart,registry.RegisterFactory(新的MvxSimplePropertyInfoTargetBindingFactory(typeof(MyBinding),typeof(MyActivity),“CurrentIndex”);MyBinding中的错误
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) });
        }
    }
}