Willkommen auf myCSharp.de! Anmelden | kostenlos registrieren
 | Suche | FAQ

Hauptmenü
myCSharp.de
» Startseite
» Forum
» Suche
» Regeln
» Wie poste ich richtig?

Mitglieder
» Liste / Suche
» Wer ist online?

Ressourcen
» FAQ
» Artikel
» C#-Snippets
» Jobbörse
» Microsoft Docs

Team
» Kontakt
» Cookies
» Spenden
» Datenschutz
» Impressum

  • »
  • Community
  • |
  • Diskussionsforum
MVVM Aktualisierung von Eigenschaften durch Task.Factory

Moderationshinweis von Abt (10.01.2016 - 21:57)

Der Beitrag wurde ursprünglich in [FAQ] Controls von Thread aktualisieren lassen (Control.Invoke/Dispatcher.Invoke) hinzugefügt.
Habe mich entschieden ihn doch abzuteilen und evtl. vorher zu besprechen.

Abt
myCSharp.de - Team

Avatar #avatar-4119.png


Dabei seit:
Beiträge: 16.030

Themenstarter:

MVVM Aktualisierung von Eigenschaften durch Task.Factory

beantworten | zitieren | melden

Ich hab noch einen Weg gefunden die WPF GUI MVVM-getreu aktualisieren zu können, also wenn man durch das ViewModel keinen Zugriff auf den Dispatcher hat:


public class MyViewModel : INotifyPropertyChanged
    {
        private readonly TaskFactory _uiTaskFactory;
        private readonly IAnyExternalService _service;

        public MyViewModel( IAnyExternalService service )
        {
            _uiTaskFactory = new TaskFactory( TaskScheduler.FromCurrentSynchronizationContext() );
            _service = service;

            // Beispielhaft bietet der Service ein Event, dessen Resultat wir an das ViewModel übertragen wollen
            // Der Service läuft aber in einem anderen Thread
            _service.OnConnected += ( obj, args ) =>
            {
                // Task im synchronisierten Context (GUI) starten
                _uiTaskFactory.StartNew( () =>
                {
                    // Wert übertragen
                    this.State = args.StateName;
                } );
            };
        }

        private string _state;
        public string State
        {
            get { return _state; }
            set
            {
                _state = value;
                // Nofify Property Changed Implementierung hier
            }
        }
    }

Klasse ist nur beispielhaft
private Nachricht | Beiträge des Benutzers
MrSparkle
myCSharp.de - Team

Avatar #avatar-2159.gif


Dabei seit:
Beiträge: 5.655
Herkunft: Leipzig

beantworten | zitieren | melden

Hi Abt,

wozu braucht man das? Oder anders gefragt, welches Problem besteht in dem Beispiel?

Normalerweise würde ich davon ausgehen, daß sich der DataBinding-Mechanismus um alles kümmert.

Christian
Weeks of programming can save you hours of planning
private Nachricht | Beiträge des Benutzers
Abt
myCSharp.de - Team

Avatar #avatar-4119.png


Dabei seit:
Beiträge: 16.030

Themenstarter:

beantworten | zitieren | melden

Konkret geht es um folgende auch die beispielhaft gezeigte implementierung.
Würde ich Task.Factory im entsprechenden Context nicht nutzen, dann wird eine entsprechende Exception geworfen.
Fehler
Additional information: The application called an interface that was marshalled for a different thread. (Exception from HRESULT: 0x8001010E (RPC_E_WRONG_THREAD))

