posté @ Monday, February 16, 2009 4:59 PM

Silverlight 2 introduit le contrôle “PasswordBox” qui permet d’entrer un mot de passe sans qu’il n’apparaisse en clair à l’écran. Le problème de ce contrôle est qu’il ne supporte pas le DataBinding sur sa propriété “Password”. En effet, si on lui affecte un Binding, une exception est levée (avec par ailleurs un message d’erreur pour le moins obscure).

Afin d’ajouter des possibilités de Binding à ce contrôle, on aurait pu en hériter et modifier son comportement. Mais cette approche est très intrusive et oblige l’utilisateur à utiliser ce nouveau contrôle. Une approche plus élégante est d’utiliser une AttachedProperty comme Pierre Lagarde nous l’a montré mercredi dernier lors de la session “Développement de contrôles avec Silverlight 2” qu’il co-animait avec Thierry Bouquain et moi, avec son exemple d’image downloader. En effet, une AttachedProperty étant une DependencyProperty spéciale, elle supporte le DataBinding, et nous pouvons donc écrire une propriété “proxy” permettant de faire le lien vers la propriété Password d’une PropertyBox.

Voici le code utilisé (fournit dans SLExtension) :

using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;

namespace SLExtensions
{
    /// <summary>
    /// Provide attached property to enable DataBinding on PasswordBox
    /// </summary>
    public class PasswordHelper : DependencyObject
    {

        /// <summary>
        /// Indicates if a PasswordBox is DataBound
        /// </summary>
        /// <param name="obj"></param>
        /// <returns></returns>
        public static bool GetIsBound(PasswordBox obj)
        {
            return (bool)obj.GetValue(IsBoundProperty);
        }

        private static void SetIsBound(PasswordBox obj, bool value)
        {
            obj.SetValue(IsBoundProperty, value);
        }

        public static readonly DependencyProperty IsBoundProperty =
            DependencyProperty.RegisterAttached("IsBound", typeof(bool), 
            typeof(PasswordHelper), 
            new PropertyMetadata(false));


        /// <summary>
        /// Text of the PasswordBox (bindable vision of Password property)
        /// </summary>
        /// <param name="obj"></param>
        /// <returns></returns>
        public static string GetText(PasswordBox obj)
        {
            return (string)obj.GetValue(TextProperty);
        }

        public static void SetText(PasswordBox obj, string value)
        {
            obj.SetValue(TextProperty, value);
        }

        public static readonly DependencyProperty TextProperty =
            DependencyProperty.RegisterAttached("Text", typeof(string),
            typeof(PasswordHelper), 
            new PropertyMetadata(string.Empty,
                (sender, args) =>
                {
                    var pwdBox = sender as PasswordBox;
                    if (pwdBox == null)
                        return;
                    var nval = (args.NewValue as string) ?? string.Empty;
                    if(pwdBox.Password != nval)
                        pwdBox.Password = nval;
                    if (!GetIsBound(pwdBox))
                    {
                        pwdBox.PasswordChanged += delegate
                        {
                            SetText(pwdBox, pwdBox.Password);
                        };
                        SetIsBound(pwdBox, true);
                    }
                }));
    }
}

Et à l’utilisation, il suffit maintenant de faire :

<PasswordBox sle:PasswordHelper.Text="{Binding Text,Mode=TwoWay}" />

Enjoy !

Commentaires :

No comments posted yet.

Ecrire un commentaire :

Titre :*
Nom *
Email
Url
Commentaire : *  


Please add 2 and 5 and type the answer here: