2017-06-27 2 views
2

Ich benutze C#, und ich habe ein Projekt, das viele PictureBox-Schaltflächen instanziiert. Ich habe auch alle Click, Hover, MouseUp, MouseDown Event-Methoden programmiert. Wie rufe ich eine Methode aus einem String-Namen, so dass ich nicht alle von Hand schreiben muss? Vielen Dank im Voraus, CarsonAufruf einer Methode aus einem String-Namen

Dictionary<string, PictureBox> buttonList = new Dictionary<string,PictureBox>(); 
string buttonName = "button_file"; 

buttonList[buttonName].Click += new EventHandler(buttonName + "_click"); 

public void button_file_click(object sender, EventArgs e) 
{ 
    // do on click stuff here 
} 
+1

Mit Reflexion (https://stackoverflow.com/questions/1121441/addeventhandler-using-reflection) würde Ihre Frage beantworten, aber die meisten wahrscheinlich, dass Sie möchte das nicht tun und stattdessen deinen Code umgestalten, um weniger Handler zu haben ... –

Antwort

0

Von Ihrem Beispielcode, ich nehme an, Sie wollen, dass sie alle button_file_click nennen.

In diesem Fall setzen gerade die Eventhandler zu dieser Methode:

buttonList[buttonName].Click += new EventHandler("button_file_click");

+0

Ich denke nicht, dass das in seinem Zweck funktionieren würde. Er möchte eine Methode nach String-Namen aufrufen können, anstatt die Methodenaufrufe hart zu codieren. – Sometowngeek

+0

SomeTowngeek das ist wahr. Ich möchte es nicht hart codieren lassen. – Carson

2

, wenn Sie die Eigenschaft Name der Schaltfläche festlegen, können Sie so:

buttonList[buttonName].Name = buttonName; 
buttonList[buttonName].Click += ButtonClick; 

und nur One metode hanle alle Tasten klicken, aber in Übereinstimmung mit ihrem Namen:

public void ButtonClick(object sender, EventArgs e) 
{ 
    var btn = (Button)sender; 
    btn.Text = btn.Name; //only for demo 
} 

aber Sie können Ihre eigene Methode vollständig schreiben:

buttonList[buttonName].Click += (s,e)=> clickEvent(buttonList[buttonName], buttonName); 

dies ist nur eine kurze Lambda-Funktion, die die Parameter entsprechend der Click-Ereignis singature akzeptiert und Ihre benutzerdefinierte Funktion ausgelöst, die clickEvent:

public void clickEvent(Button thePressedButton, string nameOfPresedButton) 
{ 
    thePressedButton.Text = btn.nameOfPresedButton; //only for demo 
} 
+0

In diesem Fall müsste er also if-else-Anweisungen oder einen Schalterfall verwenden, um die Schaltflächen zu unterscheiden und auf korrekte Methoden zu verweisen, oder? – Sometowngeek

+0

@Sometowngeek Nicht unbedingt. Zum Beispiel, wenn jede Taste gedrückt wird, ändert sich der Wert eines Elements in einem 'Wörterbuch', niemand 'if' wird benötigt. – dovid

+0

Also, ist dies kombiniert alle meine Click-Ereignisse in eine Methode (clickEvent), und zu sehen was (NameOfPresedButton) ich gedrückt habe? Ich denke, ich hätte gerne individuelle Methoden für die Click-Events. Dieses Programm hat grundsätzlich eine makeButtonAtPoint() -Methode und ich habe eine Zeile hartcodierte Informationen {makeButtonAtPoint ("button_file", 1, 1, true);} – Carson

0

Ein Methodenname reicht nicht aus ... Sie benötigen auch einen Klassennamen ... aber unter der Annahme, dass die Methode zur aktuellen Klasse gehört (this), können Sie Reflection dazu verwenden:

public void ExecuteMethod(string methodName) 
{ 
    var methodInfo = this.GetType().GetMethod(methodName); 
    methodInfo.Invoke(this, new [] {}); 
} 

Sie können das obige Ereignis jedoch nicht zuordnen, weil es nicht der richtige Delegattyp ist. Die meisten Event-Handler benötigen eine sender und eine EventArgs. So Ihr Code Arbeit machen Sie ein wenig mehr Leim bräuchten:

Dictionary<string, PictureBox> buttonList = new Dictionary<string,PictureBox>(); 
string buttonName = "button_file"; 

buttonList[buttonName].Click += GetHandler(buttonName + "_click"); 

public Action<object, EventArgs> GetHandler(string handlerName) 
{ 
    var methodInfo = this.GetType().GetMethod(handlerName, new Type[] {typeof(object), typeof(EventArgs)}); 
    return new Action<object, EventArgs> (sender, eventArgs) => methodInfo.Invoke(this, new [] {sender, eventArgs}); 
} 

Die Idee dabei ist, dass GetHandler eine Action mit der rechten Unterschrift zurückgibt (ein Objekt zu akzeptieren und eine EventArgs, in dieser Reihenfolge), das ist, geschrieben als Action<object, EventArgs>. Die Methode GetHandler verwendet Reflektion, um die richtige Methode in der aktuellen Klasse zu finden. Anschließend wird ein Lambda-Ausdruck erstellt, der die Methode über Reflection aufruft und die Argumente als Array weiterleitet.

Das obige ist natürlich nur ein Beispiel ... es wäre wahrscheinlich besser, Ihre Delegierten in einem statischen Wörterbuch zu speichern, das berechnet wird, wenn die Seite zum ersten Mal geladen wird.

Wenn Sie nach Ereignishandhabungsflexibilität suchen, die auf einem Laufzeitparameter basiert, ist ein besserer Ansatz wahrscheinlich, die Command event zu verwenden, die es Ihnen ermöglicht, eine Zeichenfolge an den Handler zu übergeben, der dann einen anderen verwenden kann Aktion abhängig vom Inhalt der Zeichenfolge. Auf diese Weise können Sie die Handler-Referenz fest codieren, aber softcodieren, was sie tut.

+0

Es empfiehlt sich, ein Wörterbuch im Voraus vorzubereiten und nicht Reflection erneut und agian (und sogar zweimal in jedem Ereignis)) – dovid

