C# Polymorphismus mit Standardklassen
lima-city → Forum → Programmiersprachen → Programmieren mit .NET & Mono
abfangen
base
button
code
dank
funktion
label
methode
mitarbeiter
panel
point
programm
sender
set
show
string
system
text
typ
windows
-
Hallo Community,
ich bin mir nicht sicher ob der Titel passend ist, aber ich habe folgendes Problem bei dem ich überhaupt nicht weiterkomme:
Ich möchte eine Klasse schreiben die von der Standardklasse Control erbt. Soweit so gut.
z.B.
public class ControlHolder : Control { public Control Holder(){ } public int get(){ return -1 } } usw...
nun würde ich z.B. gerne folgendes schreiben können:
Button btn = new ControlHolder(); TextBox txt = new ControlHolder(); Console.writeLine("Button: " + btn.get() + "TextBox" + txt.get())
Folgende Fehlermeldung erscheint (was auch klar ist):
Eine implizite Konvertierung vom Typ "System.Windows.Forms.Button" in "ControlHolder" ist nicht möglich.
doch wie geht es richtig? bitte um eure Vorschläge. :)
danke schonmal :)
Beitrag zuletzt geändert: 13.2.2014 17:42:50 von friedsei -
Diskutiere mit und stelle Fragen: Jetzt kostenlos anmelden!
lima-city: Gratis werbefreier Webspace für deine eigene Homepage
-
Hallo friedsei,
die folgende Klasse ermöglicht Dir zumindest die gewünschte Syntax:
class ControlHolder { Control ctrl; public ControlHolder(Control c) { this.ctrl = c; } public static implicit operator ControlHolder(Control c) { return new ControlHolder(c); } public int get() { return -1; } }
-
danke für die Antwort :)
kann ich dann auf diesen ControlHolder auch einen Eventhandler drauflegen? -
Hallo friedsei,
ich denke, dass Du unter 'drauflegen' meinst, dass Du die Ereignisse des gekapselten Controls abfangen kannst. Das geht leider nicht direkt.
Aber ich hätte noch eine andere Idee, nämlich schlicht die Erweiterung von Control um die gewünschten Funktionen:
public static class ControlExtensions { public static int getMyInt(this Control c) { return -1; } }
Damit kannst Du dann folgendes machen:
Button btn = new Button(); TextBox txt = new TextBox(); Console.writeLine("Button: " + btn.getMyInt() + "TextBox" + txt.getMyInt());
oder aber:
Control btn = new Button(); Control txt = new TextBox(); Console.writeLine("Button: " + btn.getMyInt() + "TextBox" + txt.getMyInt());
Und Event-Handler kannst Du wie gewohnt einbauen.
Der Nachteil ist aber, dass man keine neuen Member-Variablen einführen kann. -
danke nochmal. :)
hast du noch eine idee, wie ich das mit den member-variablen machen kann? -
Hallo friedsei,
jetzt muss ich Dich leider ein wenig enttäuschen. Man muss sich halt entscheiden, ob man die statischen Erweiterungen nutzt, was einem die Events erhält oder ob man die Objekte kapselt und dadurch beliebige Member-Variablen einführen kann.
Falls es keine Option ist den ControlHolder einfach mit einer getControl()-Methode auszustatten und das dann zur Installation der Event-Handler zu benutzen, dann kannst Du ja mal kurz beschreiben, welches Ziel Du eigentlich verfolgst.
Vielleicht gibt es ja einen anderen Weg der Dein zugrunde liegendes Problem löst. -
Es ist recht schwierig zu beschreiben,
Ich muss für mein Matura(Abitur) Projekt Buttons, Textboxen, Labels usw. per Drag & Drop in einem Panel platzieren(so ähnlich wie Windowbuilder) um ein Testprogramm zu konfigurieren, den Buttons TextBoxen usw. werden Werte und Funktionen zugewiesen . Diese gefertigte Oberfläche wird dann mit den Funktionen gespeichert und von einem Mitarbeiter der Testabteilung wieder geöffnet. Der Test-Mitarbeiter testet nun mit dieser Oberfläche ein Produkt der Firma, z.B. einen Motor.
Bis jetzt muss ich ständig abfragen welchen Typ das ausgewählte Control hat (siehe Code Bsp. 1), um eine Funktion wie z.B. getName() auszuführen. Ich würde stattdessen gerne ein Control haben (das aber gleichzeitig ein button bzw. textfeld usw. ist), dass diese Funktionen wie getName() usw. ausführen kann (Auch um das Programm leichter zu erweitern).
//Code Bsp. 1 private void ControlListener(object sender, EventArgs e) { if (sender.GetType().Equals(typeof(MyButton))){ MyButton curr = (MyButton) sender; MessageBox.Show("Name: " + curr.getName()); } else if (sender.GetType().Equals(typeof(MyTextBox))) { MyTextBox curr = (MyTextBox) sender; MessageBox.Show("Name: " + curr.getName()); } else if (sender.GetType().Equals(typeof(MyTrackBar))) { MyTrackBar curr = (MyTrackBar) sender; MessageBox.Show("Name: " + curr.getName()); } }
Also ich möchte mir die Type-Castings ersparen. -
Hallo friedsei,
der erste Gedanke, der mir kam, als ich Dein Posting gelesen habe war der folgende:
Mann kann ja eine Klasse 'MyControl' schaffe, die von Panel abgeleitet ist und in die man die gewünschten Controls einfach einbettet. Dann kann man beliebig viele Methoden, Properties und Member-Variablen hinzufügen und es sieht für den Benutzer wie ein das jeweilige normale Control aus.
Da es ja quasi ein abgespeckter GUI-Editor werden soll, benötigt man auch nicht alle Properties und Eigenschaften des eingebetteten Controls sondern nur eine kleine Teilmenge davon. Bei einem Button wird es vermutlich reichen, wenn man den Text ändern kann und wenn man das Click-Event abfangen kann. Damit würde sich der Aufwand in Grenzen halten.
Hier habe ich es mal ein wenig anprogrammiert:
using System; using System.Drawing; using System.Text; using System.Windows.Forms; namespace MyControlTest { abstract class MyControl : Panel { protected Control embeddedControl; public string MyName { get; set; } public Control EmbeddedControl { get { return embeddedControl; } } public MyControl(Control ctrl) { embeddedControl = ctrl; ctrl.Location = new Point(0, 0); ctrl.Size = this.Size; ctrl.Anchor = AnchorStyles.Top | AnchorStyles.Left | AnchorStyles.Right | AnchorStyles.Bottom; Controls.Add(ctrl); } } class MyLabel : MyControl { public MyLabel() : base(new Label()) { } public override string Text { get { return ((Label)embeddedControl).Text; } set { ((Label)embeddedControl).Text = value; } } } class MyButton : MyControl { public new event EventHandler Click; public MyButton() : base(new Button()) { Button btn = (Button)this.embeddedControl; btn.Click += Button_Click; } public override string Text { get { return ((Button)EmbeddedControl).Text; } set { ((Button)EmbeddedControl).Text = value; } } private void Button_Click(object sender, EventArgs e) { Click(this, EventArgs.Empty); } } class MyTextBox : MyControl { public MyTextBox() : base(new TextBox()) { } public override string Text { get { return ((TextBox)EmbeddedControl).Text; } set { ((TextBox)EmbeddedControl).Text = value; } } } public partial class Form1 : Form { public Form1() { InitializeComponent(); MyLabel lbl = new MyLabel(); lbl.MyName = "Label"; lbl.Location = new Point(0, 0); lbl.Size = new System.Drawing.Size(100, 24); lbl.Text = "Hallo"; Controls.Add(lbl); MyButton btn = new MyButton(); btn.MyName = "Schaltfläche"; btn.Location = new Point(100, 0); btn.Size = new System.Drawing.Size(100, 24); btn.Text = "Welt"; btn.Click += Button_Click; Controls.Add(btn); MyTextBox txt = new MyTextBox(); txt.MyName = "Textfeld"; txt.Location = new Point(0, 24); txt.Size = new System.Drawing.Size(100, 24); txt.Text = "Änder mich!"; Controls.Add(txt); } private void Button_Click(object sender, EventArgs e) { MessageBox.Show("Juhu!"); } } }
Dann ist mir aber aufgefallen, das Deine Problemstellung dadurch vermutlich nicht wirklich gelöst wird.
Dein Programm muss ja zwei Modi haben: Entwurfsmodus und Ausführungmodus.
Für den Ausführungmodus ist das da oben ja in Ordnung, aber im Entwurfsmodus soll ein Button zwar wie ein Button aussehen, darf sich aber eigentlich nicht so verhalten. Stattdessen will man ihn verschieben und z.B. die Größe ändern können. D.h. man muss die MouseDown, MouseMove und MouseUp Events abfangen können um einen Drag zu ermöglichen. Das ist aber mit den Standardcontrols, wenn überhaupt, nur über schwierige Umwege machbar.
Für den Entwurfsmodus müsste man eigentlich ein extra Control entwickeln, was die Designfunktionalität bereitstellt. Dann würde das was werden. -
Hallo Darkpandemic :)
erstmal danke für deine hilfe. Ich werde es heute ausprogrammieren. Ich glaube das löst mein Problem.
Drag & Drop habe ich mit meiner Lösung bereits bewältigt. Es ist relativ simpel Standard-Steuerelemente mit Drag&Drop zu verschieben. Ich hoffe es ist mit deiner Lösung auch so simpel ist, aber da werde ich schon eine Lösungsmöglichkeit finden.
Ich hab noch eine Frage.
Wenn ich ein MouseDownEventhandler zum Button hängen will, dann würde ich das do machen:
namespace FormTest { class MyButton : MyControl{ public new event EventHandler Click; public new event MouseEventHandler MouseDown; //<== geändert public MyButton() : base(new Button()) { Button btn = (Button) this.embeddedControl; btn.Click += Button_Click; btn.MouseDown += Button_Mouse_Down; //<== geändert } public override string Text { get { return ((Button) EmbeddedControl).Text; } set { ((Button) EmbeddedControl).Text = value; } } private void Button_Click(object sender, EventArgs e) { Click(this, EventArgs.Empty); } private void Button_Mouse_Down(object sender, MouseEventArgs e) { //<== geändert MouseDown(this, MouseEventArgs.Empty); //<== geändert } } }
aber ich bekomme folgende Fehler, wobei ich keine Ahnung habe wie ich ihn beheben kann,
Der Delegat 'System.Windows.Forms.MouseEventHandler' enthält einige ungültige Argumente.
Argument '2': Konvertierung von 'System.EventArgs' in 'System.Windows.Forms.MouseEventArgs' nicht möglich.
Ich habe bereits einiges versucht und im Internet recherchiert. jedoch komme ich nicht auf die Problemlösung.
Beitrag zuletzt geändert: 27.2.2014 10:52:14 von friedsei -
Hallo friedsei,
ironischerweise hat MouseEventArgs.Empty den Datentyp EventArgs, d.h. Du musst einen Cast einfügen:
private void Button_Mouse_Down(object sender, MouseEventArgs e) { MouseDown(this, (MouseEventArgs)MouseEventArgs.Empty); }
Aber eigentlich kannst Du auch die originalen Ereignisdaten weiterreichen, dann stehen diese auch im nächsten Handler zur Verfügung:
private void Button_Mouse_Down(object sender, MouseEventArgs e) { MouseDown(this, e); }
Das kann man bei allen anderen Ereignissen dann analog machen.
-
dankeschön darkpandemic :D
aber wenn ich die Ereignisdaten mitgebe, bekomme ich einen "Object null" Fehler. Also werde ich die erste Methode verwenden :)
Beitrag zuletzt geändert: 28.2.2014 18:09:02 von friedsei -
Diskutiere mit und stelle Fragen: Jetzt kostenlos anmelden!
lima-city: Gratis werbefreier Webspace für deine eigene Homepage