Menu

A

|

A

Binding et UITableViewCell (MvxTableViewCell)

Binding et UITableViewCell (MvxTableViewCell)

J’ai récemment eu à traiter un cas avec Xamarin iOS et MvvmCross en utilisant les Tables, je n’arrivais pas à gérer le binding entre les cellules et les éléments de ma source, j’ai fini par réussir à faire ceci avec MvxTableViewCell, donc voici comment j’ai procédé. Tout d’abord je vais décrire le cas en question.

En XAML :

Imaginons que nous ayons un ItemsControl ayant dans son ItemSource une liste d’instance d’un ViewModel. Le moteur XAML va faire en sorte dans l’arbre visuel que chaque instance du DataModel associé à un élément, reçoivent en DataContext l’élément lui-même. Ce qui permet dans le DataModel de faire du Binding directement à partir de l’élément, ce qui est pratique car on peut affecter les propriétés de notre ViewModel sur le rendu du DataModel.

Xamarin iOS et MvvmCross

Maintenant j’ai le même cas sur iOS avec Xamarin. Je crée donc un MvxTableViewController, je crée la table et surcharge donc le GetCell pour traiter mes cellules. Cependant, quand je veux créer un binding entre les éléments de ma cellule et mon élément dans la liste cela se complique.

Si je fais ce genre de binding :

UIButton myButton = (UIButton)cell.ViewWithTag(1);
this.CreateBinding(myButton).To((MyViewModel vm) => vm.MyCommand).Apply();

J’aurais une belle erreur, car la propriété MyCommand ne va pas être trouvé. En effet car le DataContext est le ViewModel de la page et non celui de l’élément. J’ai cherché longtemps avant de trouver une solution avec le MvxTableViewCell.

La solution

Afin de pouvoir effectuer le binding sur mes cellules il faut redéfinir le DataContext au moment du binding et ceux sans tout casser. Pour cela, j’ai investiguer sur l’objet MvxTableViewCell qui permet d’encapsuler un UITableViewCell afin d’y ajouter les possibilités de MvvmCross et notamment le binding.

Pour cela rien de plus simple, voici comment faire avec le code ci-dessous :

public override UITableViewCell GetCell(UITableView tableView, Foundation.NSIndexPath indexPath)
{
  // Récupération d'une cellule réutilisable
  UITableViewCell cell = tableView.DequeueReusableCell("templateName");

  // Si pas de cellule a réutiliser, on la crée
  if (cell == null)
    cell = new UITableViewCell(UITableViewCellStyle.Default, "templateName");

  // Création de la liaison avec le MvxTableViewCell
  MvxTableViewCell cellBinding = new MvxTableViewCell(cell.ClassHandle);

  // Ici l'objet data représente le nouveau DataContext, donc l'instance du ViewModel de l'élément
  cellBinding.DataContext = data;

  // Définition du binding
  UIButton myButton = (UIButton)cell.ViewWithTag(1);
  cellBinding.CreateBinding(myButton).To((MyViewModel vm) => vm.MyCommand).Apply();

  // On renvoi la cellule
  return (cell);
}

De cette façon on peut redéfinir au moment de la récupération de la cellule, le binding entre les différents éléments de notre ViewModel. Il y a sûrement plus propre et plus simple, mais dans mon cas cela a solutionné mon problème et m’a permis de faire du binding sur les éléments et non sur le DataContext de la page.

Binding et UITableViewCell (MvxTableViewCell)

Binding et UITableViewCell (MvxTableViewCell)

J’ai récemment eu à traiter un cas avec Xamarin iOS et MvvmCross en utilisant les Tables, je n’arrivais pas à gérer le binding entre les cellules et les éléments de ma source, j’ai fini par réussir à faire ceci avec MvxTableViewCell, donc voici comment j’ai procédé. Tout d’abord je vais décrire le cas en question.

En XAML :

Imaginons que nous ayons un ItemsControl ayant dans son ItemSource une liste d’instance d’un ViewModel. Le moteur XAML va faire en sorte dans l’arbre visuel que chaque instance du DataModel associé à un élément, reçoivent en DataContext l’élément lui-même. Ce qui permet dans le DataModel de faire du Binding directement à partir de l’élément, ce qui est pratique car on peut affecter les propriétés de notre ViewModel sur le rendu du DataModel.

Xamarin iOS et MvvmCross

Maintenant j’ai le même cas sur iOS avec Xamarin. Je crée donc un MvxTableViewController, je crée la table et surcharge donc le GetCell pour traiter mes cellules. Cependant, quand je veux créer un binding entre les éléments de ma cellule et mon élément dans la liste cela se complique.

Si je fais ce genre de binding :

UIButton myButton = (UIButton)cell.ViewWithTag(1);
this.CreateBinding(myButton).To((MyViewModel vm) => vm.MyCommand).Apply();

J’aurais une belle erreur, car la propriété MyCommand ne va pas être trouvé. En effet car le DataContext est le ViewModel de la page et non celui de l’élément. J’ai cherché longtemps avant de trouver une solution avec le MvxTableViewCell.

La solution

Afin de pouvoir effectuer le binding sur mes cellules il faut redéfinir le DataContext au moment du binding et ceux sans tout casser. Pour cela, j’ai investiguer sur l’objet MvxTableViewCell qui permet d’encapsuler un UITableViewCell afin d’y ajouter les possibilités de MvvmCross et notamment le binding.

Pour cela rien de plus simple, voici comment faire avec le code ci-dessous :

public override UITableViewCell GetCell(UITableView tableView, Foundation.NSIndexPath indexPath)
{
  // Récupération d'une cellule réutilisable
  UITableViewCell cell = tableView.DequeueReusableCell("templateName");

  // Si pas de cellule a réutiliser, on la crée
  if (cell == null)
    cell = new UITableViewCell(UITableViewCellStyle.Default, "templateName");

  // Création de la liaison avec le MvxTableViewCell
  MvxTableViewCell cellBinding = new MvxTableViewCell(cell.ClassHandle);

  // Ici l'objet data représente le nouveau DataContext, donc l'instance du ViewModel de l'élément
  cellBinding.DataContext = data;

  // Définition du binding
  UIButton myButton = (UIButton)cell.ViewWithTag(1);
  cellBinding.CreateBinding(myButton).To((MyViewModel vm) => vm.MyCommand).Apply();

  // On renvoi la cellule
  return (cell);
}

De cette façon on peut redéfinir au moment de la récupération de la cellule, le binding entre les différents éléments de notre ViewModel. Il y a sûrement plus propre et plus simple, mais dans mon cas cela a solutionné mon problème et m’a permis de faire du binding sur les éléments et non sur le DataContext de la page.

No Comments

Comments Are Closed