Fragensteller
Threading und MVVM-Views

Allgemeine Diskussion
-
Hi,
ich fahr mal wieder gegen die Wand mit dem ganzen Threading-Kram (kennt jemand ne Schule im Ruhrgebiet wo man Abend- oder Wochenendkurse für Fortgeschrittene C# und WPF-Programmierung findet für schmales Geld?).
Ich rufe ein Fenster mehrfach auf (bis zu 12 mal, daher mit Threadings versehen) auf diese Art:
App.xaml.cs:
namespace ASA_Videowand { public partial class App { private void Application_Startup(object sender, StartupEventArgs e) { // ... foreach (List<string> myStrings in Screen.AllScreens.Select(myScreen => _xml.GetScreenConfigs(i))) { // ... int i1 = i; List<string> strings = myStrings; var newWindowThread = new Thread(() => { var myMarketing = new Marketing(i1, strings[0]); myMarketing.Show(); Dispatcher.Run(); }); newWindowThread.SetApartmentState(ApartmentState.STA); newWindowThread.IsBackground = true; newWindowThread.Start(); } else { // ... } } i++; } } } } }
Die folgenden Dateien sind dann wohl die wichtigsten:
Marketing.xaml:<Window x:Class="ASA_Videowand.Marketing" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:main="clr-namespace:ASA_Videowand.Views" Title="{Binding WebBrowser.Title}"> <Grid> <main:MainView /> </Grid> </Window>
Marketing.xaml.cs:
namespace ASA_Videowand { public partial class Marketing { public Marketing(int screenNumber, string myLink) { InitializeComponent(); } } }
Und dann hier wohl das eigentliche Problem:
MainView.xaml:
<UserControl x:Class="ASA_Videowand.Views.MainView" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:cefSharp="clr-namespace:CefSharp.Wpf;assembly=CefSharp.Wpf" mc:Ignorable="d" d:DesignWidth="640" d:DesignHeight="300"> <Grid> <Grid.RowDefinitions> <RowDefinition /> <RowDefinition Height="Auto" /> </Grid.RowDefinitions> <cefSharp:ChromiumWebBrowser Grid.Row="0" Address="http://www.google.com" WebBrowser="{Binding WebBrowser, Mode=OneWayToSource}" Title="{Binding Title, Mode=TwoWay}" /> <StatusBar Grid.Row="1"> <ProgressBar HorizontalAlignment="Right" IsIndeterminate="{Binding WebBrowser.IsLoading}" Width="100" Height="16" Margin="3" /> <Separator /> <!-- TODO: Could show hover link URL here --> <TextBlock /> </StatusBar> </Grid> </UserControl>
MainView.xaml.cs:
namespace ASA_Videowand.Views { public partial class MainView : UserControl { public MainView() { InitializeComponent(); DataContext = new MainViewModel(); } } }
Sobald ich an diesen Punkt hier komme:<cefSharp:ChromiumWebBrowser Grid.Row="0" Address="http://www.google.com" WebBrowser="{Binding WebBrowser, Mode=OneWayToSource}" Title="{Binding Title, Mode=TwoWay}" />
hab ich ein Problem und zwar wird hier eine UI-Operation in einem Thread ausgeführt. Wie kann ich diese Windows aufrufen ohne den Fehler auszulösen? Muss ich den ganzen XAML-Kram in den Code-Behind schieben und dort initiieren mit (Begin)Invoke? Oder gibt es elegantere Lösungen? Ich muss die Fenster auf jeden Fall threaden, sonst geht mir der Server in die Knie. Spätestens nach dem 12ten Monitor. ;)
- Typ geändert Aleksander Chalabashiev Dienstag, 10. März 2015 09:08 keine bestätigte Lösung
Alle Antworten
-
Hi Marcel,
pro Anwendung gibt es nur einen UI Thread, es wird also nicht Funktionieren die Fenster in einem anderen Thread zu öffnen. Grundlegend kannst du aber das Laden der Daten in einen anderen Thread packen.
Für schmales Geld wirst du kaum C# Kurse für Fortgeschrittene finden, wenn ich es richtig im Kopf habe gibt es in Oberhausen eine Agentur die Schulungen anbietet aber die kosten so um die 1800€ für 3-5 Tage, kostenlos gibt es aber viel Inhalte im Netz. Z.B. die Virtual Akademie.
MFG
Björn
-
Das mit der MVA ist schonmal ganz interessant. Das merke ich mir, danke.
Aber ich habe vorher den gleichen Aufruf benutzt, nur statt dort ein View zu laden, habe ich direkt den von .net integrierten WebBrowser benutzt. Das funktionierte einwandfrei.
Also statt in der Marketing.xaml
<main:MainView />
zu nutzen, einfach<WebBrowser x:Name="MarketingBrowser" Margin="0,0,-17,0" OverridesDefaultStyle="False" ScrollViewer.CanContentScroll="False" ScrollViewer.HorizontalScrollBarVisibility="Hidden" ScrollViewer.VerticalScrollBarVisibility="Hidden"/>
Ich musste dann zwar im Aufruf gleichlock (Locker) { InitializeComponent(); }
nutzen, weil die Browser sich sonst gegenseitig störten, aber es ging.
- Bearbeitet Marcel Gpunkt Dienstag, 24. Februar 2015 12:46
-
Ich habe es jetzt folgendermassen probiert:
16 Fenster erstellen und davon dann die Browserobjekte selbst in Tasks zu stecken. Leider bekomm ich das nicht hin, egal wie ich es mache. In 80% aller Fälle sagt er mir trotzdem dass das Objekt nicht dem Thread gehört und einen neuen Fehler habe ich bei dieser Variante bekommen:
public Marketing(int screenNumber, string myLink) { InitializeComponent(); DataContext = new MainViewModel(); _screenNumber = screenNumber; InitializeWindow(myLink); } private async void InitializeWindow(string myLink) { await Task.Factory.StartNew(() => InitializeBrowser(myLink), TaskCreationOptions.LongRunning); } private void InitializeBrowser(string myLink) { var marketingBrowser = new ChromiumWebBrowser(); MainGrid.Children.Add(marketingBrowser); marketingBrowser.Address = myLink; }
Fehlermeldung: Der Typeninitialisierer für "CefSharp.Wpf.ChromiumWebBrowser" hat eine Ausnahme verursacht.
Hierbei kann ich aber nicht in die Details schauen.
Es muss doch möglich sein mehrere Objekte auf der GUI mehrerer Fenster auf verschiedene Tasks zu verteilen.
-
Hi Marcel.
Du musst alle UI-Elemente im Haupt-Thread erzeugen. Im Hintergrund laufen eine Vielzahl von Aktivitäten zur Erzeugung eines Fensters ab, die die nicht thread-sicher sind. Die Erzeugung in einem anderen Thread (bei Dir über Task.Factory) ist nicht zulässig.Was Du machen kannst, ist der Aufruf der Erzeugung der Fenster in einem anderen Thread, wobei die eigentliche Instanziierung über Invoke (oder Dispatcher) in den Haupt-Thread einzuordnen ist.
--
Peter -
Wie genau meinst du deinen zweiten Absatz?
Anfänglich habe ich es ja (mit dem IE-WebBrowser) so gemacht, dass ich über Threads die Fenster aufgerufen habe und dort wurde alles dann verteilt erledigt. Jetzt, mit Chromium, scheint das nicht mehr zu gehen, weil das WebBrowser-Objekt anscheinend anders behandelt wird.
Es geht halt vor allem darum, dass die Fenster (im Normalfall 12 von 16) jeweils eine HTML5 oder Flash-Animation ablaufen lassen und diese müssen halbwegs flüssig laufen. Ich hatte das anfangs so, dass alles im selben Thread lief, aber allein bei 3 Fenstern fängt das schon an zu ruckeln.
-
Hi Marcel,
wenn die CPU nicht genügend Leistung bringt, dann kann bei 3 Fenstern Schluss sein. Du kannst mal versuchen, das Programm mit 3 Fenstern 5 mal zu starten und zu überprüfen, ob in diesem Fall bei mehreren CPU-Kernen eine Verbesserung erreicht wird, wenn die einzelnen UI-Threads in verschiedenen Kernen abgearbeitet werden. Ich kann mir aber vorstellen, dass das nicht helfen wird, da trotz mehrerer Instanzen die Browser-Engine ggf. nur einmal arbeitet.--
Peter -
Hallo Marcel,
auch am Namen der Anwendung bzw. des Namensraumes und deiner angabe über das video, gehe ich mal davon aus, dass die Anwendung ASA_Videowand mehrer Videos an einem (mehrer?) Bildschirme zeigen soll.
Es wäre möglicherweise besser, statt in WPF einer Browser zu erstellen, der wiederum ein Flasch-Plung in erstellt, einfach das Video selbst abzuspielen.
Dazu kannst du das MediaElement verwenden, welches da performanter arbeiten sollte.
Wenn du vielleicht weitere Informationen haben möchtest, dann sag doch bitte genauer, was du willst, wie viele Bildschrime es gibt usw. - oder ob ich mich auf dem Holzweg befinde :D
© 2015 Thomas Roskop
Germany // Deutschland
-
@Peter: Doch das hilft enorm. Wie gesagt hatte ich anfangs statt den Chromium zu nutzen, den normalen IE-WebBrowser genutzt und diesen habe ich mit
var newWindowThread = new Thread(() => { var myMarketing = new Marketing(i1, strings[0]); myMarketing.Show(); Dispatcher.Run(); }); newWindowThread.SetApartmentState(ApartmentState.STA); newWindowThread.IsBackground = true; newWindowThread.Start();
aufgerufen. Fehlerfrei. Das habe ich deshalb getan, weil ich halt mit 3 Fenstern schon Probleme hatte. Nun haben wir auf einem Server sogar 12 WebBrowser gleichzeitig laufen und es läuft auch da fast ruckelfrei. Leider hat der WebBrowser aber ärgere Probleme mit der Flash-Player Darstellung, bzw. es stürzt bei einigen Servern ganz ab wenn es mehrfach aufgerufen wird. Daher wollten wir einen anderen Browser ausprobieren als den IE. Leider lässt der sich jetzt nicht so starten wie der Standard von .Net.
@Thomas: Das ist leider keine Option, da hier einige HTML5-"Filme" ablaufen sollen, die im Endeffekt ja nur JQuery-Übergänge sind und zum Anderen muss das Flash hier interaktiv sein. Wir haben nämlich nicht nur eine riesige Videowand, sondern diese ist auch mit einem riesigen Touchrahmen versehen. Hier läuft dann ein "Glücksrad", welches per Touch angeschubst wird. Ist wirklich simpelste Mechanik im Flash, aber es ist leider kein einfacher Film.
-
Hallo Marcel,
also den übergang der HTML5-geschcitehn in WPF zu erstellen ist jetzt nun wirklich keine herausragende Kunst, und die Flash-Spiele sollten auch nicht dermaßen genail sein, als das es unmöglich ist anders zu lösen.
Wie gesagt, wenn dir die performance wichtig ist, dann versuche mal etwas auf WPF zu portieren.
Aber, im endeffekt liegt es ja auch in deiner Entscheidung, mehr als empfehlen kann ich nicht.
© 2015 Thomas Roskop
Germany // Deutschland
-
Entschuldigung, dass ich mich wohl etwas undeutlich ausgedrückt habe.
Was ich aussagen wollte, war dass du versuchen solltest, statt die WebBrowser zu verwenden, die viel Leistung ziehen, einfach die Funktionen in WPF zu erstellen. So musst du z.B. keinen WebBrowser verwenden, um eine HTML5-Diashow zu erstellen.
Du kannst einfach über einen Zeitgeber gesteuert die Animationen anzeigen. Aber auch das Flash-Glücksspiel solte machbar sein, dazu kannst du ebenfalls WPF selbst verwenden, statt das über einen FlashPlayer, duch einen WebBrowser gewrappt dazustellen.
Kurz: Ich würde komplett die Browser herausnehmen, und nur WPF-Technik verwenden.
© 2015 Thomas Roskop
Germany // Deutschland
-
Aus, zum Teil eigener Neugier, was heißt hier ändern: Wollen sie die Bilder selbst ändern, oder auch die Animation. Wollen sie die Spiele komplett ändern?
Sollten die Änderungen sich in Grenzen halten, dann könntest du einfach eine Konfigurationsdatei erstellen, die dann von denen Angepasst werden kann.
Sonst musst du die Marketingsabteilung halt bitten, einen besseren Rechner zu kaufen. Ganz einfach.
PS: Sollte es nicht anders gehen, mir ist gerade eine Alternative eingefallen.
Du könntest es doch so machen, dass du für jeden WebBrowser einen eigenen Prozess! öffnest, und dieser dann in Regelmäßigen Abständen (60 mal pro Sekunde) mittels Visual die Grafik des WebBrowser-Controls kopiert und z.B. über Pipes oder Sockets an den Hauptprozess sendest. Dort kann dann das Bild des Visual mittel VisualBrush gemalt werden.
Aber dann wünsche icjh dir viel spaß bzgl. des Netzwerkes, der Synchronisation, dem Overhead, der Steuerung und zuordnung der Prozesse usw.
© 2015 Thomas Roskop
Germany // Deutschland
- Bearbeitet Thomas Roskop Donnerstag, 26. Februar 2015 07:49
-
Ich habe gerade nochmal mit denen geredet und es sieht wohl so aus, als wenn das doch klappen könnte. Sprich: Ich versuch mich dann an der Mediensteuerung. Jetzt muss ich mich dann aber erstmal damit befassen wie man einen Pfeil drehen lässt auf einem Glücksrad. :) Bin ja mal gespannt wie das geht. Was ich von WPF in dem Bereich gesehen habe bisher sah ja ganz komfortabel aus.
Das mit dem besseren Rechner wäre übrigens keine gute Idee. Was bringt es mir nen 8-fach-Kern i7 im Rechner zu haben, wenn trotzdem alle Fenster im selben Thread laufen? Dann habe ich da 64 Threads und 63 davon im Leerlauf.
-
Ich hatte vorhin noch eine Idee, nämlich einfach das Flashplayer-ActiveX Objekt einzubinden und die Flashvideos direkt abzuspielen, aber leider kann ich nach dem Einbinden der Komponenten das Objekt nicht nutzen. Wenn ich es dem Werkzeugkasten per Hand hinzufüge, dann bleibt es ausgegraut und es kommt eine Fehlermeldung, dass es deaktiviert bleiben würde.
Jetzt habe ich testweise andere Werkzeuge aus den COM-Komponenten hinzugefügt und alle bleiben ausgegraut. Jemand ne Idee was das sein könnte?
-
Hallo Marcel
bist du weitergekommen?
Gruß
Aleksander
Bitte haben Sie Verständnis dafür, dass im Rahmen dieses Forums, welches auf dem Community-Prinzip „IT-Pros helfen IT-Pros“ beruht, kein technischer Support geleistet werden kann oder sonst welche garantierten Maßnahmen seitens Microsoft zugesichert werden können.
-
Ich versuche es zwar jetzt mit einem anderen Ansatz, aber im Endeffekt ist das Problem noch nicht gelöst. Aber ich arbeite mit dem selben Problem (nur anders verpackt) jetzt in diesem Thread hier:
https://social.msdn.microsoft.com/Forums/de-DE/59dd2d88-1616-416b-8277-748afd7bd3f3/threading-mit-multiplen-videos-slideshows-etc?forum=visualcsharpde#de629639-242a-4214-964d-712d7117dcc6