Bienvenue à Blogs CodeS-SourceS Identification | Inscription | Aide

[WP7] Comment avoir une applicationbar bindable ?

L’API Windows Phone 7 permet d’afficher une barre de menu standard dans vos applications. Malheureusement, il n'est pas possible de faire du binding dessus, car l'object n'est pas un FrameworkElements, mais pourquoi ? Voici la réponse de Peter Torrs:

Firstly, the ApplicationBar is not a Silverlight element and thus not all Silverlight concepts apply to it. For example, you would expect that the Background could be set to any kind of brush - SolidColorBrush, LinearGradientBrush, and so on - but because the AppBar is actually rendered by the Windows Phone shell, it only supports a solid colour. You might also expect to be able to put arbitrary Content inside the buttons, or to apply RenderTransforms to the menu items, and so on. And you should be able to put it anywhere on the screen with HorizontalAlignment / VerticalAlignment, right? Again, none of these things are supported by the underlying shell UX, so they would all have to throw exceptions or no-op when called. And where's the fun in that?

Secondly, the content models in Silverlight 3 do not support controls with multiple collections of items. Some of the built-in elements have multiple collections - for example, Grid has the Children collection in addition to the RowDefinitions and ColumnDefinitions collections - but these are not actually usable outside of the "core" (they rely on PresentationFrameworkCollection, which is an internal class, and in order to maintain portability across platforms we are not adding anything phone-specific to the "core"). For the AppBar, we want both a Buttons collection and a MenuItems collection, and that's just not doable in a clean, strongly-typed API (there are hacks, such as making the AppBar a generic container and then hoping that developers only put buttons and menu items into it, but they're not good design). Silverlight 4 has addressed this limitation with the DependencyObjectCollection class, but Windows Phone is based on version 3, not 4.

Pour résumer, l’applicationBar n’est pas un objet SilverLight…voila qui est bien embêtant…

Pour répondre au besoin de binding, j’ai développé un wrapper qui le permet, il est ainsi possible d’associer des commandes sur le click d’un bouton et ainsi de respecter les patterns MVVM.

Son utilisation est très simple, prenons l’exemple d’un bouton et d’un item de menu:

<Controls:BindableApplicationBar x:Name="AppBar" BarOpacity="1.0" IsVisible="{Binding IsBarVisible}" >
  <Controls:BindableApplicationBarIconButton Command="{Binding AddCommand}" Text="Add" IconUri="/images/appbar.add.rest.png" />
  <Controls:BindableApplicationBar.MenuItems>
    <Controls:BindableApplicationBarMenuItem  Text="Settings" Command="{Binding SettingsCommand}" />
  </Controls:BindableApplicationBar.MenuItems>
</Controls:BindableApplicationBar>

Regardons maintenant les rouages du wrapper. Le wrapper est un control héritant de ItemsControl et implémentant l’interface standard IApplicationBar. Je l’ai nommé BindableApplicationBar.

[ContentProperty("Buttons")]
public class BindableApplicationBar : ItemsControl, IApplicationBar
{
    // ApplicationBar wrappé
    private readonly ApplicationBar _applicationBar;

    public BindableApplicationBar()
    {
        _applicationBar = new ApplicationBar();
        this.Loaded += BindableApplicationBar_Loaded;
    }

