2012-06-27 40 views
3

我是MvvmCross的新手,我有一個問題。MvvmCross Monotouch C# - 綁定Int屬性 - 模式:雙向

我注意到以下綁定的代碼在只有一個辦法:

{ this, "{'CurrentIndex':{'Path':'CurrentIndex','Mode':'TwoWay'}}" } 
  • CURRENTINDEX是一個int屬性中查看
  • CURRENTINDEX也是一個int屬性在視圖模型

這種方式可行!

  • 視圖模型=>查看

但不是這樣!

  • 查看=>視圖模型

我有ViewControllers的集合,我的目標是呼籲CURRENTINDEX在視圖模型一個的DeleteCommand。

然而,

「Android和觸摸雙向綁定是不完整的」

參考:MvvmCross experiences, hindsight, limitations?

我的猜測是雙向模式只適用於控制(的UILabel,的UITextField, ...)但不適用於屬性。

那麼,有沒有一種好方法可以使它在兩種方式下都能正常工作?或者我的問題有其他選擇嗎?

帕特里克

回答

4

爲了使結合到View之間傳送的任何值到一個ViewModel,那麼它需要掛接到某個事件的值的變化時。

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

在視圖/活動中,使用了一個單一模式 - 因此每個綁定必須掛鉤到單獨的事件中。例如,使用TextChanged事件(參見MvxEditTextTextTargetBinding.cs)連接EditText上的文本,而使用Listener對象而不是事件(請參閱MvxSeekBarProgressTargetBinging.cs)將SeekBar中的值連接起來。

所以,如果你想實現這種雙向爲您的活動結合,那麼你可以通過這樣做:

  • 聲明一個事件 - CurrentIndexChanged - 在您的活動(MyActivity),其發射時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,而不是在這種情況下使用聲明性綁定可能會更好。

要清楚......在這種情況下,我將最有可能只寫活動財產:

public int CurrentIndex 
{ 
    get { return _currentIndex; } 
    set { _currentIndex = value; ViewModel.CurrentIndex = value; } 
} 

還是......我會考慮在活動不具有所有這些屬性。


如果有幫助,還有關於自定義綁定一些更多的信息:


希望這有助於!恕我直言綁定在那裏幫助你,當你在XML正在努力 - 你不必使用它們...

斯圖爾特


UPDATE如果你打算做大量的這些並遵循相同的名稱模式 - 使用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) }); 
     } 
    } 
} 
+0

@Stuart,在上例中,CurrentIndex是int類型,而MyBinding 要求T將是引用類型。如何使用您的更新答案? – ttotto

+0

@Stuart,註冊表。RegisterFactory(new MvxSimplePropertyInfoTargetBindingFactory(typeof(MyBinding ),typeof(MyActivity),「CurrentIndex」)); MyBinding錯誤 ttotto