Grund: der Event wird eben in einem anderen Thread ausgeführt; und irgendwie muss ich ja in den korrekten Context kommen.
Ich hab in ViewModel aber keinen Dispatcher (ausser ich hole ihn mir über Dispatcher.CurrentDispatcher oder ähnliches, was sicherlich nicht konform ist.

Die FAQ; und das ist der Grund, weshalb ich es dort aufgeführt hatte - beachtet das gar nicht.

In meinem konkreten Fall handelt es sich um eine Windows 10 App, die mit einem Microsoft Band2 kommuniziert und das SDK verwendet.
Ich seh jetzt nicht wirklich (oder ich übersehe es), wo das der Binding-Mechanismus automatisch übernehmen würde.
private Nachricht | Beiträge des Benutzers
ErfinderDesRades
myCSharp.de - Experte

Avatar #avatar-3151.jpg


Dabei seit:
Beiträge: 5.299

beantworten | zitieren | melden

ist das nicht ein bischen böse zu den Resourcen, wenn jedes Viewmodel seine eigene TaskFactory mit sich rumschleppt?
Der frühe Apfel fängt den Wurm.
private Nachricht | Beiträge des Benutzers
Abt
myCSharp.de - Team

Avatar #avatar-4119.png


Dabei seit:
Beiträge: 16.030

Themenstarter:

beantworten | zitieren | melden

Finde ich jetzt weniger böse als nen Dispatcher rein zu stopfen ;-)
Du kannst bei Bedarf die TaskFactory wrappen und injecten, dann haste nur einen. Aber wollte hier ja die grundlegende Funktionsweise zeigen; keinen Service zur Verfügung stellen.

Kannst die Methode

 _uiTaskFactory.StartNew( () =>
                {
                    // Wert übertragen
                    this.State = args.StateName;
                } );
gerne

 _uiContextService.ExecuteInUIContext( () =>
                {
                    // Wert übertragen
                    this.State = args.StateName;
                } );
nennen :-)
private Nachricht | Beiträge des Benutzers
ErfinderDesRades
myCSharp.de - Experte

Avatar #avatar-3151.jpg


Dabei seit:
Beiträge: 5.299

beantworten | zitieren | melden

ich verstehe nicht, oder du ;)

Ich meine, jede Viewmodel-Instanz erhält ein neues (new) TaskFactory-Objekt. Ich weiß nicht, wie fett diese Factories sind, und obs was ausmacht, wenn man 10000 Datensätze lädt, dass damit dann auch 10000 TaskFactory-Objekte erstellt sind.
Der frühe Apfel fängt den Wurm.
private Nachricht | Beiträge des Benutzers
Abt
myCSharp.de - Team

Avatar #avatar-4119.png


Dabei seit:
Beiträge: 16.030

Themenstarter:

beantworten | zitieren | melden

Ja, weiß was Du meinst.


 public MyViewModel( IAnyExternalService service, IMyFactoryWrapper wrapper )
        {


Wrap Deine Factory mit einem IMyFactoryWrapper Service, lass eine einzige Instanz davon existieren, injecte sie via DI und jut is. =)
private Nachricht | Beiträge des Benutzers
ErfinderDesRades
myCSharp.de - Experte

Avatar #avatar-3151.jpg


Dabei seit:
Beiträge: 5.299

beantworten | zitieren | melden

hmm - ich dachte, das sei hier für eine FAQ vorgesehen, also gedacht als Hilfe für weniger fortgeschrittene.
Aber ob die mit Fach-Chinesisch wie "Wrap Deine Factory mit einem IMyFactoryWrapper Service, lass eine einzige Instanz davon existieren, injecte sie via DI und jut is." was anzufangen wissen?
Dieser Beitrag wurde 1 mal editiert, zum letzten Mal von ErfinderDesRades am .
Der frühe Apfel fängt den Wurm.
private Nachricht | Beiträge des Benutzers
Abt
myCSharp.de - Team

Avatar #avatar-4119.png


Dabei seit:
Beiträge: 16.030

Themenstarter:

beantworten | zitieren | melden

Finds schade (und etwas wirr), dass Du das jetzt in den falschen Hals rein bekommst.
Eben wegen der Zielgruppe habe ich nicht von Anfang an den DI-Container verwendet, sondern die Factory im Konstruktor erstellt.

