Freitag, Juni 5, 2020

WPF-Cross-Thread-Objekt Zugreifen

Ich habe ein Problem bezüglich cross-thread-Aufrufe in WPF.

            foreach (RadioButton r in StatusButtonList)
        {
            StatusType status = null;
            r.Dispatcher.Invoke(new ThreadStart(() => status= ((StatusButtonProperties)r.Tag).StatusInformation));
            if (AppLogic.CurrentStatus == null || AppLogic.CurrentStatus.IsStatusNextLogical(status.Code))
            {
                SolidColorBrush green = new SolidColorBrush(Color.FromRgb(102, 255, 102));
                r.Dispatcher.Invoke(new ThreadStart(() =>  r.Background = green));
            }
            else
            {
                SolidColorBrush red = new SolidColorBrush(Color.FromRgb(255, 0, 0));
                r.Dispatcher.Invoke(new ThreadStart(() => r.Background = red));
            }
        }

Wenn ich diesen code ausführen, funktioniert es einwandfrei für die erste iteration. Aber während der zweiten iteration die Zeile:

  r.Dispatcher.Invoke(new ThreadStart(() => status= ((StatusButtonProperties)r.Tag).StatusInformation))

Ursachen dieser Ausnahme:

Cannot use a DependencyObject that belongs to a different thread than its parent Freezable.

Habe ich versucht, ein paar Lösungen, aber ich kann nicht finden, alles zu verarbeiten.

Jede Hilfe dankbar!

  • Erstellen SolidColorBrush-rot + grün in einem thread, das ist nicht das gleiche wie r.Dispatcher.Aufrufen…?
  • Warum sind Sie mit einem neuen thread für diejenigen, die setter? Da Sie mit Invoke(), ist es blockiert, bis der thread fertig ist mit seiner Arbeit, so dass es wahrscheinlich verlangsamt die ganze Sache nach unten.

3 Kommentare

  1. 5

    Würde ich diese umschreiben zu:

    r.Dispatcher.Invoke(new Action(delegate()
    {
        status = ((StatusButtonProperties)r.Tag).StatusInformation;
    
        if (AppLogic.CurrentStatus == null || AppLogic.CurrentStatus.IsStatusNextLogical(status.Code))
        {
            r.Background = Brushes.Green;
        }
        else
        {
            r.Background = Brushes.Red;
        }
    
    }));
    • Funktioniert auch, danke!
  2. 3
        r.Dispatcher.Invoke(
          System.Windows.Threading.DispatcherPriority.Normal,
          new Action(
            delegate()
            {
                    //DO YOUR If... ELSE STATEMNT HERE
            }
        ));
    • Funktioniert perfekt, vielen Dank!
  3. 1

    Gehe ich davon aus, dass Sie in einem anderen thread als das man was erstellt diese RadioButtons. Ansonsten ist der Aufruf keinen Sinn macht. Seit der Erstellung der SolidColorBrush in diesem thread, Sie haben bereits eine potenzielle cross-thread, dort anrufen.

    Es würde mehr Sinn machen, um die cross-thread-Aufrufe mehr „chunky“, also setzen Sie alles in der foreach-Schleife in einer einzigen Invoke-Aufruf.

    foreach (RadioButton r in StatusButtonList)
    {
        r.Dispatcher.Invoke(new ThreadStart(() => 
            {
                StatusType status = ((StatusButtonProperties)r.Tag).StatusInformation;
                if (AppLogic.CurrentStatus == null || AppLogic.CurrentStatus.IsStatusNextLogical(status.Code))
                {
                    SolidColorBrush green = new SolidColorBrush(Color.FromRgb(102, 255, 102));
                    r.Background = green;
                }
                else
                {
                    SolidColorBrush red = new SolidColorBrush(Color.FromRgb(255, 0, 0));
                    r.Background = red;
                }
            });
    }

    Könnten Sie auch erwägen BeginInvoke wenn die verschiedenen Aufrufe werden nicht interdependant.

Kostenlose Online-Tests