14. November 2016
Sebastian Thurm
0

WPF-Tricks: Kontext-Menü per Behaviour

Behaviours bieten in WPF die Möglichkeit ein Stück Funktionalität in einer wiederverwendbare Komponente zu verpacken. Behaviours erlauben Anwendungsdesignern – mit wenig Aufwand – Änderungen am Programmverhalten zu bewirken ohne in den Programmcode einzugreifen. Die Entwickler stellen dafür beispielsweise Behaviours für Drag & Drop oder Touch-Interaktion bereit, die dann im „Blend“ einfach auf das entsprechende Element angewandt werden. Dieses Tutorial zeigt, wie sich mit Hilfe eines Behaviours ein Kontext-Menü erzeugen lässt.

Das Ziel:

Die Inhalte eine Liste sollen vom Nutzer kopiert werden können. Da wir die einzelnen Listenelemente nicht in editierbare Text-Boxen umwandeln möchten, soll ein Kontextmenü das Kopieren möglich machen:

WPF Inhalt kopieren

Kontext-Menü zum Kopieren des Inhaltes.

So geht’s:

Wir erstellen ein neues Behaviour indem wir von Behaviour<T> ableiten. Das Blend-Behaviour findet sich in System.Windows.Interactivity. Als Typ geben wir FrameworkElement an – damit funktioniert unser Behaviour auf praktisch allen Controls:

public class InhaltKopierenBahavior : Behavior<FrameworkElement>

Als erstes überschreiben wir OnAttached() und OnDetaching(). Hier können wir reagieren, wenn ein Behaviour hinzugefügt oder entfernt wird.

protected override void OnAttached()
{
 base.OnAttached();
}

protected override void OnDetaching()
{
 base.OnDetaching();
}

Das Behaviour bietet uns Zugriff auf das Element, an das es ‚attached‘ wurde. Dafür gibt es das Property AssociatedObject. Das AssociatedObject ist immer vom Typ, der bei der Klassendefintion angegeben wurde. (hier FrameworkElement). An das AssociatedObject ‚hängen‘ wir jetzt unser Kontext-Menü mit den gewünschten Optionen. In unserem Beispiel reicht uns der Befehl „Inhalt kopieren“. Dieser soll den angeklickten Text in die Zwischenablage kopieren. Im Beispiel wird der Menüeintrag auch gleich noch mit einem Icon versehen:

protected override void OnAttached()
{
 base.OnAttached();
            
 var uri = new Uri("copy-icon-256.png");

 var logo = new BitmapImage();
 logo.BeginInit();
 logo.DecodePixelWidth = 16;
 logo.UriSource = uri;
 logo.EndInit();

 var menuEintrag = new MenuItem
 {
  Header = "Inhalt kopieren",
  Icon = new Image { Source = logo }
 };
 menuEintrag.Click += MenuEintragOnClick;

 AssociatedObject.ContextMenu = new ContextMenu();
 AssociatedObject.ContextMenu.Items.Add(menuEintrag);
 AssociatedObject.PreviewMouseRightButtonDown += MouseDown;
}

Das Element, zu dem wir unser Kontext-Menü hinzufügen ist nicht zwingend das Element, dessen Inhalt wir kopieren wollen. Wir wollen ja den Inhalt eines ListViewItems und nicht den gesamten ListView kopieren. Das Behaviour auf jedes Listenelement anzuwenden, wäre aber unverhältnismäßig mühevoll. Dem AssociatedObject fügen wir deshalb noch einen Event-Handler hinzu. Beim Rechtsklick soll nicht nur das Menü geöffnet, sondern zugleich auch das „angeklickte“ Element ermittelt werden. Das „getroffene“ Element speichern wir uns in dem Field ‚_element‘.

private void MouseDown(object sender, MouseButtonEventArgs args)
{
 _element = args.MouseDevice.DirectlyOver;
 args.Handled = true;
}

Nun setzen wir die eigentliche Kopier-Funktionalität um, dafür bekommt der Menü-Eintrag einen entsprechenden Event-Handler. Wir gehen davon aus, dass das getroffene Element ein Text-Block ist. Wenn nicht, können wir ohnehin nichts sinnvoll in die Zwischenablage kopieren.

private void MenuEintragOnClick(object sender, RoutedEventArgs args)
{
 var textBlock = _getroffenesElement as TextBlock;
 if (textBlock != null)
 {
  Clipboard.SetDataObject(textBlock.Text);
 }
}

Zu guter Letzt wenden wir das Behaviour in unserer Anwendung an. Wichtig ist, dass auch der „Blend“ Namespace eingebunden ist: xmlns:i=“http://schemas.microsoft.com/expression/2010/interactivity“

<ListView>
 <i:Interaction.Behaviors>
  <behaviours:InhaltKopierenBahavior/>
 </i:Interaction.Behaviors>
</ListView>

 

Sebastian Thurm ist Dipl.-Ing. für Computervisualistik und arbeitet als Frontend-Entwickler und UX-Berater für die Saxonia Systems AG, Dresden. Er war in den letzten Jahren in verschiedenen Projekten im Bereich Handel, Industrie und Energiewirtschaft tätig.

Xing 

TeilenTweet about this on TwitterShare on Facebook0Share on Google+0Share on LinkedIn0