Das Wrappen ist entstanden, da Du die Ressourcen"verschwendung" (und indirekt die Einfachheit) bemängelt hattest. Und die Ausdruckweise war so gewählt, da ich Dich als fortgeschrittenen Entwickler angenommen hatte und Du dies verstehst.
Das DI-Beispiel würde ich gar nicht in die FAQ mit aufnehmen - es war nur eine Antwort und die Lösung auf Deine Ressourcen-Kritik.
private Nachricht | Beiträge des Benutzers
FZelle
myCSharp.de - Experte



Dabei seit:
Beiträge: 9.987

beantworten | zitieren | melden

Zitat
Das DI-Beispiel würde ich gar nicht in die FAQ mit aufnehmen - es war nur eine Antwort und die Lösung auf Deine Ressourcen-Kritik.
Was ich schade finden würde, denn so wird genau das passieren was ErfinderDesRades angenommen hat.
Auch die FAQ sollten immer und in jedem Fall der best Praxis entsprechen.
private Nachricht | Beiträge des Benutzers
Abt
myCSharp.de - Team

Avatar #avatar-4119.png


Dabei seit:
Beiträge: 16.030

Themenstarter:

beantworten | zitieren | melden

Also erst mal gings mit ja um den Lösungsweg an für sich, den ich - ich seh bisher nur Vorteile, keine Nachteile - in die FAQ aufnehmen würde.
Wir können das dann gerne als Basisumsetzung sowie als Umsetzung via DI aufzeigen.

Wir bewegen uns irgendwie von der Kernsache weg...
private Nachricht | Beiträge des Benutzers
ErfinderDesRades
myCSharp.de - Experte

Avatar #avatar-3151.jpg


Dabei seit:
Beiträge: 5.299

beantworten | zitieren | melden

nanU?
Ich hätte diese 2 Punkte für die kernsache gehalten:
1) Zu diskutieren, wie die best practice sei, und da hab ich vermutet, dass deine Lösung, so, wie sie in post#1 steht, unnötig viel Speicher belegt.
2) Auch die Gestaltung, sodass auch Anfänger von der FAQ profitieren.

Was wäre in deinen Augen die Kernsache?

(Ich trau mich kaum, es abzuschicken, denn zu diskutieren, was die Kernsache ist, ist ganz sicher nicht die Kernsache.
Meinetwegen kannste meine Posts auch rauslöschen, wenn das hilft, den Thread wieder mehr @Topic zu bringen.

(Was ich noch nur ungern zugebe: )
Ausserdem könnte ich tatsächlich kein DI umsetzen. Ich weiß zwar im groben, was das ist, aber alle meine Versuche einer praktischen Test-Umsetzung führten zu mehr Uständlichkeit statt zu weniger.
Wäre jetzt ein neuer Anlauf, wenn mir hier jetzt was praktikables präsentiert würde.

(Auch hierfür fürchte ich, harsche Ablehnung zu erfahren: )
Zur Gestaltung hätte ich noch die Bitte um ein lauffähiges Code-Sample. Ist für mich ein "Tutorial-Prinzip": Solange ich die Tutorial-Aussage nicht in Code umgesetzt auf meiner Platte habe, solange ist das Tut nichts als unbewiesene Worte.
)(Klammer zu )
Der frühe Apfel fängt den Wurm.
private Nachricht | Beiträge des Benutzers
Abt
myCSharp.de - Team

Avatar #avatar-4119.png


Dabei seit:
Beiträge: 16.030

Themenstarter:

beantworten | zitieren | melden

Also der funktionierende Code ist https://github.com/BenjaminAbt/MicrosoftBand2HeartRateApp/blob/master/src/BandApp/ViewModels/HeartRateViewModel.cs

Es würde wahrscheinlich 5 Minuten brauchen selbst eine entsprechende Beispielumsetzung zu realisieren, wenn hier die App nicht ausführen kann.
Wenn es um das "Beweisen" geht......

