Laden...

Eigene Button Klasse erstellen

Erstellt von ZeraTFK vor 13 Jahren Letzter Beitrag vor 13 Jahren 8.810 Views
Z
ZeraTFK Themenstarter:in
4 Beiträge seit 2011
vor 13 Jahren
Hinweis von herbivore vor 13 Jahren

Warnung an Leser, die ähnliches vorhaben: Der Code von ZeraTFK ist aus verschiedenen Gründen fehlerhaft und auch sonst nicht empfehlenswert. Bessere Lösungen finden ihr in den Links weiter unten.

Eigene Button Klasse erstellen

Hi,

Ich habe da mal eine Frage.

Ich hatte vor ein Programm zu schreiben, welches aus einem einzigen Menü besteht.
Als erstes wollte ich eine eigene Klasse erstellen, welche eines Button gleicht.
Ich erzeuge auf der Hauptform das Objekt und dieses beinhaltet Folgende eigenschaften:

 public Image CImage { get; set; }
        public Image CImage_Hover { get; set; }
        public Image CImage_Push { get; set; }
        public Buttonstate Bstate { get; set; }
        public String CName { get; set; }
        public Point CPos { get; set; }
        public Size CSize { get; set; }
        Thread Event_Thread;

Nun brauche ich ja die Events die auch ein normaler Button hat.
Meine erste frage ist, sollte ich von Controls erben?

Ich dachte mir nein und habe eigene Events gemacht.
Da dies mein erstes mal ist, das ich Events mache, bin ich mir auch recht unsicher ob es stimmt was ich da gemacht habe.

Der Button hat nun diese Events:

 public event EventHandler<MouseEventArgs> On_MyMouseMove;
        public event EventHandler<MouseEventArgs> On_MyMouseLeave;
        public event EventHandler<MouseEventArgs> On_MyMouseDown; 

Diese werden aber komischer weiße nur einmal im Programm ausgeführt und dann nie wieder, also dachte ich ich muss diese in ein Thread packen welcher im Konstruktor des Buttons gestartet wird.

Das wäre dann der Thread

 public void MyThread()
        {
            while (true)
            {
                //hier wird mit dem Server connected
                //dann musst du sagen, dass jetzt das Event ausgelöst werden soll
                if (this.On_MyMouseMove != null) //ist ein EventHandler zugewiesen?
                {
                    Point last_p = new Point(0, 0);

                    //GetCursorPos(ref MousePoint);
                    if (Cursor.Position.X >= CPos.X && Cursor.Position.X <= CPos.X + CSize.Width &&
                        Cursor.Position.Y >= CPos.Y && Cursor.Position.Y <= CPos.Y + CSize.Height)
                    {
                        if (last_p.X != Cursor.Position.X && last_p.Y != Cursor.Position.Y)
                        {
                            MouseEventArgs m = new MouseEventArgs(Button.MouseButtons, 0, Button.MousePosition.X, Button.MousePosition.Y, 0);

                            On_MyMouseMove(this, m);
                        }
                    }

                    last_p = new Point(Cursor.Position.X, Cursor.Position.Y);

                    Thread.Sleep(1);
                }


                if (this.On_MyMouseLeave != null) //ist ein EventHandler zugewiesen?
                {

                    //GetCursorPos(ref MousePoint);
                    if (Cursor.Position.X < CPos.X || Cursor.Position.X > CPos.X + CSize.Width ||
                        Cursor.Position.Y < CPos.Y || Cursor.Position.Y > CPos.Y + CSize.Height)
                    {
                        if (Bstate == Buttonstate.HOVER)
                        {
                            MouseEventArgs m = new MouseEventArgs(Button.MouseButtons, 0, Button.MousePosition.X, Button.MousePosition.Y, 0);

                            On_MyMouseLeave(this, m);
                            Bstate = Buttonstate.IDLE;
                        }
                    }
                }


                if (this.On_MyMouseDown != null) //ist ein EventHandler zugewiesen?
                {

                    //GetCursorPos(ref MousePoint);
                    if (Cursor.Position.X >= CPos.X && Cursor.Position.X <= CPos.X + CSize.Width &&
                        Cursor.Position.Y >= CPos.Y && Cursor.Position.Y <= CPos.Y + CSize.Height)
                    {
                        if (Bstate == Buttonstate.HOVER && Button.MouseButtons == MouseButtons.Left)
                        {
                            MouseEventArgs m = new MouseEventArgs(Button.MouseButtons, 0, Button.MousePosition.X, Button.MousePosition.Y, 0);

                            On_MyMouseDown(this, m);
                        }
                    }
                }
                Thread.Sleep(1);
            }
        }

In der Hauptform erzeuge ich den Button und teile die Evente zu

