Hallo zusammen,
Ich habe eine Klasse die durch die Main aufgerufen wird und diese erstellt in einem Thread einen TCP Listener, der mir auf Telnet Kommandos reagiert.
Wenn der listener den das Telnet Kommando HIDE erhällt soll er mir mein Formular verstecken, wenn er SHOW erhält soll das Formular angezeigt werden.
Der Listener läuft gut und macht was er soll.
Ich schaffe es einfach nicht, abhängig vom empfangenen Wert das Formular aus dem Listener heraus zu Steuern.
Habe mir hier und auch woanders schon die Form1 Form 2 Sachen angeschaut aber irgendwie komme ich damit nicht weiter.
Ist jemand so gut, und öffnet mir die Augen, ich habe nicht die leiseste Ahnung.
Grüße.
Hallo WolleWtal,
hilf uns ein wenig dir zu helfen
meinst du mit
Habe mir hier und auch woanders schon die Form1 Form 2 Sachen angeschaut
zum Beispiel [FAQ] Warum blockiert mein GUI? ?
Was genau meinst du mit
irgendwie komme ich damit nicht weiter
Was hast du probiert? Wo hakt es? Hast du Code?
Gruss
Coffeebean
Microsoft MVP // Me // Blog // GitHub // @Egghead // All my talks // Speakerdeck
Hierhin übergibt meine Klasse den empfangenen Befehl:
public static void Befehl(String Befehl)
{
Worker(Befehl);
}
Leider kann ich in der static anscheinend nicht den Befehl Show(); oder Hide(); nutzen.
Deswegen habe ich versucht den Befehl hierhin zu übergeben, was aber leider auch nicht funktioniert, weil dann anscheinend ein Objektverweis fehlt.
private void Worker(String DoIt)
{
switch (DoIt)
{
case "SHOW":
Show();
break;
case "HIDE":
Hide();
break;
default:
break;
}
}
Ohne Hilfe bekomme ich das nicht hin.
Bin doch schon im Betreffenden Formular mit meinem Befehl, warum klappt dass denn dann nicht, ich verstehe es nicht.
Hier noch der gesamte Code des Formulars zur Vollständigkeit.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
namespace nspHSBrowser
{
/// <summary>
///
/// </summary>
public partial class Browser : Form
{
/// <summary>
///
/// </summary>
public Browser()
{
InitializeComponent();
this.ShowInTaskbar = false;
WB_01.DocumentCompleted += new WebBrowserDocumentCompletedEventHandler(WB_01_DocumentCompleted);
WB_01.Navigate("http://192.168.111.171:3777/");
}
private void HSWLaNOnOffico_MouseDoubleClick(object sender, MouseEventArgs e)
{
this.Visible = true;
this.WindowState = FormWindowState.Normal;
}
private void WB_01_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
{
((WebBrowser)sender).Document.Window.Error += new HtmlElementErrorEventHandler(Window_Error);
}
private void Window_Error(object sender, HtmlElementErrorEventArgs e)
{
e.Handled = true;
}
public static void Befehl(String Befehl)
{
Worker(Befehl);
}
private void Worker(String DoIt)
{
switch (DoIt)
{
case "SHOW":
Show();
break;
case "HIDE":
Hide();
break;
default:
break;
}
}
}
}
Gruß, Wolle
a) und warum ist die Methode static? Eine statische Methode kann eben keine Instanz-Methode aufrufen. Basics OOP. static entfernen und es geht.
b) Aktionen über Strings zu übergeben ist "der falschester" von allen möglichen Wegen. Wenn überhaupt in diesem Sinne, dann mit Enums.
Was das am Ende werden soll erschließt sich mir nicht wirklich.
Willst nicht mal beschreiben, was das eigentlich werden soll? Nur ein Remote-Kommando abwarten oder soll das mehr werden? Ein Bot?
- performance is a feature -
Microsoft MVP - @Website - @AzureStuttgart - github.com/BenjaminAbt - Sustainable Code
Das fertige Programm nimmt über die TCPListener.cs Befehle von einem Smarthome Server über Telnet entgegen und soll je nach erhaltenem Befehl mein Form Anzeigen oder halt wieder ausblenden.
Die Form stellt nur einen Webserver ohne Rahmen zur Verfügung den ich halt über eine Visualisierung im Smarthome einblenden kann, sodass es aussieht, dass der Browser zur Visualisierung gehört.
Eigentlich ist das schon alles was passieren soll.
Das soll die Basis des Programmes werden, alles weitere steht noch nicht fest.
a) und warum ist die Methode static? Eine statische Methode kann eben keine Instanz-Methode aufrufen. Basics OOP. static entfernen und es geht.
Wenn ich Static entferne kann mein TCP-Listener nicht mehr auf
public void Befehl(String Befehl)
{
Worker(Befehl);
}
zugreifen.
Was muss ich machen, dass ich aus TCPListener.cs die Form Anzeigen, bzw. Ausblenden kann.
b) Aktionen über Strings zu übergeben ist "der falschester" von allen möglichen Wegen. Wenn überhaupt in diesem Sinne, dann mit Enums.
Die Ausgabe von TCPListener ist halt ein String der das enthält, was man per Telnet an den Listener übergeben hat.
Das ganze wollte ich halt mit switch auswerten, aber wie nun das Ergebnis aus TCPListener an die Form übergeben wird, ist mir egal, Hauptsache am Ende macht meine Form halt Show(); oder Hide();
Ich bekomme halt die Übergabe aus TCPListener nicht so hin, dass ich Show(); oder Hide(); im Formular ausführen kann.
Gruß, Wolle
Also zu aller erst fehlen Dir wohl die absoluten Basics, was die objektorientierte Programmierung angeht. Daher ein freundlicher Hinweis auf [FAQ] Wie finde ich den Einstieg in C#?
Zudem programmierst Du in die falsche Richtung: die Business Logik sollte die UI nicht kennen, sondern umgekehrt.
Die UI sollte einen Event von TcpListener abonnieren, sodass die UI auf Aktionen reagieren kann.
Du versuchst es umgekehrt: das kann nicht klappen.
Bau also entsprechend Dein Code um, dann klappt es auch und ist dann prinzipiell auch Regelkonform.
Siehe auch [Artikel] Drei-Schichten-Architektur für das grundlegende Verständnis von Software.
(was Du machst ist der "verbotene Zugriff" ganz rechts im Bild des Einleitungsposts!)
- performance is a feature -
Microsoft MVP - @Website - @AzureStuttgart - github.com/BenjaminAbt - Sustainable Code
Die UI sollte einen Event von TcpListener abonnieren, sodass die UI auf Aktionen reagieren kann.
Du versuchst es umgekehrt: das kann nicht klappen.
Kannst Du mir nicht mal ein Einfaches Beispiel dafür geben, wie man das richtig machen müsste?
Ich meine, anhand einer Klasse und einer Form.
Form Aboniert Event von Klasse und reagiert auf event.
Gruß
Sorry, aber bitte hab Verständnis, dass ich Dir jetzt nicht den Code dazu schreiben werde; ich hab auch noch andere Dinge zutun. Sonst wäre ich Sonntags bei Sonnenschein auch nicht im Büro.
Das Forum ist halt auch kein kostenloser Code-Generator, weil man sich die Basics oder Doku nicht antun will 😃
Du brauchst:
Diesen Event musst Du dann in die UI abonnieren und darauf reagieren.
- performance is a feature -
Microsoft MVP - @Website - @AzureStuttgart - github.com/BenjaminAbt - Sustainable Code
Das Du mir meinen kompletten Code schreibst, erwarte ich auch garnicht, aber ein wenig mehr Hilfe hätte ich mir schon erhofft.
Aber sei es drum.
Wenn ich dich richtig verstehe müsste TCPListener in meinem Beispiel von meiner Form erzeugt und auf ein Event, was vorher abonniert wurde, in TCPListener reagieren.
Richtig?
Du musst Dir unbedingt die Basics aneignen, sonst fährt jeder Deiner Software-Versuche gegen die Wand.
Vom Code kopieren lernt man nichts - und ich fürchte einige Teile dieses Codes verstehst nicht ganz...
Und Du solltest unbedingt die Texte durchlesen, die man Dir schreibt 😉
Du brauchst:
- eine Klasse (zB "Server"), die den TcpListener wrappt, da Du ja sicherlich auf die Clients hören willst.
- Diese Klasse hat einen Event für "ClientConnected", sowie für "ClientDataReceived", denn Du willst ja auf die Daten hören, wenn ein Client was schickt.
Wenn ich dich richtig verstehe müsste TCPListener in meinem Beispiel von meiner Form erzeugt und auf ein Event, was vorher abonniert wurde, in TCPListener reagieren.
Client
class Program
{
static void Main(string[] args)
{
var ipAddress = Dns.GetHostEntry("localhost").AddressList.First(a => a.AddressFamily == AddressFamily.InterNetwork);
Thread.Sleep(5000); // wait for server start
Console.WriteLine("Client: Connecting to server");
// Create multiple clients with multiple textx
foreach (var c in Enumerable.Range(0, 5))
{
TcpClient client = new TcpClient();
client.Connect(ipAddress, 17597);
Console.WriteLine($"Client #{c}: Connected to server");
using (var clientWriteStream = new StreamWriter(client.GetStream()))
{
foreach (var i in Enumerable.Range(0, 10))
{
clientWriteStream.WriteLine($"Hejsan #{i} from client #{c}");
clientWriteStream.Flush();
}
}
}
Console.WriteLine("Press any key to exit");
Console.ReadKey();
}
}
Server
class Program
{
static void Main(string[] startParameters)
{
Console.WriteLine("Server init.");
var ipAddress = Dns.GetHostEntry("localhost").AddressList.First(a => a.AddressFamily == AddressFamily.InterNetwork);
MyServer server = new MyServer(ipAddress, 17597);
server.OnClientConnected += (sender, client) => Console.WriteLine($"[SERVER]: Client '{client.Client.RemoteEndPoint}' connected.");
server.OnClientMessage += (sender, args) => Console.WriteLine($"[SERVER]: Message from client '{args.Client.Client.RemoteEndPoint}': '{args.Message}'");
Console.WriteLine("Server start.");
Task runningServer = server.RunServerAsync();
Console.WriteLine("Server is running. Press any key to exit.");
Console.ReadKey();
try
{
server.Cancel(TimeSpan.FromSeconds(30));
Console.WriteLine("Soft Cancel done.");
}
catch (Exception)
{
Console.WriteLine("Hard Cancel done.");
}
Console.WriteLine("Press any key to exit.");
Console.ReadKey();
}
}
public class MyServer
{
private TcpListener _listener;
private List<TcpClient> _clients = new List<TcpClient>();
private CancellationTokenSource _cts = new CancellationTokenSource();
private Task _runningServerTask = null;
private List<Task> _connectedClientTasks = new List<Task>();
public MyServer(IPAddress address, int port)
{
_listener = new TcpListener(address, port);
}
// Events
protected virtual void FireClientConnected(TcpClient client) => OnClientConnected?.Invoke(this, client);
public event EventHandler<TcpClient> OnClientConnected;
protected virtual void FireClientMessage(ClientMessageEventArgs args) => OnClientMessage?.Invoke(this, args);
public event EventHandler<ClientMessageEventArgs> OnClientMessage;
public Task RunServerAsync()
{
if (_runningServerTask == null)
{
try
{
_runningServerTask = Task.Run(async () =>
{
_listener.Start();
while (true)
{
// warten bis jemand connected
TcpClient client = await _listener.AcceptTcpClientAsync();
_clients.Add(client);
_connectedClientTasks.Add(Task.Run(async () => { await ListenToClientAsync(client); }, _cts.Token));
}
}, _cts.Token);
}
catch (Exception ex) when (_cts.Token.IsCancellationRequested)
{
// Es wurde ein Cancel angefragt
}
finally
{
_listener.Stop();
}
}
return _runningServerTask;
}
private async Task ListenToClientAsync(TcpClient client)
{
using (var stream = new StreamReader(client.GetStream()))
{
string data;
while ((data = await stream.ReadLineAsync()) != null)
{
FireClientMessage(new ClientMessageEventArgs(client, data));
}
}
}
public void Cancel(TimeSpan maxCancelWaitTime)
{
_cts.Cancel(maxCancelWaitTime);
// Warten auf das Beenden aller Clients
Task.WhenAll(_connectedClientTasks);
// warten bis der Server beendet ist
Task.WhenAll(_runningServerTask);
}
}
public class ClientMessageEventArgs : EventArgs
{
public TcpClient Client { get; }
public string Message { get; }
public ClientMessageEventArgs(TcpClient client, string message)
{
Client = client;
Message = message;
}
}
Die Konsolenanwendung ist hier die Präsentationsschicht.
- performance is a feature -
Microsoft MVP - @Website - @AzureStuttgart - github.com/BenjaminAbt - Sustainable Code