Quand la boite de dialogue n’est plus ton ami.

Bien que j’apprécie l’API WinRT pour développer des apps universelles je ne peux m’empêcher de penser que la peinture n’est pas totalement sèche en ce qui concerne Windows (Phone) 8.1.
L’objet de cet article est de vous montrer un exemple de problème apporté par ce manque de finition mais également un moyen simple de le contourner.

MessageDialog m’a tué

Lorsque je veux communiquer des messages importants à l’utilisateur de mon app je lui affiche une boite de dialogue.
En Silverlight cela se passe comme ceci :

MessageBox.Show("Hello world!");

En WinRT c’est à peine plus compliqué :

var dialog = new MessageDialog("Hello world!");
await dialog.ShowAsync();

Jusqu’ici tout va bien.

Imaginons maintenant qu’un DispatcherTimer ou une Task de votre cru décide de lancer une seconde boite de dialogue pendant que la première est affichée que va t’il se passer ?

En Silverlight, la seconde boite attendra sagement son tour et s’affichera lorsque la première sera fermée.

Nice !

WinRT considère qu’une seule boite de dialogue peut être affichée à la fois n’en déplaise aux travailleurs parallèles. Une exception sera donc levée lors de l’affichage de la seconde boite et fermera votre application.

Sad !

sh nazg durbatulûk

J’aimerai retrouver un comportement de boite de dialogue similaire à celle de Silverlight.
A savoir, lorsque plusieurs boites doivent être affichées au même moment, elles attendront leur tour pour s’afficher.

On va donc mettre en place un sémaphore qui sera chargé d’attendre le tour du ShowAsync de MessageDialog.

static SemaphoreSlim semaphore = new SemaphoreSlim(1);

public static async Task ShowOrWaitAsync(this MessageDialog dialog)
{            
	await semaphore.WaitAsync();

	try
	{
		await dialog.ShowAsync();
	}
	finally
	{
		semaphore.Release();
	}
}

On préférera utiliser ici SemaphoreSlim plutôt qu’un Mutex par exemple pour sa capacité à travailler de manière asynchrone.

La méthode ayant été déclarée comme méthode d’extension de « MessageDialog » grâce au paramètre « this » nous allons pouvoir écrire pour chaque boîte de dialogue à appeler le code suivant :

MessageDialog dialog = new MessageDialog("Test 0");
await dialog.ShowOrWaitAsync();

Elle attendra patiemment son tour en cas de conflit d’affichage.

Merci qui ?

Vous trouverez la solution du projet ici. La classe à inclure dans votre projet s’appelle « DialogManager ».En Bonus, elle gère également les ContentDialog de Windows Phone qui souffre du même mal.

Je trouve vraiment dommage que ce genre de scénario, finalement assez courant, ne soit pas prise en charge nativement par l’API.
Mais Windows 10 arrive bientôt, et j’ai espoir que tous ces petits tracas seront bientôt de l’histoire ancienne.

Win10IsComing

leave your comment