CloseButton.On_MyMouseMove += new EventHandler<MouseEventArgs>(CloseButton_On_MyMouseMove);

            CloseButton.On_MyMouseLeave += new EventHandler<MouseEventArgs>(CloseButton_On_MyMouseLeave);

            CloseButton.On_MyMouseDown +=new EventHandler<MouseEventArgs>(CloseButton_On_MyMouseDown);

Das Move und Leave Event klappt perfekt... Die Grafiken ändern sich sobald das Event eintritt.

Nun mein eigentliches Problem:
Ich erzeuge einen CloseButton, welcher bei dem OnClick Event aus dem Thread des Buttons auf den Hauptthread springt und da folgende Funktion ausführt:

public void CloseButton_On_MyMouseDown(object sender, MouseEventArgs e)
        {
            Close();
        }

Doch es kommt immer die Meldung:> Fehlermeldung:

Ungültiger threadübergreifender Vorgang: Der Zugriff auf das Steuerelement Form1 erfolgte von einem anderen Thread als dem Thread, für den es erstellt wurde.

Mache ich etwas an den Events falsch, da ich nicht glaube das Events in ein Thread müssen.. da wird mein Fehler sein oder?

Oder kann ich per delegaten die Hauptform Closen?
Habe das schon versucht doch ohne erfolg?!?

Danke im vorraus

Mit freundlichen Grüßen
Zera!

A
118 Beiträge seit 2009
vor 13 Jahren

Hallo,

Ich habe den Code mal überflogen und hab das Gefühl, dass du etwas falsch verstanden hast.

Wieso nicht von Control erben?
Welchen Sinn sollen den Thread.Sleep und while(true) haben?

Ich würde das Ganze nochmal ordentlich überarbeiten, bzw. komplett neu schreiben.

Trotzdem, als Antwort auf dein Problem:
[FAQ] Controls von Thread aktualisieren lassen (Control.Invoke/Dispatcher.Invoke)

Mfg
Aratar

Z
ZeraTFK Themenstarter:in
4 Beiträge seit 2011
vor 13 Jahren

Ich habe es schon versucht von Control zu erben, doch wenn ich dann alles eingestellt habe, ist meine eigene Grafik die ich aus der Klasse erhaus male weg und stattdessen ist da ein Graues viereck wo eigntlich die Grafik des Buttons ist.

Und das Sleep habe ich eingebaut, da ich so CPU Leistung erhalten möchte.

Danke für deine schnelle Antwort! Ich werde es mal damit versuchen.

4.931 Beiträge seit 2008
vor 13 Jahren

Hallo ZeraTFK,

ich kann mich Aratar nur anschließen: dein Code ist kompletter Unsinn.

Aber trotzdem noch mal die Nachfrage: es geht um WinForms, oder?
Dann darfst du den UI-Thread nicht blockieren, s.a. [FAQ] Warum blockiert mein GUI? und auch keine Controls außerhalb des UI-Threads erzeugen.

Um einen eigenen Button (in WinForms) zu erzeugen, gibt es viele andere Möglichkeiten, s. z.B.
http://www.codeproject.com/KB/buttons/xp-style_button.aspx
http://www.codeproject.com/KB/buttons/XCtrls.aspx
http://www.codeproject.com/KB/buttons/RoundButton_csharp.aspx
http://www.codeproject.com/KB/buttons/RoundButton.aspx

Edit: ein Beispiel für einen dynamischeren Button (mit Animation) gibt es unter
http://www.codeproject.com/KB/buttons/PulseButton.aspx

Du brauchst also weder eigene Threads noch die Standardevents nachzubauen...

Hauptansatz ist einfach das Überschreiben der Paint-Methode, s.a. [Tutorial] Zeichnen in Windows-Programmen (Paint/OnPaint, PictureBox)

Z
ZeraTFK Themenstarter:in
4 Beiträge seit 2011
vor 13 Jahren

Ich habe es nun allein hinbekommen, dank des Links von Aratar.
Musste den Code auch gar nicht großartig umändern und musste dennoch nicht Erben.
Es Funktioniert besser als ich dachte also kann der Code auch gar nicht so Unsinnig sein 😉

4.931 Beiträge seit 2008
vor 13 Jahren

Doch, deine gesamte Thread-Methode ist überflüssig und daher unsinnig!
Außerdem laufen die ausgelösten Events dann auch im Nebenthread, d.h. in der Event-Methode müßte man zum Zugriff auf die UI dann auch wieder 'invoken'.
Und 1000 mal pro Sekunde die Mausposition per Polling abzufragen, ist auch mehr als schlechter Programmierstil.
Und ich tippe darauf, daß du für jeden Button wahrscheinlich diese Thread-Methode aktiv aufrufst (d.h. je mehr Buttons, um so mehr Threads -> Performance-Killer).

Ich weiß nicht, woher du diesen Programmierstil hast, aber dieser Beitrag hat wirklich Potential auf den Titel "DAU des Monats" bzw. Coding Styles Horror 😉