Willkommen auf myCSharp.de! Anmelden | kostenlos registrieren
 | Suche | FAQ

Hauptmenü
myCSharp.de
» Startseite
» Forum
» Suche
» Regeln
» Wie poste ich richtig?

Mitglieder
» Liste / Suche
» Wer ist online?

Ressourcen
» FAQ
» Artikel
» C#-Snippets
» Jobbörse
» Microsoft Docs

Team
» Kontakt
» Cookies
» Spenden
» Datenschutz
» Impressum

  • »
  • Community
  • |
  • Diskussionsforum
Trigger in CodeBehind erzeugen
OlafSt
myCSharp.de - Member



Dabei seit:
Beiträge: 78
Herkunft: HH

Themenstarter:

Trigger in CodeBehind erzeugen

beantworten | zitieren | melden

Hallo Freunde,

ich habe hier eine Fragestellung, die auch durch Google und StackOverflow unbeantwortet geblieben ist - womöglich habe ich aber auch falsch gefragt.

Ich habe hier eine WPF-Anwendung, die eine Landkarte zeichnet. Das ganze sieht wie folgt aus:


private void DrawElement(float[][][] data)
        {
            //Und los gehts mit Zeichnen
            List<PathFigure> li = new();

            for (int areaCount = 0; areaCount < data.Length; areaCount++)
            {
                //Startpunkt ermitteln
                Point startPoint = ScaleCoordToPoint(data[areaCount][0][0], data[areaCount][0][1]);
                PointsDrawn++;

                //PathGeometry zeichnen
                PathFigure path = new ();
                path.StartPoint = startPoint;

                for (int coordCount = 1; coordCount < data[areaCount].Length; coordCount++)
                {
                    Point pt = ScaleCoordToPoint(data[areaCount][coordCount][0], data[areaCount][coordCount][1]);
                    PointsDrawn++;
                    path.Segments.Add(new LineSegment(pt, true));
                }
                li.Add(path);
            }

            PathGeometry pg = new();

            for (int i = 0; i < li.Count; i++)
                pg.Figures.Add(li[i]);

            li.Clear();

            System.Windows.Shapes.Path p = new();
            p.Stroke = Brushes.Black;
            p.StrokeThickness = 1;
            p.Data = pg;
            TheCanvas.Children.Add(p);
        }

So weit, so gut, so funktionierts. Wenn jemand eine performantere Idee hat, bin ich aufgeschlossen - ist aber nicht die Frage.

Ich möchte nun einen OnMouseOver-Trigger (oder MouseEnter/MouseLeave) an jeden der einzelnen PathGeometry anhängen. Alle Beispiele, die ich bisher gesehen habe - inklusive hier im Forum - befassen sich mit dem Trigger innerhalb des XAML. Das ist okay, wenn man das Objekt im XAML erstellt, aber das ist hier nicht der Fall.

Doch wie mache ich das per Code-Behind ?

Bin für jeden Schubser dankbar.
private Nachricht | Beiträge des Benutzers
MrSparkle
myCSharp.de - Team

Avatar #avatar-2159.gif


Dabei seit:
Beiträge: 5.655
Herkunft: Leipzig

beantworten | zitieren | melden

Zitat von OlafSt
Doch wie mache ich das per Code-Behind ?

Man würde den Inhalt der Canvas im XAML an die Canvas binden. So könntest du auch Trigger definieren.
Siehe dazu [Artikel] MVVM und DataBinding

Man kann Trigger zwar auch im Code-behind definieren, aber das ist umständlich, schwer zu lesen und zu verstehen, und von WPF eigentlich auch nicht so vorgesehen. Daher wirst du auch kaum jemanden finden, der dir damit weiterhelfen könnte.
Weeks of programming can save you hours of planning
private Nachricht | Beiträge des Benutzers
jogibear9988
myCSharp.de - Member



Dabei seit:
Beiträge: 625
Herkunft: Offenau

beantworten | zitieren | melden

Muss es denn ein Trigger sein oder kannst du dich auch an die Events hängen?

Dann kannst ja einfach sowas


public static IEnumerable<T> FindVisualChilds<T>(DependencyObject depObj) where T : DependencyObject
{
    if (depObj == null) yield return (T)Enumerable.Empty<T>();
    for (int i = 0; i < VisualTreeHelper.GetChildrenCount(depObj); i++)
    {
        DependencyObject ithChild = VisualTreeHelper.GetChild(depObj, i);
        if (ithChild == null) continue;
        if (ithChild is T t) yield return t;
        foreach (T childOfChild in FindVisualChilds<T>(ithChild)) yield return childOfChild;
    }
}
von https://stackoverflow.com/a/978352/579623

verwenden und alle PathGeometrys suchen
cSharp Projekte : https://github.com/jogibear9988
private Nachricht | Beiträge des Benutzers
Gimmick
myCSharp.de - Member



Dabei seit:
Beiträge: 135

beantworten | zitieren | melden

Pro System.Windows.Shapes.Path oder pro PathGeometry?

Dem Path müsste man doch einen Style zuweisen können?

