Wie kann ich das umgehen (C#)?
Hallo. Also ich hab ein C# Socket Server (Der von Python angesprochen wird). Weil ein SocketServer das Programm ja bekanntlich "aufhängt" (while True schleife) hab ich einen Thread daraus gemacht. Joah nur gibt es da anscheinend ein Problem
"CoreWebView2 can only be accessed from the UI thread."
Klingt lustig ist es aber nicht. Also muss ich entweder dafür sorgen das im gleichen Thread kommuniziert wird (Hab ich aber wirklich keine Idee wie das gehen soll) oder ich muss von diesem Thread dort irgendwie in den UI Thread callen. Aber da hätte ich noch ne Frage ... Wie? Ich hab wirklich keine Idee wie man das machen könnte, ihr vielleicht?
Danke im Voraus und lg.
P.S.
Hier der Code:
Program.cs:
Window.cs:
HelpClasses.cs (Bitte nicht rummeckern mir ist nichts anderes eingefallen als Name):
2 Antworten
Wie schon unter deiner anderen Frage geschrieben:
https://www.gutefrage.net/frage/warum-kann-man-das-webview-nicht-sehen
Du musst entweder asynchron arbeiten (Netzwerk ist sowieso prinzipiell asynchron, die synchronen Methoden sind nur ein mieser Hack von Microsoft) oder das alles in einen eigenen Thread auslagern, musst dich dann aber auch selber um die Synchronisation kümmern.
Beides ist kein einfaches Thema und da solltest Du dich definitiv vorher einarbeiten. Am Ende würde ich aber zu async raten, das ist zwar auch kompliziert und viel "Magie" im Hintergrund, aber es ist mMn. einfacher, als klassisches Multi Threading "zu Fuß".
Oder dir ist völlig egal, ob dein Projekt noch wartbar bleibt, dann nutze die Invoke-Methode von der Form oder einem Control.
Besser wäre, Du arbeitest asynchron, dann passiert die Synchronisation automatisch, der TcpClient und Stream können das. Allerdings wird das mit deinem Code nicht funktionieren. Asynchroner Code muss aus dem UI-Thread heraus gestartet werden, dann wird immer wieder zum UI-Thread zurück synchronisiert und Du brauchst dich nicht weiter darum kümmern.
Oder Du machst es manuell mit Queues, Channels, WaitEvents und was es noch für Möglichkeiten gibt.
Beim async hast Du auch Threads, nur nicht mehr nur einen, sondern beliebig viele - oder doch nur einen :D
Und es gibt ein System, was dafür sorgt, dass der Code nach einem await im selben Thread läuft, wie der Code davor - zumindest gibt es die Infrastruktur dafür (SynchronizationContext) und WinForms, WPF, etc. implementieren sie.
Und dazwischen, während auf die Netzwerk-Antwort gewartet wird, ist der Thread frei für anderes Zeug.
Sowas wäre mit klassischem MultiThreading nicht möglich bzw. sehr aufwändig.
Und es ist auch immer noch aufwändig, nur dass Microsoft 99% der Arbeit geleistet hat.
Das ist ja das schöne daran, Du musst dich nicht mehr um Threads kümmern, sondern der Framework-Code (oder dein eigener), den Du aufrufst, kümmert sich um die Frage, ob ein neuer Thread nötig ist oder nicht. So kann es z.B. sein, dass der Code durchgehend synchron läuft, weil einfach nicht gewartet werden muss.
Verstehe verstehe. Nur die Sache ist: Mein Code ist dafür gedacht zu warten. Das ist quasi seine bestimmung. Ich baue noch einen UI über Python und das WebView dort. Und dann connecte ich über das Socket zu C# und kann so die WebViews von C# durch Python ansteuern. Ich würde den UI theoretisch auch in C# machen, allerdings ist das Backend dafür in Python schon mehr als nur Fertig. Vielleicht übersetze ich das irgendwann aber ich hab zurzeit wenig lust 900 Zeilen in C# zu übersetzen xD.
Mein Code ist dafür gedacht zu warten.
Und?
Die meisten Programme verbringen ihre Zeit mit Warten auf Netzwerk, Datenbank, Dateisystem, etc.
Und dann connecte ich über das Socket zu C# und kann so die WebViews von C# durch Python ansteuern
Also eigentlich soll die Python-Anwendung eine Verbindung mit der C#-Anwendung aufbauen? Warum dann so umständlich?
Hatte ich dir doch schon mal geschrieben: Bau eine simple Web-API auf, mit ASP.NET Core ist das kein Problem und ich gehe stark davon aus, dass man mit Python HTTP-Calls absetzen kann.
900 Zeilen
Süß :D
Jap, süß. Aber nicht Süß wenn man das übersetzen soll. Was die Web API angeht: Ich hab mir C# reingeholt für die Geschwindigkeit. Web Calls (Auf einem Localhost) haben mit meiner Erfahrung 400ms? Sowas ca. außer man verwendet den PHP Web Server. Gut, ASP.NET usw. hab ich noch nie versucht. Aber mit Sockets hatte ich noch nie Probleme und bis jetzt waren sie auch immer extrem schnell. Ich hab auch einen Intentor mit Python geschrieben und ihn mit einem Minecraft Plugin verbunden (Dadurch konnten die Villager sich "unterhalten"). Und dort war es auch immer relativ schnell. Deswegen dachte ich mir halt direkt das ich Sockets verwende. Was währe denn der Vorteil an den HTTP-Calls, wenn ich fragen darf?
HTTP ist ein Protokoll auf Basis von TCP.
Du machst also das gleiche, nur umständlich und weniger ausführlich getestet.
So oder so sind das natürlich andere Technologien, doch in den meisten Fällen hast Du so den Vorteil, dass das ganze (Fehler-) Handling und bereits implementiert und alles gut getestet wurde.
Außerdem ist der Code mMn. bedeutend einfacher.
Wobei ich aber gerade nicht weiß, wie man ASP.NET Core in einer WinForms oder WPF Anwendung hosten kann ... muss ich mal testen
Oder das Python-Programm baut die Web-API auf und der .NET-Client spricht ihn an. So oder so gibt's Frameworks, die dir den Großteil der Arbeit abnehmen.
Grundsätzlich ist es bei .NET so, dass kein Thread auf Controls (GUI-Elemente) zugreifen darf, die er nicht selbst erzeugt hat. Das hat unter anderem auch Sicherheitsgründe. Genaueres steht in der Doku zu deiner Exception.
Zudem solltest du bei einem ordentlichen Konzept erst gar nicht auf dieses Problem stoßen. Dementsprechend solltest du dir grundsätzlich über dein Konzept Gedanken machen.
Denn normalerweise sind die Nutzeingaben vom Backend getrennt. Dazwischen baut man eine Schnittstelle. Die Schnittstelle bedient deinen UI-Thread asynchron mit Anweisungen, welche entsprechende Änderungen an den Controls deiner GUI auslösen.
In deinem Fall solltest du also alles nach dem Web-Socket als Backend definieren. Zwischen deiner Windows-Form und dem Socket baust du eine Klasse, die für entsprechende GUI-Elemente die entsprechenden Funktionen bereitstellt, und auch umgekehrt bei entsprechenden Nutzeingaben den Socket entsprechend anspricht. Die Kommunikation, bzw. der Aufruf dieser Funktionen erfolgt asynchron, entweder durch die Definition deines Threads oder direkt durch ein Invoke.
Socket-Programmierung ist definitiv für Fortgeschrittene. Wenn dir Grundlagen fehlen, solltest du dich eventuell erst mit einfacheren Anwendungsfällen beschäftigen, sonst frustriert das ziemlich schnell.
LG Knom
Wie immer eine Hilfreiche Antwort, danke dir. Ich hab es jetzt mit win.Invoke gemacht. Muss auch nicht wirklich wartbar sein, an sich brauche ich von C# nämlich nicht mehr viel. Das ganze Asynchron Zeug ist halt ... Verwirrend. Ich hab mein Lebenlang mit Threads gearbeitet, ist ne Angewohnheit geworden. Vielen Dank, jetzt klappt alles!