2012-06-27 4 views
3

Я новичок в MvvmCross, и у меня есть вопрос.MvvmCross Monotouch C# - Binding Int Property - Режим: TwoWay

я заметил, что следующий код привязки работает только одним способом:

{ this, "{'CurrentIndex':{'Path':'CurrentIndex','Mode':'TwoWay'}}" } 
  • CurrentIndex является Int собственности в представлении
  • CurrentIndex также Int недвижимости в ViewModel

Этот способ работает!

  • ViewModel => Просмотр

Но это не так!

  • Вид => ViewModel

У меня есть коллекция ViewControllers и моя цель состояла в том, чтобы вызвать DeleteCommand для CurrentIndex в ViewModel.

Однако

"Android и сенсорный 2 способ привязки являются неполными"

Ссылка: MvvmCross experiences, hindsight, limitations?

Моя догадка режим TwoWay работает только для элементов управления (UILabel, UITextField, ...), но не для свойств.

Итак, есть ли хороший способ заставить его работать в обоих направлениях? Или есть альтернативы моей проблеме?

Патрик

ответ

4

Для того, чтобы привязка передать любое значение между видом на ViewModel, то нужно подключить в какое-то событие, когда изменяется значение.

В ViewModel это событие всегда является событием в интерфейсе INotifyProperty.

В представлении/действии используется один шаблон - поэтому каждое привязку должно подключаться к отдельному событию. Например, текст в EditText подключается с использованием события TextChanged (см. MvxEditTextTextTargetBinding.cs), а значение в SeekBar подключается с использованием объекта Listener, а не события (см. MvxSeekBarProgressTargetBinging.cs).

Так что если вы хотите, чтобы реализовать эту двустороннюю привязку для вашей деятельности, то вы могли бы сделать это:

  • объявить событие - 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 с событием измененной EventHandler с именем 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 (новый MvxSimplePropertyInfoTargetBindingFactory (typeof (MyBinding ), typeof (MyActivity), «CurrentIndex»)); Ошибка в MyBinding ttotto