poniedziałek, 21 września 2009

[Behaviors] TextBox Enter Button Invoke (TargetedTriggerAction)

Jakiś czas temu zdarzyło mi się napisać własny behavior, który w odróżnieniu od tych które dłubie na co dzień, może mieć zastosowanie w wielu aplikacjach, stąd też pomysł aby się nim podzielić :)

Co to są behaviorsy nie będę się rozpisywał w tym temacie. Zagadnienie jest większe, a do poczytania o nim polecam świetny artykuł: http://www.silverlightshow.net/items/Behaviors-and-Triggers-in-Silverlight-3.aspx

O co chodzi?

Skoro już wszyscy wiedzą co to są behaviorsy w Silverlight 3.0, to wypadało by powiedzieć że mój jest typu "TargetedTriggerAction", czyli wykonuje akcję na innym obiekcie gdy ten do którego jest przypisany, wywoła wybrany event.

Mój behavior po wciśnięciu przycisku "Enter" we wskazanym textboxsie zasymuluje wciśnięcie wskazanego przycisku (wszystko co dziedziczy z ButtonBase).

Pewnie pomyśleliście sobie od razu, co za bzdura, przecież można podpiąć event i wywołać tą samą metodę w kodzie. Tylko co w przypadku gdy namiętnie stosujemy MVVM, gdzie nasz "code behind" jest czyściutki i zawiera tylko konstruktor? W takim wypadku behavior jest tym czego poszukujemy. Co ważniejsze, "code behind" pozostaje nienaruszony, nie śmiecimy również w ViewModelu, a operacje "interfejsowe" pozostają ładnie oddzielone i nadają się do ponownego użycia.

Standardowe zastosowanie

Jak wspomniałem, behavior ma zastosowanie przede wszystkim w aplikacjach z wzorcem MVVM, a jego miejsce to np. pole wyszukiwania.

Live demo

Wciskając "Enter" w polu tekstowym otrzymujemy ten sam efekt co wciskając przycisk.

Dodajemy do aplikacji

    <Button x:Name="TargetedButton" Content="Targeted Button"  />
<TextBox Text="TextBox" >
<i:Interaction.Triggers>
<i:EventTrigger EventName="KeyDown" >
<behavior:TextBoxEnterButtonInvoke TargetName="TargetedButton" />
</i:EventTrigger>
</i:Interaction.Triggers>
</TextBox>

, gdzie "i:" jest przestrzenią nazw dla "clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity", a "behavior:" dla projektu w którym umieszony jest kod bahaviora.

Kod źródłowy

Kodu jest niewiele, więc postanowiłem wkleić go cały.

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;
using System.Windows.Interactivity;
using System.Windows.Automation.Peers;
using System.Windows.Automation.Provider;
using System.Windows.Controls.Primitives;

/// TargetedTriggerAction for TextBox control.
/// Invokes targeted button when Enter is pressed inside TextBox.
///
/// Jacek Ciereszko
/// http://jacekciereszko.pl
///

///

namespace TextBoxEnterBehavior
{
public class TextBoxEnterButtonInvoke : TargetedTriggerAction
{
///
/// Gets or sets the peer.
///

/// The peer.
private AutomationPeer _peer { get; set; }

///
/// Gets or sets the target button
///

private ButtonBase _targetedButton { get; set; }

///
/// Called after the TargetedTriggerAction is attached to an AssociatedObject.
///

/// Override this to hook up functionality to the AssociatedObject.
protected override void OnAttached()
{
base.OnAttached();
_targetedButton = this.Target;
if (null == _targetedButton)
{
return;
}

// set peer
this._peer = FrameworkElementAutomationPeer.FromElement(_targetedButton);
if (this._peer == null)
{
this._peer = FrameworkElementAutomationPeer.CreatePeerForElement(_targetedButton);
}
}

///
/// Called after targeted Button change.
///

/// Override this to hook up functionality to the new targeted Button.
protected override void OnTargetChanged(ButtonBase oldTarget, ButtonBase newTarget)
{
base.OnTargetChanged(oldTarget, newTarget);
_targetedButton = newTarget;
if (null == _targetedButton)
{
return;
}

// set peer
this._peer = FrameworkElementAutomationPeer.FromElement(_targetedButton);
if (this._peer == null)
{
this._peer = FrameworkElementAutomationPeer.CreatePeerForElement(_targetedButton);
}
}

///
/// Invokes the targeted Button when Enter key is pressed inside TextBox.
///

/// KeyEventArgs with Enter key
protected override void Invoke(object parameter)
{
KeyEventArgs keyEventArgs = parameter as KeyEventArgs;
if (null != keyEventArgs && keyEventArgs.Key == Key.Enter)
{
if (null != _peer)
{
IInvokeProvider invokeProvider = _peer.GetPattern(PatternInterface.Invoke) as IInvokeProvider;
invokeProvider.Invoke();
}
}
}
}
}

Do pobrania

Kod jest także dostępny do pobrania na stronie http://gallery.expression.microsoft.com/en-us/TextBoxInvokeButton.


Pozdrawiam,

Jacek Ciereszko

Brak komentarzy: