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)

routed_event_malli-esimerkki (routed_event_malli.zip)

AttachedBehaviours-esimerkki (AttachedBehaviours.zip)

Commanding-esimerkki (Commanding.zip)

DragDrop-esimerkki (DragDrop.zip)

Attached Behaviours / Properties

AttachedBehaviours-esimerkki (AttachedBehaviours.zip)

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));

        // Täällä tehdään varsinaiset muutokset kontrollin toiminnallisuuteen
        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

DragDrop-esimerkki (DragDrop.zip)

drag drop in wpf explained end to end

Drag & Dropin perustoiminnot voi tehdä Attached Propertyn avulla. kts. luentomalli.

Toimintaa selventää parhaiten Walkthrough: Enablind Drag and Drop on a User Control

Routed Events

routed_event_malli-esimerkki (routed_event_malli.zip)

Routed Event kulkee elementtipuussa ylös tai alaspäin eli saman tapahtuman voi käsitellä useampikin elementti eikä vain ainoastaan yksi 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(OmaButton));
 
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

Commanding-esimerkki (Commanding.zip)

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>
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;
}

Käyttäjien kommentit

Kommentoi Lisää kommentti
Kurssimateriaalien käyttäminen kaupallisiin tarkoituksiin tai opetusmateriaalina ilman lupaa on ehdottomasti kielletty!
http://appro.mit.jyu.fi/gko/luennot/luento14/
© Tommi Lahtonen (tommi.j.lahtonen@jyu.fi) <http://hazor.iki.fi/>
2016-01-13 18:19:13
Informaatioteknologia - Jyväskylän yliopiston informaatioteknologian tiedekunta