none
Threading und MVVM-Views RRS feed

  • 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. ;)

    Dienstag, 24. Februar 2015 10:24

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 

    Dienstag, 24. Februar 2015 11:52
  • 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 gleich
    lock (Locker)
    {
      InitializeComponent();
    }
    nutzen, weil die Browser sich sonst gegenseitig störten, aber es ging.


    Dienstag, 24. Februar 2015 12:12
  • 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.

    Mittwoch, 25. Februar 2015 10:59
  • 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

    Mittwoch, 25. Februar 2015 11:44
  • 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.

    Mittwoch, 25. Februar 2015 12:27
  • 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

    Mittwoch, 25. Februar 2015 13:20
  • 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

    Mittwoch, 25. Februar 2015 13:21
  • @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.

    Mittwoch, 25. Februar 2015 15:22
  • 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

    Mittwoch, 25. Februar 2015 16:47
  • Es ist doch schon alles in WPF. Ich glaube ich verstehe momentan nicht so ganz was du mir sagen willst...
    Donnerstag, 26. Februar 2015 06:59
  • 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

    Donnerstag, 26. Februar 2015 07:05
  • Das wäre ne sehr gute Idee, hatte ich auch schon überlegt, aber die Marketingabteilung ist davon gar nicht begeistert. Die wollen die Seiten selbst verändern können und von denen kann keiner C#/WPF.
    Donnerstag, 26. Februar 2015 07:10
  • 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


    Donnerstag, 26. Februar 2015 07:27
  • 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.

    Donnerstag, 26. Februar 2015 08:03
  • Also, zu erst einmal viel Glück mit WPF - das sollte sehr spannend werden.

    Wegen des besseren Rechners, die Idee war mit dem verwenden von mehreren Prozessen verbunden.


    © 2015 Thomas Roskop

    Germany // Deutschland

    Donnerstag, 26. Februar 2015 12:14
  • Du meinst das Programm mehrmals zu starten?

    Dann wird es aber schwer die automatisch auf den richtigen Monitoren zu verteilen. ;)

    Donnerstag, 26. Februar 2015 15:34
  • Hallo,

    nein, ich dachte an was anderes - aber, da du es ja in WPF machen kannst, ist die Idee irrelevant.


    © 2015 Thomas Roskop

    Germany // Deutschland

    Donnerstag, 26. Februar 2015 17:28
  • 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?

    Freitag, 27. Februar 2015 14:57
  • 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.

    Donnerstag, 5. März 2015 11:18
  • 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

    Freitag, 6. März 2015 07:12