Und die Kernsache ist für mich die TaskFactory im entsprechend synchronisierten Kontext statt ein Dispatcher.
DI ist dann Beiwerk. Wobei das injezieren von Abhängigkeiten (über den Konstruktor) ohnehin nur zum Lösen von harten Abhängigkeiten ist und keine Pflicht DI zu nutzen, aber das ist ein anderes Thema.
private Nachricht | Beiträge des Benutzers
ErfinderDesRades
myCSharp.de - Experte

Avatar #avatar-3151.jpg


Dabei seit:
Beiträge: 5.299

beantworten | zitieren | melden

ich bin iwie zu dumm zum Downloaden - gibts da einen Sample-Solution-Zip?

Ich sehe da nur im Browser präsentiertes c#, müsste ich auskopieren, und überhaupt erst ein Sample-Projekt drumrum erstellen, was den Fehler reproduziert.
Dieser Beitrag wurde 1 mal editiert, zum letzten Mal von ErfinderDesRades am .
Der frühe Apfel fängt den Wurm.
private Nachricht | Beiträge des Benutzers
Abt
myCSharp.de - Team

Avatar #avatar-4119.png


Dabei seit:
Beiträge: 16.030

Themenstarter:

beantworten | zitieren | melden

Wie immer auf GitHub zuerst auf die Projekteseite (hier https://github.com/BenjaminAbt/MicrosoftBand2HeartRateApp) und dann rechts auf Download Zip.
private Nachricht | Beiträge des Benutzers
ErfinderDesRades
myCSharp.de - Experte

Avatar #avatar-3151.jpg


Dabei seit:
Beiträge: 5.299

beantworten | zitieren | melden

ah, danke.

kann ich aber aufgrund jedes der Requirements nicht öffnen:

Visual Studio 2015 Update 1
Microsoft Band 2 SDK (integrated as NuGet Package)
Microsoft Band (1 or 2) or FakeBand
Dieser Beitrag wurde 1 mal editiert, zum letzten Mal von ErfinderDesRades am .
Der frühe Apfel fängt den Wurm.
private Nachricht | Beiträge des Benutzers
ErfinderDesRades
myCSharp.de - Experte

Avatar #avatar-3151.jpg


Dabei seit:
Beiträge: 5.299

beantworten | zitieren | melden

Zitat
Es würde wahrscheinlich 5 Minuten brauchen selbst eine entsprechende Beispielumsetzung zu realisieren, wenn hier die App nicht ausführen kann.
(OT: Solche Bemerkungen kriegen es immer wieder hin, dass ich das Gefühl hab, ich soll mich dumm fühlen.
Du schaffst es sicherlich in 5 Minuten, ich aber vermutlich nicht. Allein die fehlerwerfenden Funktionalität - das müsste ich erst konzipieren, aufsetzen, testen, korrigieren...)

Zitat
Wenn es um das "Beweisen" geht......
Bingo! - es geht genau ums Beweisen.
Und ich sehe immer den Autor einer FAQ/Tutorial in der Beweispflicht, nicht den Leser.
Und bewiesen ist erst, wenns auf meinem System funktioniert, wie erwartet, und der Code auch sonst Tut-Aussagen bestätigt.


Beweis-Suche ist bei mir automatische Reaktion, und das hat mich tatsächlich erstmal von abgehalten, deinen Kernpunkt aufzufassen (ich kann halt nur eins nachm andern)
Zitat
Und die Kernsache ist für mich die TaskFactory im entsprechend synchronisierten Kontext statt ein Dispatcher.
Also pros und cons, die TaskFactory zu nehmen, wenn kein Dispatcher gegeben.

Da fällt mir tatsächlich was zu ein, sogar trotz misserfolgter Beweissuche - ist aber auch nix wirklich originelles:
pro:
Es funktioniert (nehme ich mal an). Das ist zunächstmal das entscheidende

con:
vermutlich wesentlich langsamer als Dispatcher.BeginInvoke. Ich hab bisserl IL gespickelt, Dispatcher macht was ganz anderes als TaskFactory.

Schlussfolgerung:
  1. Wenn verfügbar, immer den Dispatcher nehmen
  2. vlt. kann man sich noch iwas ausdenken, einen Dispatcher iwie doch noch herzukriegen
    Ich jdfs. akzeptiere nicht unbesehen, dass das ganz unmöglich ist, weil zumindest im Gui isser ja da.
    Ist halt die Herausforderung, es mit möglichst wenig Kopplung hinzukriegen, aber für solch gibts ja einige Mechanismen und Pattern.
  3. Testen.
    Wie schlimm ist der Performance-Nachteil?
Dieser Beitrag wurde 4 mal editiert, zum letzten Mal von ErfinderDesRades am .
Der frühe Apfel fängt den Wurm.
private Nachricht | Beiträge des Benutzers
t0ms3n
myCSharp.de - Member



Dabei seit:
Beiträge: 314

beantworten | zitieren | melden

Zitat von ErfinderDesRades
(Was ich noch nur ungern zugebe: )
Ausserdem könnte ich tatsächlich kein DI umsetzen. Ich weiß zwar im groben, was das ist, aber alle meine Versuche einer praktischen Test-Umsetzung führten zu mehr Uständlichkeit statt zu weniger.
Wäre jetzt ein neuer Anlauf, wenn mir hier jetzt was praktikables präsentiert würde.
Das wäre doch noch was für die FAQ oder eher vielleicht als Artikel? :)

