Una delle principali difficoltà nel passare dai Windows Forms a WPF è sicuramente quella di affrontare gli stessi problemi in maniera completamente diversa da come sono stati affrontati in passato, in pratica lo stesso problema di chi, dopo anni di VB6 decide di passare a VB 2008.
Tra le tecniche che, lentamente, stanno ottenendo parecchio successo tra gli sviluppatori WPF c’è sicuramente l' "Attached Behavior" ovvero il racchiudere in una classe esterna una o più funzionalità applicabili in base alla necessità ai vari elementi che compongono una UI WPF.
Consideriamo un caso tanto semplice, quanto frequente: Selezionare il contenuto di una TextBox quando questa ottiene il focus.
Se fossimo nel mondo WinForms avremmo diverse possibilità per raggiungere lo scopo, dal mappare l'evento Enter su una routine comune, al creare un controllo custom che arricchisce il controllo base con la nuova funzionalità.
Entrambe le soluzioni sono applicabili in WPF, entrambe però hanno, come nei WinForm, dei punti deboli: il primo non è molto riutilizzabile mentre il secondo è forse un pò troppo complesso per un operazione cosi banale.
In WPF si usa risolvere questo genere di problematiche utilizzando una tecnica denominata Attached Behavior che sfrutta le potenzialità offerte dalle Dependency Properties abbinando Attached Properties con PropertyChangedCallback.
Creiamo quindi una classe TextBoxBehavior e aggiungiamo a questa un attached property denominata AutoSelectText

public static class TextBoxBehavior
{ 
  public static bool GetAutoSelectText (TextBox textBox)
  {
    return (bool)textBox.GetValue(AutoSelectTextProperty);
  }
  public static void SetAutoSelectContents (TextBox textBox, bool value)
  {
    textBox.SetValue(AutoSelectTextProperty, value);
  }
  public static readonly DependencyProperty AutoSelectTextProperty =
      DependencyProperty.RegisterAttached(
      "AutoSelectedContents",
      typeof(bool),
      typeof(TextBoxBehavior), 
      new UIPropertyMetadata(OnAutoSelectedChanged));

  static void OnAutoSelectedChanged (DependencyObject sender, DependencyPropertyChangedEventArgs e)
  {
    //Get source
    TextBox source = (sender as TextBox);      
    //Null means property is not attached to a TextBox
    if (source == null) return;
    if ((bool)e.NewValue)
      source.GotFocus += HandleGotFocus;
    else
      source.GotFocus -= HandleGotFocus;
  }

  static void HandleGotFocus (object sender, RoutedEventArgs e)
  {
    TextBox source = (sender as TextBox);
    source.SelectAll();
  }
}
 

Come potete notare la ‘magia’ sta nel sottoscrivere gli eventi che ci interessando nel metodo associato a PropertyChangedCallback che verrà invocato non appena l' Attached Property verrà inizializzata dal parser XAML.
A questo punto non ci rimane che aggiungere la funzionalità alle textbox nello XAML (vedi sotto) estendendo, di fatto, il controllo con una soluzione riutilizzabile che non coinvolge la parte dichiarativa in dettagli legati alla funzionalità a run-time.

<Window x:Class="AttachedBehaviorDemo.Window1" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:m="clr-namespace:AttachedBehaviorDemo" Title="Window1" Height="300" Width="300"> <StackPanel> <TextBox m:TextBoxBehavior.AutoSelectContents="True" Height="21" Margin="10,10" Text="Test1" /> <TextBox m:TextBoxBehavior.AutoSelectContents="True" Height="22" Margin="10,10" Text="Test2" /> </StackPanel> </Window>

 

Technorati Tags: ,