+0

Das Befehlsereignis könnte funktionieren. Obwohl ich nach einzelnen Methodenaufrufen von String-Namen suchte, glaube ich, dass das Befehlsereignis funktionieren wird. Danke – Carson

+0

Kann ich die .Command-Eigenschaft zu einer PictureBox hinzufügen? Welchen Namespace verwendet der Befehl und CommandName? – Carson

0

Sie können Reflektion verwenden, um die Methode einer Klasse nach Name zu suchen und dann einen Event-Handler-Delegaten mit dieser Methode zu erstellen.Zum Beispiel:

void bindHandler(string buttonName) 
     { 
      string methodName = buttonName + "_click"; 
      System.Reflection.MethodInfo m = this.GetType().GetMethods().FirstOrDefault(x => x.Name == buttonName + "_click"); 
      PictureBox button = buttonList[buttonName]; 
      Delegate handler = Delegate.CreateDelegate(typeof(EventHandler), this, m); 
      button.Click += (EventHandler)handler; 
     } 

Fulling Arbeitscode:

namespace WindowsFormsApp1Cs 
{ 
    public partial class Form1 : Form 
    { 
     public Form1() 
     { 
      InitializeComponent(); 
     } 

     private void Form1_Load(object sender, EventArgs e) 
     { 
      MyClass c = new MyClass(); 
      foreach (var item in c.buttonList) 
      { 
       this.Controls.Add(item.Value); 
      } 
     } 
    } 
    public class MyClass 
    { 
     public Dictionary<string, PictureBox> buttonList; 
     public delegate void MyClickHandler(object sender, EventArgs e); 
     public MyClass() 
     { 
      buttonList = new Dictionary<string, PictureBox>(); 
      buttonList.Add("button_file_1", new PictureBox() { Width = 100, Height = 100, Name = "button_file_1", Anchor = AnchorStyles.Top | AnchorStyles.Left, Top = (buttonList.Count * 100) + 10, Left = 10, ImageLocation="0.jpg" }); 
      buttonList.Add("button_file_2", new PictureBox() { Width = 100, Height = 100, Name = "button_file_2", Anchor = AnchorStyles.Top | AnchorStyles.Left, Top = (buttonList.Count * 100) + 10, Left = 10, ImageLocation = "0.jpg" }); 
      buttonList.Add("button_file_3", new PictureBox() { Width = 100, Height = 100, Name = "button_file_3", Anchor = AnchorStyles.Top | AnchorStyles.Left, Top = (buttonList.Count * 100) + 10, Left = 10, ImageLocation = "0.jpg" }); 
      foreach (var item in buttonList) 
      { 
       bindHandler(item.Key); 
      } 
     } 
     void bindHandler(string buttonName) 
     { 
      string methodName = buttonName + "_click"; 
      System.Reflection.MethodInfo m = this.GetType().GetMethods().FirstOrDefault(x => x.Name == buttonName + "_click"); 
      PictureBox button = buttonList[buttonName]; 
      Delegate handler = Delegate.CreateDelegate(typeof(EventHandler), this, m); 
      button.Click += (EventHandler)handler; 
     } 
     public void button_file_1_click(object sender, EventArgs e) 
     { 
      Debug.WriteLine("button_file_1_click"); 
     } 
     public void button_file_2_click(object sender, EventArgs e) 
     { 
      Debug.WriteLine("button_file_2_click"); 
     } 
     public void button_file_3_click(object sender, EventArgs e) 
     { 
      Debug.WriteLine("button_file_3_click"); 
     } 
    } 
} 
+0

Beachten Sie, dass der zweite Parameter (this) der Methode eine Instanz eines Objekts sein sollte, für das die Methode m deklariert ist. Delegate-Handler = Delegate.CreateDelegate (typeof (EventHandler), dies, m) –

+0

Dies funktioniert. Danke, Carson – Carson

+0

Danke. Wenn es Ihr Problem löst, können Sie es als die akzeptierte Antwort markieren, um anderen zu helfen, die das gleiche Problem haben, das diese Frage liest. –

Verwandte Themen