Ich vermute mal, soweit ich dies nachvollziehen konnte, liegt der Hauptgrund warum man dies z.B. über einen Service nutzt in der Testbarkeit?
private Nachricht | Beiträge des Benutzers
Abt
myCSharp.de - Team

Avatar #avatar-4119.png


Dabei seit:
Beiträge: 16.030

Themenstarter:

beantworten | zitieren | melden

Natürlich ist es die Testbarkeit. Es ist aber auch die Wiederverwendbarkeit. Ich kann zB kein Dispatcher verwenden, wenn ich das ViewModel eben nicht nur in WPF verwende, sondern zB. auch in einer anderen Technologie.
Die Art und Weise des Dispatchers ist doch eine harte Bindung an WPF und untergräbt in meinen Augen der Sinn und Zweck eines MVVM ein dieser Stelle und in diesem Bezug massiv.
Zitat
(OT: Solche Bemerkungen kriegen es immer wieder hin, dass ich das Gefühl hab, ich soll mich dumm fühlen.
War zu keiner Zeit Sinn und Zweck.
Die 5 Minuten sind - wie bei solch einem Satz üblich - als Indikator für die Einfachheit der Nachvollziehbarkeit zu werten; nicht in einer totalen Aussage.
Muss man denn bei jedem Satz aufpassen, was man sagt....? Also....

Man sieht doch schon am gesamten Quellcode, dass das keine Welt ist das Ding in einer eigenen App nachzuvollziehen, wenn man kein VS2015 hat.
Das sind ~30 Zeilen Code?! Also irgendwie - sorry - mal auf dem Boden bleiben. =)

Und da fängt es schon an
Zitat
Schlussfolgerung:
Wenn verfügbar, immer den Dispatcher nehmen
Seh ich schon nicht so. Ich würde es "wenn notwendig, dann den Dispatcher nehmen" ausdrücken.
Das Ding ist halt NUR in der WPF GUI da. Aber.. entwickle ich ein ViewModel immer nur für WPF?
Soviel zum Thema "Perfektes Beispiel für die FAQ"... um Deine Argumente zu nehmen ;-)

Und daher hätte ich auch gern Feedback von WPF Profis, bevor das in die FAQ kommt - eben auch in Bezug auf Erfahrung zum Dispatcher, Wiederverwendbarkeit, Testbarkeit, Modularisierung etc etc. Das, was eben 'ne moderne Software (mit) ausmacht.

