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: Modifier les jeux de couleur dans les Thèmes des pages modernes de SharePoint Online par Blog Technique de Romelard Fabrice le 07-04-2018, 13:26

- Office 365: Script PowerShell pour fixer le Quota Warning de toutes les collections d’un tenant par Blog Technique de Romelard Fabrice le 07-03-2018, 14:16

- MVP Award 2018-2019 par Blog de Jérémy Jeanson le 07-02-2018, 20:39

- Reprise des articles de 2014 à aujourd’hui par Blog de Jérémy Jeanson le 06-20-2018, 13:00

- Office 365: Comment créer un sous-plan dans Office 365 Planner par Blog Technique de Romelard Fabrice le 06-14-2018, 17:19

- Office 365: Script PowerShell de création de sous-sites basés sur CSOM ou PnP par Blog Technique de Romelard Fabrice le 06-12-2018, 14:58

- Office 365: Comment exporter tous les comptes Azure Active Directory ayant une license via PowerShell par Blog Technique de Romelard Fabrice le 05-17-2018, 13:46

- PowerShell: Comment avoir le Country Name depuis un Country Code par Blog Technique de Romelard Fabrice le 05-17-2018, 13:20

- Office 365: Comment supprimer un compte externe d’un site SharePoint Online en mode Extranet par Blog Technique de Romelard Fabrice le 05-11-2018, 17:00

- Office 365: Comment reconfigurer le lien “Bloc-notes” d’un teamsite par Blog Technique de Romelard Fabrice le 05-09-2018, 16:45