3

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

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

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

这种方法有效!

  • 视图模型 => 视图

但不是这样!

  • 视图 => 视图模型

我有一组 ViewController,我的目标是为 viewModel 中的 CurrentIndex 调用 DeleteCommand。

然而,

“Android 和 Touch 2 方式绑定不完整”

参考:MvvmCross 经验、事后诸葛亮、局限性?

我的猜测是 TwoWay 模式仅适用于控件(UILabel,UITextfield,...),但不适用于属性。

那么,有没有一种好方法可以让它在这两种方式下都起作用?或者我的问题有其他选择吗?

帕特里克

4

1 回答 1

4

为了让绑定在 View 和 ViewModel 之间传输任何值,它需要在值更改时挂钩到某个事件。

在 ViewModel 中,此事件始终是 INotifyProperty 接口中的事件。

在视图/活动中,使用了一个单一的模式——因此每个绑定都必须挂钩到一个单独的事件中。例如,EditText 上的 Text 使用 TextChanged 事件(参见MvxEditTextTextTextTargetBinding.cs)连接,而 SeekBar 中的值使用 Listener 对象而不是事件连接(参见MvxSeekBarProgressTargetBinging.cs)。

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

  • 在您的活动 (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;
        }
    }
}

您需要在设置中告诉绑定系统有关此绑定的信息,例如:

       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的​​已更改 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) });
        }
    }
}
于 2012-06-27T18:00:37.367 回答