Mir ist völlig schleierhaft, wieso wir jetzt Dinge diskutieren, die weder notwendig noch zielführend sind.
private Nachricht | Beiträge des Benutzers
LaTino
myCSharp.de - Experte

Avatar #avatar-4122.png


Dabei seit:
Beiträge: 3.003
Herkunft: Thüringen

beantworten | zitieren | melden

Aus Neugier - spricht was dagegen, den Service nicht so eng an das vm zu binden, sondern ihm einen Delegaten zum Aktualisieren eines Wertes (hier: State) unterzuschieben?


public class MyViewModel : INotifyPropertyChanged
    {
        private readonly TaskFactory _uiTaskFactory;

        public MyViewModel( IAnyExternalService service )
        {
            _uiTaskFactory = new TaskFactory( TaskScheduler.FromCurrentSynchronizationContext() );
            //Call setzt im service die Aktualisierungsmethode
            service.Call(_uiTaskFactory.StartNew(() => service.Update(State)));
            
        }
        //Property State wie gehabt
    }


LaTino
Dieser Beitrag wurde 1 mal editiert, zum letzten Mal von LaTino am .
"Furlow, is it always about money?"
"Is there anything else? I mean, how much sex can you have?"
"Don't know. I haven't maxed out yet."
(Furlow & Crichton, Farscape)
private Nachricht | Beiträge des Benutzers
Abt
myCSharp.de - Team

Avatar #avatar-4119.png


Dabei seit:
Beiträge: 16.030

Themenstarter:

beantworten | zitieren | melden

Finde nicht, dass der Service dafür verantwortlich sein sollte oder gar kann.
Der kennt a) die Umstände nicht oder b) könnte durch einen Dritten kommen und unveränderlich sein.
private Nachricht | Beiträge des Benutzers
witte
myCSharp.de - Member



Dabei seit:
Beiträge: 955

beantworten | zitieren | melden

Zitat von Abt
Ich kann zB kein Dispatcher verwenden, wenn ich das ViewModel eben nicht nur in WPF verwende, sondern zB. auch in einer anderen Technologie.
Die Art und Weise des Dispatchers ist doch eine harte Bindung an WPF und untergräbt in meinen Augen der Sinn und Zweck eines MVVM ein dieser Stelle und in diesem Bezug massiv.
Hi,
dafür gibt es den SynchronizationContext der den jeweiligen GUI-Kontext abstrahiert.
private Nachricht | Beiträge des Benutzers
Abt
myCSharp.de - Team

Avatar #avatar-4119.png


Dabei seit:
Beiträge: 16.030

Themenstarter:

beantworten | zitieren | melden

Zitat von witte
dafür gibt es den SynchronizationContext
Genau das verwendet ja "meine" Factory (nur eben ohne den Dispatcher) auch ;-)

Mit der Suche nach fand ich aber auch das, was ich als nützliche Umsetzung ohne die Abhängigkeit auf den Dispatcher empfinde:

public class ThreadSafeObservableCollection<T> : ObservableCollection<T>
{
    private SynchronizationContext SynchronizationContext;

    public ThreadSafeObservableCollection()
    {
        SynchronizationContext = SynchronizationContext.Current;

        // current synchronization context will be null if we're not in UI Thread
        if (SynchronizationContext == null)
            throw new InvalidOperationException("This collection must be instantiated from UI Thread, if not, you have to pass SynchronizationContext to con                                structor.");
    }

    public ThreadSafeObservableCollection(SynchronizationContext synchronizationContext)
    {
        if (synchronizationContext == null)
            throw new ArgumentNullException("synchronizationContext");

        this.SynchronizationContext = synchronizationContext;
    }

    protected override void ClearItems()
    {
        this.SynchronizationContext.Send(new SendOrPostCallback((param) => base.ClearItems()), null);
    }