So in etwa


Style style = new Style(typeof(DeineKlasse));

Trigger trigger = new Trigger(){Property = DeineKlasse.IsMouseOver, Value = true/false});
Setter setter = new Setter(DeineKlasse.DasProperty, value);// statt value: new Binding(...falls vorhanden...) {Converter = new DeinConverter() }));

trigger.Setters.Add(setter);
style.Trigger.Add(trigger);

DasObjekt.Style = style;

PathGeometry hat aber kein Property für einen Style.
private Nachricht | Beiträge des Benutzers
MarsStein
myCSharp.de - Experte

Avatar #avatar-3191.gif


Dabei seit:
Beiträge: 3.170
Herkunft: Trier -> München

beantworten | zitieren | melden

Hallo,

Zitat
PathGeometry hat aber kein Property für einen Style.

Richtig. Der Style kommt erst mit dem FrameworkElement, und das ist Deinem Fall eben erst der Path.
Das bedeutet, man müsste allen einzelnen PathFigures eine eigene PathGeometry und diesen wiederum einen eigenen Path verpassen, statt alles zusammen in einem Path zu zeichnen.
Ich hab es jetzt nicht ausprobiert, aber dann müsste/sollte es auch mit Style und Trigger funktionieren.

Gruß, MarsStein
Non quia difficilia sunt, non audemus, sed quia non audemus, difficilia sunt! - Seneca
private Nachricht | Beiträge des Benutzers
OlafSt
myCSharp.de - Member



Dabei seit:
Beiträge: 78
Herkunft: HH

Themenstarter:

beantworten | zitieren | melden

Hallo Freunde,

ich hatte keine Gelegenheit bis gestern, da wieder bei zu gehen. Ich brauchte echt mal Abstand von C#-Code 😁

Durch den letzten Post von @MarsStein kam ich auf eine andere Idee: Das Path-Element hat einen MouseOver-, MouseEnter- und MouseLeave-Event, alle darunterliegenden (Geometry etc) haben das nicht. Anstatt also nur einen allumfassenden Path zu zeichnen, zeichne ich für jedes Element, das ein MouseOver-Event benötigt, einen eigenen Path.

Ergo schrumpft der Algorithmus auf dies hier zusammen:


private void DrawElement(float[][][] data, string KreisName = "")
        {
            //Und los gehts mit Zeichnen

            for (int areaCount = 0; areaCount < data.Length; areaCount++)
            {
                PathGeometry pg = new();
                //Startpunkt ermitteln
                Point startPoint = ScaleCoordToPoint(data[areaCount][0][0], data[areaCount][0][1]);
                PointsDrawn++;

                //PathGeometry zeichnen
                PathFigure path = new();
                path.StartPoint = startPoint;

                for (int coordCount = 1; coordCount < data[areaCount].Length; coordCount++)
                {
                    Point pt = ScaleCoordToPoint(data[areaCount][coordCount][0], data[areaCount][coordCount][1]);
                    PointsDrawn++;
                    path.Segments.Add(new LineSegment(pt, true));
                }
                pg.Figures.Add(path);

                System.Windows.Shapes.Path p = new();
                p.Stroke = Brushes.Black;
                p.StrokeThickness = 1;
                p.Data = pg;
                p.Tag = KreisName;

                //Events hier anklemmen
                p.MouseEnter += AreaEnter;
                p.MouseLeave += AreaLeave;
                TheCanvas.Children.Add(p);
            }
        }

Ich gebe einen string im Tag-Property mit, damit ich im Eventhandler erkennen kann, welches der Elemente das Event gefeuert hat.

Das fühlt sich für mich viel eher nach "Windows Forms-Style" an denn WPF, aber für dieses kleine Programm hier mag das gehen. Viel größer wird es eh nicht. So oder so, es funktioniert und ich danke für den Schubser in eine zielführende Richtung.

Äußerst interessant für mich wäre, wie man das "in reiner Lehre" in WPF wohl machen würde. Ich denke, das da konzeptionell schon anders herangegangen werden muss, ich habe aber keine blasse Idee, wie...
Dieser Beitrag wurde 1 mal editiert, zum letzten Mal von OlafSt am .
private Nachricht | Beiträge des Benutzers
Th69
myCSharp.de - Experte

Avatar #avatar-2578.jpg


Dabei seit:
Beiträge: 4.359

beantworten | zitieren | melden

MVVM entsprechend würde man die Path-Daten an das Canvas binden, und die Ereignisse dann als ICommand (evtl. mit Hilfe von AttachedCommandBehavior V2 aka ACB o.ä.).
private Nachricht | Beiträge des Benutzers
Palladin007
myCSharp.de - Member

Avatar #avatar-4140.png


Dabei seit:
Beiträge: 1.786
Herkunft: Düsseldorf

beantworten | zitieren | melden

Zitat von Th69
evtl. mit Hilfe von AttachedCommandBehavior V2 aka ACB o.ä.
Das gibt's auch von Microsoft:
https://github.com/Microsoft/XamlBehaviorsWpf
private Nachricht | Beiträge des Benutzers