2012-10-05 1 views
2

Le problème est le même que pas la programmation avec MVVMCross, mais je me demande s'il y a une solution « multi-plateforme »:MVVMCross peut-il modifier le sélecteur lorsque vous cliquez sur ImageButton dans ListView?

Lorsque vous utilisez un ImageButton sur un MvxBindableListView (ou un ListView), nous devons mettre des options pour pour utiliser une action sur ce bouton:

 <ImageButton 
      ... 
      android:focusable="false" 
      android:clickable="true" 
      ... 
      local:MvxBind="'Click':{'Path':'Command1'}}" 
      /> 

Avec ces paramètres, les boutons réagissent sur le "Command1". Mais le problème est que le "sélecteur visuel" de ListView ne change pas.

Donnons un exemple:

Lorsque vous avez 5 lignes dans votre ListView, et le premier est sélectionné. Je touche l'ImageButton de la 3ème rangée, le "Command1" va réagir (avec le 3ème item du ListView) mais le sélecteur restera sur la première rangée.

Ainsi, dans Android, nous devons mettre une sorte de code comme ceci: Avec ce morceau de code

_imagebutton.Click += (object sender, EventArgs eventsArgs) => 
    { 
     View v = ... 
     MvxBindableListView l = ... 
     int p = l.GetPositionForView(...); 
     l.PerformItemClick(..., p, p); 
    }; 

l'élément droit est sélectionné et que le comportement est correct (tant que je ne suis pas voulez déclencher un événement réel avec ItemClick). Mais cette solution est la "façon Android" et pas vraiment crossplatform (et je vous laisse imaginer le code terrible pour initialiser tout ça)

Quelqu'un a une meilleure solution?

Hugo

Répondre

1

En partie, cela se sent comme cela est juste « UI oeil de bonbons » - et ainsi tombe dans le domaine de « Voir préoccupation » - et il est donc pas quelque chose qui mvvmcross tente normalement de faire multiplateforme .

Cependant ... Je pense qu'il y a un moyen. Si le gestionnaire de commandes dans ViewModel définit également un entier CurrentSelectedPosition sur le ViewModel, chaque interface utilisateur peut lier la propriété SelectedItemPosition de ViewModel à chaque liste de chaque interface utilisateur, ce qui devrait entraîner la mise à jour native de la sélection par l'interface utilisateur.

Je pense que cela fonctionne ... Mais sur Android, il aurait besoin d'un peu contraignant:

public class MvxAdapterViewSelectedItemPositionTargetB-inging : MvxBaseAndroidTargetBinding 
{ 
    private readonly AdapterView _adapterView; 

    public MvxAdapterViewSelectedItemPositionTargetBinging(AdapterView adapterView) 
    { 
     _adapterView = adapterView; 
     _adapterView.ItemSelected += AdapterViewOnItemSelected; 
    } 

    public override void SetValue(object value) 
    { 
     _adapterView.SetSelection((int)value); 
    } 

    private void AdapterViewOnItemSelected(object sender, AdapterView.ItemSelectedEventArgs itemSelectedEventArgs) 
    { 
     FireValueChanged(itemSelectedEventArgs.Position); 
    } 

    public override MvxBindingMode DefaultMode 
    { 
     get 
     { 
      return MvxBindingMode.TwoWay; 
     } 
    } 

    public override Type TargetType 
    { 
     get 
     { 
      return typeof(Int32); 
     } 
    } 

    protected override void Dispose(bool isDisposing) 
    { 
     if (isDisposing) 
     { 
      if (_adapterView != null) 
      { 
       _adapterView.ItemSelected -= AdapterViewOnItemSelected; 
      } 
     } 
     base.Dispose(isDisposing); 
    } 
} 

enregistré à l'aide:

 registry.RegisterFactory(new MvxCustomBindingFactory<AdapterView>("SelectedItemPosition", adapterView => new MvxAdapterViewSelectedItemPositionTargetBinging(adapterView))); 

et lié à l'interface utilisateur dans AXML par exemple comme:

<Mvx.MvxBindableListView 
    android:id="@android:id/list" 
    android:layout_width="fill_parent" 
    android:layout_height="fill_parent" 
    local:MvxBind="{'ItemsSource':{'Path':'Emails'},'SelectedItemPosition':{'Path':'CurrentSelectedPosition'}}" 
    local:MvxItemTemplate="@layout/listitem_email" 
/> 

J'ai testé cette idée en utilisant une liste de courrier électronique où les éléments de liste ViewModel étaient:

public class SimpleEmail 
    { 
     public EmailViewModel Parent { get; set; } 
     public string From { get; set; }  
     public string Header { get; set; }  
     public string Message { get; set; }  
     public ICommand Command1 
     { 
      get 
      { 
       return new MvxRelayCommand(() => Parent.CurrentSelectedPosition = Parent.Emails.IndexOf(this)); 
      } 
     } 
    } 
  • mais évidemment, cela est juste une démo ...

Note: J'utilise la position sélectionnée plutôt que l'objet sélectionné dans le code ci-dessus - parce que je connais les listes que vous utilisez. e très longtemps!


Si vous vouliez envisager une approche différente de votre code Android seulement, alors je pense que vous pouvez le faire en héritant de Mvx.MvxBindableListView (et peut-être l'élément de liste trop) et l'utilisation de ces classes pour mettre à jour le sélection d'une manière peut-être moins douloureuse.

+0

Salut Stuart, Merci encore pour votre réponse rapide. Il semble qu'Android ne réagisse pas à la valeur _adapterView.SetSelection ((int)). C'est pourquoi j'ai dû faire un PeformItemClick sur ListView avec la bonne position. Néanmoins, votre solution est plus jolie car elle est nativement liée au ListView. Je vais essayer d'hériter de MvxBindableListView quand j'aurai le temps (le délai arrive vite!) – hugoterelle

+0

AdapterView semble répondre à SetSelection ici - mais peut-être cela dépend de ce que votre "sélecteur visuel" est. Je pense qu'il y a une différence entre state_selected et state_pressed - mais je ne suis pas un expert en la matière! – Stuart

Questions connexes