    void BindableApplicationBar_Loaded(object sender, RoutedEventArgs e)
    {
        // AU chargement du control, on recherche la page ou est situé le control pour lui associé notre applicationbar
        var page =
            this.GetVisualAncestors().Where(c => c is PhoneApplicationPage).FirstOrDefault() as PhoneApplicationPage;
        if (page != null) page.ApplicationBar = _applicationBar;
    }
...

L’étape suivant est d’ajouter les boutons et menuItems XAML à l’applicationbar wrappé.

protected override void OnItemsChanged(System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
{
    base.OnItemsChanged(e);
    // On efface tout, pour être sur...
    _applicationBar.Buttons.Clear();
    _applicationBar.MenuItems.Clear();
    // On récupère tous les boutons défini dans les items de l'ItemsControl
    foreach (BindableApplicationBarIconButton button in Items.Where(c => c is BindableApplicationBarIconButton))
    {
        // on les affectes a l'application bar
        _applicationBar.Buttons.Add(button.Button);
    }
    foreach (BindableApplicationBarMenuItem button in Items.Where(c => c is BindableApplicationBarMenuItem))
    {
        _applicationBar.MenuItems.Add(button.MenuItem);
    }
}

Ensuite, pour que le binding soit effectif, il suffit de rajouter les DependencyProperty.

public static readonly DependencyProperty IsVisibleProperty =
    DependencyProperty.RegisterAttached("IsVisible", typeof(bool), typeof(BindableApplicationBar), new PropertyMetadata(true, OnVisibleChanged));

private static void OnVisibleChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
    if (e.NewValue != e.OldValue)
    {
        ((BindableApplicationBar) d)._applicationBar.IsVisible = (bool) e.NewValue;
    }
}

public bool IsVisible
{
    get { return (bool)GetValue(IsVisibleProperty); }
    set { SetValue(IsVisibleProperty, value); }
}

Le mécanisme du wrapper est plus ou moins identique pour BindableApplicationBarIconButton et BindableApplicationBarMenuItem.

Le binding peut ainsi s’effectuer sur les propriétés (Visible, Text, …), et sur les commands et commandparameter ! Je précise que le binding sur la propriété text est très pratique dans le cas d’une application multilingue. On peut ainsi appliqué du binding sur des fichiers de resources, comme expliqué dans cet article MSDN :http://msdn.microsoft.com/en-us/library/ff637520%28VS.92%29.aspx

Ce code est utilisé pour le projet Warnygo, et est bien sur disponible : Phone7.Fx.Preview.zip

Si vous avez des retours, n’hésitez pas !

Publié jeudi 19 août 2010 11:46 par Nicolas
Classé sous : ,
Ce post vous a plu ? Ajoutez le dans vos favoris pour ne pas perdre de temps à le retrouver le jour où vous en aurez besoin :

Commentaires

Pas de commentaires
Les commentaires anonymes sont désactivés

Les 10 derniers blogs postés

- Office 365: Script PowerShell pour assigner des droits Full Control à un groupe défini par Blog Technique de Romelard Fabrice le 04-30-2017, 09:22

- SharePoint 20XX: Script PowerShell pour exporter en CSV toutes les listes d’une ferme pour auditer le contenu avant migration par Blog Technique de Romelard Fabrice le 03-28-2017, 17:53

- Les pièges de l’installation de Visual Studio 2017 par Blog de Jérémy Jeanson le 03-24-2017, 13:05

- UWP or not UWP sur Visual Studio 2015 ? par Blog de Jérémy Jeanson le 03-08-2017, 19:12

- Désinstallation de .net Core RC1 Update 1 ou SDK de Core 1 Preview 2 par Blog de Jérémy Jeanson le 03-07-2017, 19:29

- Office 365: Ajouter un utilisateur ou groupe dans la liste des Site collection Administrator d’un site SharePoint Online via PowerShell et CSOM par Blog Technique de Romelard Fabrice le 02-24-2017, 18:52

- Office 365: Comment créer une document library qui utilise les ContentTypeHub avec PowerShell et CSOM par Blog Technique de Romelard Fabrice le 02-22-2017, 17:06

- [TFS] Supprimer en masse les dépendances à SQL Enterprise ou Developer avant de procéder à une migration par Blog de Jérémy Jeanson le 02-20-2017, 20:30

- Office 365: Attention au volume utilisé par les fichiers de Thèmes de SharePoint Online par Blog Technique de Romelard Fabrice le 02-07-2017, 18:19

- [SCVMM] Supprimer une machine bloquée par Blog de Jérémy Jeanson le 01-31-2017, 21:22