Non è raro non trovare tutte le caratteristiche di cui si ha bisogno nei controlli di Windows Presentation Foundation, seppure molto elastici e versatili tramite style e template. Nelle WinForm per personalizzare un controllo è necessario utilizzare subclassing o ereditare dal controllo per sovrascrivere alcuni metodi e anche questo è possibile farlo in WPF. In aiuto però possono venire anche le attached property che possono essere sfruttare per agganciare una proprietà ad un controllo ed influire su di esso basandosi su eventi e ulteriori proprietà. Il vantaggio di questo è approccio sta nel poter agganciare alcuni comportamenti a piacimento, anche su tipologie diverse di controlli; in questo caso queste proprietà prendono il nome di attached behavior.
In questo script si prepara quindi un behavior che permetta di nascondere automaticamente un Menu alla perdita del focus, come alcuni player fanno, e di farlo ricomparire alla pressione del tasto alt. Per farlo occorre creare una classe che contenga l'attached property con i rispettivi metodi statici Set e Get, come il pattern richiede per essere interpretato dal parser XAML.
public static class MenuBehavior { public static readonly DependencyProperty AutoHideProperty = DependencyProperty.RegisterAttached("AutoHide", typeof(Boolean), typeof(Menu), new FrameworkPropertyMetadata(false, new PropertyChangedCallback(OnAutoHideChanged))); public static void SetAutoHide(Menu menu, bool value) { menu.SetValue(AutoHideProperty, value); } public static bool GetAutoHide(Menu menu) { return (bool)menu.GetValue(AutoHideProperty); }
Il metodo OnAutoHideChanged è il cuore del behavior, perché in esso va implementato il codice di personalizzazione. Nell'esempio in questione si deve intercettare la perdita del focus da parte del Menu per nasconderlo, e la pressione del tasto alt, a livello di oggetto radice (solitamente la Window), per farlo ricomparire.
private static void OnAutoHideChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { Menu menu = (Menu)d; // Cerco l'elemento principale, per intercettare la pressione di tutti i pulsanti FrameworkElement parent = menu; while (true) { FrameworkElement newParent = LogicalTreeHelper.GetParent(parent) as FrameworkElement; if (newParent != null) parent = newParent; else break; } KeyEventHandler menuKeyDownHandler = delegate(object sender, KeyEventArgs ke) { // Se preme ALT, mostro il menu if (ke.KeyboardDevice.Modifiers == ModifierKeys.Alt) { menu.Visibility = Visibility.Visible; } }; if ((bool)e.NewValue) { // Intercetto gli eventi if (parent != null) parent.KeyDown += menuKeyDownHandler; menu.LostKeyboardFocus += MenuLostFocusHandler; menu.Visibility = Visibility.Collapsed; } else { // Non intercetto più gli eventi if (parent != null) parent.KeyDown -= menuKeyDownHandler; menu.LostKeyboardFocus -= MenuLostFocusHandler; menu.Visibility = Visibility.Visible; } }
A questo punto il suo utilizzo è piuttosto banale:
<Window xmlns:m="clr-namespace:MyApplicaation"> <DockPanel> <Menu DockPanel.Dock="Top" m:MenuBehavior.AutoHide="True"> <MenuItem Header="_File"> <MenuItem Header="_Exit" /> </MenuItem> </Menu> <TextBox></TextBox> </DockPanel> </Window>
Commenti
Per inserire un commento, devi avere un account.
Fai il login e torna a questa pagina, oppure registrati alla nostra community.