【问题标题】:MvvmCross Monotouch C# - Binding Int Property - Mode: TwoWayMvvmCross Monotouch C# - 绑定 Int 属性 - 模式:TwoWay
【发布时间】:2012-06-27 17:12:00
【问题描述】:

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

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

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

这种方法行得通!

  • ViewModel => 视图

但不是这样!

  • 视图 => 视图模型

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

然而,

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

参考:MvvmCross experiences, hindsight, limitations?

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

那么,有没有一种好方法可以让它同时发挥作用呢?或者我的问题有什么替代方案吗?

帕特里克

【问题讨论】:

    标签: mvvm xamarin.ios mvvmcross


    【解决方案1】:

    为了让绑定在 View 和 ViewModel 之间传递任何值,当值发生变化时,它需要挂钩到某个事件。

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

    在视图/活动中,使用了一个单一的模式 - 因此每个绑定都必须挂钩到一个单独的事件中。例如,EditText 上的 Text 使用 TextChanged 事件(参见 MvxEditTextTextTargetBinding.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) });
            }
        }
    }
    

    【讨论】:

    • @Stuart,在上面的例子中,CurrentIndex 是 int 类型,而 MyBinding 要求 T 是引用类型。如何使用您更新的答案?
    • @Stuart, registry.RegisterFactory(new MvxSimplePropertyInfoTargetBindingFactory(typeof(MyBinding), typeof(MyActivity), "CurrentIndex")); MyBinding 中的错误
    猜你喜欢
    • 2016-10-26
    • 2015-03-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-10-15
    • 2012-06-11
    • 2011-08-10
    • 1970-01-01
    相关资源
    最近更新 更多