Attached Behaviours, Routed Events, Routed Commands ja Drag & Drop - Luento 14
Käydään läpi Attached Properties / Behaviours, Routed Events, Routed Commands ja Drag & Drop
Luentoesimerkki (luento14.zip)
- Luentovideo (Youtube)
- tjlahton2012-03-07_1451.mp4 56.1 Mt
- tjlahton2012-03-07_1451.wmv 94.0 Mt
- tjlahton2012-03-07_1451.mp3 25.4 Mt
Attached Behaviours / Properties
Attached propertieseilla voi lisätä ominaisuuksia elementin lapsi- tai vanhenmpielementteihin kuten esim.
<DockPanel> <Button DockPanel.Dock="Top">Painike</Button> </DockPanel>
Samaan tapaan voi tehdä lähes mitä tahansa laajennoksia joita voi kytkeä mihin tahansa elementtien riippumatta xamlin elementtipuun rakenteesta.
Esimerkki apinoitu artikkelista Artikkelista:Attached behaviours in WPF
// tarkistetaan, että tekstikenttään syötetään vain numeroita public static class NumbersOnlyBehaviour { public static bool GetNumbersOnly(DependencyObject obj) { return (bool)obj.GetValue(NumbersOnlyProperty); } public static void SetNumbersOnly(DependencyObject obj, bool value) { obj.SetValue(NumbersOnlyProperty, value); } public static readonly DependencyProperty NumbersOnlyProperty = DependencyProperty.RegisterAttached("NumbersOnly", typeof(bool), typeof(NumbersOnlyBehaviour), new UIPropertyMetadata(false, OnNumbersOnlyChanged)); private static void OnNumbersOnlyChanged(object sender, DependencyPropertyChangedEventArgs e) { if (!(sender is TextBox)) return; TextBox textBox = (TextBox)sender; bool isNumberOnly = (bool)(e.NewValue); if (isNumberOnly) textBox.PreviewTextInput += BlockNonNumbers; else textBox.PreviewTextInput -= BlockNonNumbers; } private static void BlockNonNumbers(object sender, TextCompositionEventArgs e) { foreach (char ch in e.Text) if (!Char.IsDigit(ch)) e.Handled = true; } }
XAML:
<TextBox oma:NumbersOnlyBehaviour.NumbersOnly="True" />
Drag & Drop
- Lisää raahattavaan objektiin MouseMove tms. tapahtumankäsittelijä, joka aloittaa Drag & Drop -toiminnon
- DoDragDrop
- Määritä lähtöobjekti, raahattava tieto ja mahdolliset raahausefektit
- Jonkin elementin pitää olla raahauksen kohde (AllowDrop = True)
- Kohteessa täytyy käsitellä Drop-tapahtuma, joka ottaa vastaan raahatun tiedon (GetData )
- Tee raahatulla tiedolla jotakin
Drag & Dropin perustoiminnot voi tehdä Attached Propertyn avulla. kts. luentomalli.
Routed Events
Routed Event kulkee elementtipuussa ylös tai alaspäin eli saman tapahtuman voi käsitellä useampikin elementti eikä vain ainoastaan yksi kuten Windows Formsissa
- Tunneling - tapahtuma kulkee puussa juuresta ylöspäin eli käsittely alkaa Window-elementistä ja kulkee puuta eteenpäin kunnes päätyy lehteen (Preview-events)
- Bubbling - tapahtuma kulkee puussa sisältä kohti juuri esim. painikkeen Click-tapahtumassa painike käsittelee tapahtuman ensin ja seuraava elementti, jonka sisällä painike on jne. kunnes saavutaan juurielementtiin eli esim. Window
- Direct - tapahtuman käsittely kuten Windows Formsissa
Yleensä sama tapahtuma käsitellään tapahtumaparina eli ensimmäisenä on Tunneling-versio tapahtumasta ja sen jälkeen Bubbling-versio esim. PreviewMouseLeftButtonDown-tapahtuu ensin (Tunneling) ja myöhemmin MouseLeftButtonDown (Bubbling).
Tapahtuman voi käsitellä useampi käsittelijä. Matkan varrella tapahtumaan liittyvää dataa voidaan muuttaa. Käsittelijä voi myös ilmoittaa, että tapahtuma on käsitelty (e.Handled = True), jonka jälkeen muut eivät saa tapahtumaa enää käsittelyyn (Tämä on tosin kierrettävissä, HandleEventsToo = True).
public class OmaButton: Button { public static readonly RoutedEvent OmaEvent = EventManager.RegisterRoutedEvent( "Oma", RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(OmaControl)); public event RoutedEventHandler Oma { add { AddHandler(OmaEvent, value); } remove { RemoveHandler(OmaEvent, value); } } void RaiseOmaEvent() { RoutedEventArgs newEventArgs = new RoutedEventArgs(OmaButton.OmaEvent); RaiseEvent(newEventArgs); } protected override void OnClick() { RaiseOmaEvent(); } }
EventSetter ja EventTrigger toimivat vain Routed Eventien kanssa. EventTriggereihin palataan animaatioiden yhteydessä.
Attached Events
<StackPanel Background="LightGray" Orientation="Horizontal" Button.Click="CommonClickHandler"> <Button Name="YesButton" Width="Auto" >Yes</Button> <Button Name="NoButton" Width="Auto" >No</Button> <Button Name="CancelButton" Width="Auto" >Cancel</Button> </StackPanel>
Routed Commands
Routed Commands aktivoivat/disabloivat niihin liittyvät käyttöliittymäkontrollit automaattisesti sen perusteella ilmoittaakö niihin liittyvä käsittelijä komennon olevan käytössä tai pois käytöstä
Routed Commandeja käyttävien elementtien ei tarvitse suoraan liittyä vastaaviin käsittelijöihin
Komento:
<Button Name="komentopainike" Command="ApplicationCommands.Save">Save</Button> <Button Command="Save" CommandTarget="{Binding ElementName=komentopainike}" >Save</Button> <Window.InputBindings> <KeyBinding Key="O" Modifiers="Control" Command="ApplicationCommands.Open" /> </Window.InputBindings> <StackPanel> <Menu> <MenuItem Command="ApplicationCommands.Paste" CommandTarget="{Binding ElementName=mainTextBox}" /> </Menu> <TextBox Name="mainTextBox"/> </StackPanel> <!-- Oma komento --> <Window.CommandBindings> <CommandBinding Command="{x:Static custom:Window1.CustomRoutedCommand}" Executed="ExecutedCustomCommand" CanExecute="CanExecuteCustomCommand" /> </Window.CommandBindings>
Komennon käsittelijä:
<UserControl ...> <UserControl.CommandBindings> <CommandBinding Command="ApplicationCommands.Save" CanExecute="OnCanExecute" Executed="OnExecute"/> </UserControl.CommandBindings> </UserControl>
- CanExecute määrää onko komento suoritettavissa vai ei (e.CanExecute = True;)
- Executed suorittaa varsinaisen toiminnon
KeyGesture OpenKeyGesture = new KeyGesture( Key.O, ModifierKeys.Control); KeyBinding OpenCmdKeybinding = new KeyBinding( ApplicationCommands.Open, OpenKeyGesture); this.InputBindings.Add(OpenCmdKeybinding); CommandBinding OpenCmdBinding = new CommandBinding( ApplicationCommands.Open, OpenCmdExecuted, OpenCmdCanExecute); // yhdistetään komento ikkunaan this.CommandBindings.Add(OpenCmdBinding); public static RoutedCommand CustomRoutedCommand = new RoutedCommand(); //CommandBinding customCommandBinding = new CommandBinding( // CustomRoutedCommand, ExecutedCustomCommand, CanExecuteCustomCommand); // käytetään lyhyyden vuoksi samoja metodeja mitä open-komennon kanssa CommandBinding customCommandBinding = new CommandBinding( CustomRoutedCommand, OpenCmdExecuted, OpenCmdCanExecute); this.CommandBindings.Add(customCommandBinding); Button CustomCommandButton = new Button(); CustomCommandButton.Command = CustomRoutedCommand; void OpenCmdExecuted(object target, ExecutedRoutedEventArgs e) { String command, targetobj; command = ((RoutedCommand)e.Command).Name; targetobj = ((FrameworkElement)target).Name; MessageBox.Show("The " + command + " command has been invoked on target object " + targetobj); } void OpenCmdCanExecute(object sender, CanExecuteRoutedEventArgs e) { e.CanExecute = true; }
- Attached Behaviours in WPF
- Attached Properties
- Routed Events overview
- Understanding Routed Events and Commands In WPF
- Commanding Overview
- RoutedCommand class
- Drag & Drop Overview
- How can I drag and drop items between data bound ItemsControls?
- Wpf Drag & Drop behaviour
- Introduction to Attached Behaviors in WPF
Käyttäjien kommentit