    protected override void InsertItem(int index, T item)
    {
        this.SynchronizationContext.Send(new SendOrPostCallback((param) => base.InsertItem(index, item)), null);
    }

    protected override void RemoveItem(int index)
    {
        this.SynchronizationContext.Send(new SendOrPostCallback((param) => base.RemoveItem(index)), null);
    }

    protected override void SetItem(int index, T item)
    {
        this.SynchronizationContext.Send(new SendOrPostCallback((param) => base.SetItem(index, item)), null);
    }

    protected override void MoveItem(int oldIndex, int newIndex)
    {
        this.SynchronizationContext.Send(new SendOrPostCallback((param) => base.MoveItem(oldIndex, newIndex)), null);
    }
}

Müsste man nur noch für die allgemeine Verwendung anpassen.
Hätte den Vorteil, dass man das asynchrone Verhalten nicht hat, wenn man es nicht braucht.
private Nachricht | Beiträge des Benutzers
ErfinderDesRades
myCSharp.de - Experte

Avatar #avatar-3151.jpg


Dabei seit:
Beiträge: 5.299

beantworten | zitieren | melden

echt - da war SynchronisizeContext eingebaut?

Dann ist gut möglich dasses recht sauber ist, denn in WinForms geht Control.BeginInvoke intern auch über genau diesen SynchronisizeContext.
Und die SynchronisizeContext-Choose ist sauber nachm Strategy-Pattern aufgezogen, um verschiedene Präsentationstechnologien entkoppeln zu können.


Trotzdem ist gut möglich, dass ein Dispatcher deutlich bessere Leistung bringt - zumindest in WinForms muss man sich ja nicht grade überschlagen vor Begeisterung.
Dieser Beitrag wurde 1 mal editiert, zum letzten Mal von ErfinderDesRades am .
Der frühe Apfel fängt den Wurm.
private Nachricht | Beiträge des Benutzers
witte
myCSharp.de - Member



Dabei seit:
Beiträge: 955

beantworten | zitieren | melden

... und hier ist noch eine Erweiterungsmethode SendAsync von Stephen Toub die asynchron warten kann.
private Nachricht | Beiträge des Benutzers
ErfinderDesRades
myCSharp.de - Experte

Avatar #avatar-3151.jpg


Dabei seit:
Beiträge: 5.299

beantworten | zitieren | melden

So, jetzt reden wir glaub über 3 oder 4 verschiedene Dinge, und keins davon kann ich testen - weiß nicht, obs euch da anders geht.

