GUI über Console steuern?


gott_ad

Grünschnabel
Hi,

ich hab da mehr ein konzeptionelles Problem. Also ich habe ein Programm gebaut, dass ein Fenster anzeigt, dass fast leer ist. Links in diesem Fenster ist ne ToolBar mit 3 Buttons. Deren Beschriftung ist "Rot", "Gruen", "Blau". Wenn ich einen der Buttons drücke und dann auf den Hintergrund, zeichnet mir das Programm ein Kästchen in angegebener Farbe.
So weit, so gut (also das Programm ist natürlich viel viel komplizierter, aber ich hab es jetzt mal vereinfacht).

Jetzt hab ich mir überlegt, hätte ich auch gerne zusätzlich eine Steuerung über Console. D.h. ich habe nicht nur die Möglichkeit mit Maus zu aggieren, sondern es soll auch alles über Console gehen. In die schreibe ich dann: "add gruen 120 200" -> d.h. er würde einen grünen kasten an die Stelle 120, 200 auf dem Fenster setzen.

Die Frage ist jetzt, wie man das schlau realisiert? Ich könnte jetzt einfach einen Befehlssatz erstellen, aber das find ich langweilig. Wie wäre es mit Reflection? Also eine Klasse durchsucht sich selbst und gibt seine Funktionsnamen aus oder ich versuch die Befehle direkt auf eine Funktion anzuwenden? Dann könnte er allerdings auch JEDE Funktion starten (was ja nicht sinnvoll wäre). Außerdem muss man ja vor dem nutzen von Invoke etc. erst ein Objekt dieser Klasse erstellen. Da weiß ich auch nicht wie das dann läuft, denn die eigentliche Instanz existiert ja schon.

Also, falls jemand sowas schon mal gemacht hat oder mir einen Tip geben möchte, oder weitere Fargen hat, wäre ich sehr dankbar.

gruß Gott_aD
 

gott_ad

Grünschnabel
Hi,

ich bins wieder. Hab mal selbst ein paar Experimente gestartet. Befehle einer Klasse per Refelction aufzurufen funktioniert tadellos. Hier mal das Beispiel dazu:
Code:
using System;
using System.Collections.Generic;
using System.Reflection;
using System.Text;

namespace Console_reflection_test {
              class einstieg {
		static void Main(string[] args) {
			new Program();
		}
	}


	public class Program {
		private bool ErwarteEingabe;

		public void init() {
			Console.WriteLine("Funktion INIT");
		}

		public void help() {
			Console.WriteLine("Liste von Befehlen:");
			Type dieseKlasse = this.GetType();
			object dummy = new object();
			Type dummyKlasse = dummy.GetType();
			foreach (MemberInfo mi in dieseKlasse.GetMethods()) {
				bool gleich = false;
				foreach (MethodInfo mi_dummy in dummyKlasse.GetMethods()) {
					if (mi.Name == mi_dummy.Name) { gleich = true; }
				}
				if ((!gleich)) { Console.WriteLine("\t" + mi.Name); }
			}
		}

		public Program() {
			ErwarteEingabe = true;
			Console.Title = "Konsolen Test";
			help();
			konsole();
		}

		private void konsole() {
			string zeile;
			Type dieseKlasse = this.GetType();
			while (ErwarteEingabe) {
				Console.Write(">");
				zeile = Console.ReadLine();
				string[] teile = zeile.Split(' ');
				object[] uebergabe = new object[teile.Length-1];
				int count = -1;
				foreach(string s in teile){
					if (count >= 0) {
						uebergabe[count] = s;
					}
					count++;
				}
				MethodInfo mi = null;
				mi = this.GetType().GetMethod(teile[0]);
				if (mi == null) {
					Console.WriteLine("FEHLER: Funktion nicht gefunden!");
				} else {
					try {
						mi.Invoke(this, uebergabe);
					}catch (Exception ex2) {
						Console.WriteLine("FEHLER: Uebergabeparameter sind falsch! (" + ex2.Message + ")");
					}
				}
			}
		}

		public void cu() {
			ErwarteEingabe = false;
		}

		public void add(string a, string b) {
			Console.WriteLine(Convert.ToInt32(a) + Convert.ToInt32(b));
		}
	}
}
Alle "public" Funktionen werden zu Anfang selbstständig ausgelesen (bzw. bei Eingabe von "help") und dann auch aufgerufen (wenn der Funktionsname in der konsole eingeben wurde). Einziger Nachteil ist, dass alle Parameter als strings ankommen, aber damit kann man leben ;-) (z.b. bei "add 5 3")

Jetzt gibt es aber Probleme mit der GUI. Diese läuft ja in einem eigenen Thread (Application.Run). Wenn ich also jeweils eins der beiden sachen (GUI oder Konsole) in einen extra Thread packe (oder beide in einen extra Thread) dann laufen sie parallel (sonst läuft immer nur eine Sache und die andere erst nachdem die erste beendet wurde). Ich kann dann auch über die Konsole das Fenster ein bzw. ausblenden (ohne Probleme). Rufe ich aber über die Konsole eine Funktion der GUI auf, die der Form einen Button hinzufügt, ist das Fenster nicht mehr ansprechbar. Hat da jemand eine Lösung für mich?

thx
 

Christian Kusmanow

Erfahrenes Mitglied
Hallo gott_ad!

gott_ad hat gesagt.:
Rufe ich aber über die Konsole eine Funktion der GUI auf, die der Form einen Button hinzufügt, ist das Fenster nicht mehr ansprechbar
Controls dürfen nur von dem Thread angesprochen werden von dem sie erstellt wurden.
Im Framework 2.0 wird jetzt sogar sowas wie eine IllegalThreadCrossException geworfen.
Der Name ist mir jetzt nicht mehr so geläufig.
Du musst also mit delegates arbeiten.
MSDN hat gesagt.:
MethodBase.Invoke Method (Object, Object[])

obj
- The instance that created this method. ( Also dein Form, wenn static null )
parameters
- An argument list for the invoked method or constructor.
@Kommunikation:
Du hast doch alles fest vorgegeben, dann bietet sich für die Kommunikation zwischen
deiner Console und deinem Form ein Interface bestens an.
Du spaarst dir so das Suchen der Methoden und Funktionen, das dieses meines Erachtens
nur für Diagnosezwecke von Modularisierten Programmen vorgesehen ist.
Vor allem wird der Code übersichtlicher. ;) Übergib es deiner Konsolen-Klasse einfach im Konstruktor.

MfG, cosmo
 

gott_ad

Grünschnabel
Vielen Dank für die Antwort.
Auf delegates bin ich noch nicht gekommen, so ganz hab ich die auch noch nicht durchschaut ;-)
Aber das mit dem Interface ist ja auch ne schlaue Idee! War ja auch mehr zu testzwecken gedacht. Wahrscheinlich wird es statt einer richtigen Console auch einfach nur ein Windows-Textfenster geben, dass die Eingaben analysiert, damit sind dann beide auch im selben Thread.

Thx!