Also falls jemand sich die Mühe gemacht hat, eine Test-Solution für diese Fragen zu erstellen, wäre ich zumindest dankbar (ich weiß nicht, wie's den anderen geht), wenner die Sources hier anhängen könnte.
Dieser Beitrag wurde 1 mal editiert, zum letzten Mal von ErfinderDesRades am .
Der frühe Apfel fängt den Wurm.
private Nachricht | Beiträge des Benutzers
Abt
myCSharp.de - Team

Avatar #avatar-4119.png


Dabei seit:
Beiträge: 16.030

Themenstarter:

beantworten | zitieren | melden

Zitat von ErfinderDesRades
echt - da war SynchronisizeContext eingebaut?.
Zitat von Abt
_uiTaskFactory = new TaskFactory( TaskScheduler.FromCurrentSynchronizationContext() );
private Nachricht | Beiträge des Benutzers
Abt
myCSharp.de - Team

Avatar #avatar-4119.png


Dabei seit:
Beiträge: 16.030

Themenstarter:

beantworten | zitieren | melden

Gibt es Vorschläge - gerne auch von anderen - wie wir nun unsere FAQ in diesem Hinblick verbessern können?
Aktuell ist es leider nicht abgedeckt.
private Nachricht | Beiträge des Benutzers
Dominicano
myCSharp.de - Member



Dabei seit:
Beiträge: 23
Herkunft: Dajabon

beantworten | zitieren | melden

Hallo Abt

Ich habe da ein Server-Client-Projekte zur Steuerung von Licht und verschiedenen elektronischen Geräten - auch als Smarthome bekannt.
Es läuft auf Win 10 und Android absolut fehlerfrei, nur beim Raspberry Pi 3 mit WinIoT bekomme ich Ausnahmen gemeldet. Ich bin mir nicht sicher wo genau der Fehler ist, da es teilweise funktioniert.
Bsw. das bringt keine Ausnahme:


if (house_Start.ServerStatus)
                    Device.StartTimer(TimeSpan.FromSeconds(1), () => OnTimerTick());


private bool OnTimerTick()
        {
            Device.BeginInvokeOnMainThread(async () =>
            {
                if (house_Start.ServerStatus)
                    serverLabel.Text = "Server ist offline";
                else if (!house_Start.ClientStatus)
                    serverLabel.Text = "Client nicht gestartet";
                else
                    serverLabel.Text = "Server ist online";
            });
            return true;
        }
nur hier scheint es bei der zusammenführung der verschiedenen Tasks zu geben:


private void UpdateLampen()
        {
            Device.StartTimer(TimeSpan.FromMilliseconds(10), () => UpdateLabel());
        }


private bool UpdateLabel()
        {
            if (j < 32 && LampenLabel[j].BackgroundColor == Color.Red && Lampen[j])
                DispatcherHelper.CheckBeginInvokeOnUI(()=>
                //Dispatcher.BeginInvokeOnMainThread(() =>
                {
                    LampenLabel[0].BackgroundColor = Color.Green;
                    j++;
                });
            else if (j < 32 && LampenLabel[j].BackgroundColor == Color.Green & !Lampen[j])

                DispatcherHelper.CheckBeginInvokeOnUI(() =>
                //Dispatcher.BeginInvokeOnMainThread(() =>
                {
                    LampenLabel[j].BackgroundColor = Color.Red;
                    j++;
                });
            else
                j++;
            if (j > 31)
            {
                j = 0;
                return false;
            }
            else
                return true;
        }
Die Meldung von VisualStudio19 lautet:


The application called an interface that was marshalled for a different thread. (Exception from HRESULT: 0x8001010E (RPC_E_WRONG_THREAD))
Die Frage ist nun: wird dein TaskFactory Abhilfe schaffen? Ich habe schon mehrere "mögliche Lösungen" getestet (wie man noch im Code sieht), keine hat geholfen.

Danke schonmal im Voraus, Domi
private Nachricht | Beiträge des Benutzers
Abt
myCSharp.de - Team

Avatar #avatar-4119.png


Dabei seit:
Beiträge: 16.030

Themenstarter:

beantworten | zitieren | melden

Zitat
wird dein TaskFactory Abhilfe schaffen?
Weiß ich nich; eher unwahrscheinlich. Aber probiers doch aus..? Was hindert dich? Dein Code halt so, wie man das in WPF bzw. Xamarin, wenn ich das richtig sehe, nicht tun sollte.
Du wirst wahrscheinlich irgendwo ne manuelle Synchronisation vergessen haben, die notwendig ist, bekommst dafür nun die Quittung als Zugriffsverletzung.
Aber ich kenn auch Xamarin nicht mehr; Jahre nicht mehr verwendet.

Mit Bindings ( [Artikel] MVVM und DataBinding) bekommst halt Thread-Synchronität geschenkt, warum nutzt das nicht?
Für Xamarin: Das Model-View-ViewModel-Muster - Xamarin

Auch das ganze manuelle Updaten über einen Timer kannst Du damit prinzipiell sparen; oder zB Reactive Extensions / Reactive UI nutzen, das die Threads automatisch synchronisiert.
Der Thread ist darüber hinaus über 5 Jahre alt. Ich wüsste nicht mal mehr, was mein Code damals getan hat :-)
private Nachricht | Beiträge des Benutzers