Laden...

Threadübergreifender Zugriff auf ein Objekt schlägt fehl

Erstellt von chhoelzle vor 5 Jahren Letzter Beitrag vor 5 Jahren 1.673 Views
C
chhoelzle Themenstarter:in
2 Beiträge seit 2018
vor 5 Jahren
Threadübergreifender Zugriff auf ein Objekt schlägt fehl

Hallo
Ich habe folgende Klasse

using BFH.Model;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;

namespace BFH.CustomControls
{
    /// <summary>
    /// Interaktionslogik für SafetyStatus.xaml
    /// </summary>
    public partial class SafetyStatusView : Window
    {
        private SafetyStatus SafetyStatus;
        private TextBlock[] TextBlocks;
        public Border[] Borders;

        public SafetyStatusView()
        {
            InitializeComponent();

            SafetyStatus = new SafetyStatus();
            SafetyStatus.PropertyChanged += new PropertyChangedEventHandler(SafetyStatusPropertyChanged);

            TextBlocks = new TextBlock[SafetyStatus.Status.Count];
            Borders = new Border[SafetyStatus.Status.Count];

            BuildGUIContent();

        }

        #region methods
        private void BuildGUIContent()
        {
            for (int i = 0; i < SafetyStatus.Status.Count; i++)
            {
                Grid.RowDefinitions.Add(new RowDefinition());

                TextBlocks[i] = new TextBlock();
                Borders[i] = new Border();

                Grid.Children.Add(TextBlocks[i]);
                Grid.Children.Add(Borders[i]);

                Grid.SetRow(TextBlocks[i], i);

                Grid.SetRow(Borders[i], i);
                Grid.SetColumn(Borders[i], 1);

                TextBlocks[i].Text = SafetyStatus.Text[i];
                TextBlocks[i].FontFamily = new FontFamily("Segoe UI Semibold");
                TextBlocks[i].FontSize = 16;
                TextBlocks[i].Foreground = Brushes.White;
                TextBlocks[i].SetValue(TextBlock.MarginProperty, new Thickness(2));

                if (ConnectPLC.Read_BOOL_fromPLC(SafetyStatus.SignalNames[i],true))
                    Borders[i].Background = Brushes.Green;
                else
                    Borders[i].Background = (SolidColorBrush)(new BrushConverter().ConvertFrom("#1C536F"));

                Borders[i].SetValue(Border.CornerRadiusProperty, new CornerRadius(10));
                Borders[i].SetValue(Border.MarginProperty, new Thickness(2));
            }
        }

        private void SafetyStatusPropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            for (int i = 0; i < SafetyStatus.Status.Count; i++)
            {
                if (SafetyStatus.Status[i])
                    try
                    {
                        Borders[i].Background = Brushes.Green;
                    }
                    catch (Exception err)
                    {
                        MessageBox.Show(err.ToString());
                    }
                else
                    try
                    {
                    Borders[i].Background = (SolidColorBrush)(new BrushConverter().ConvertFrom("#1C536F"));
                    }
                    catch (Exception err)
                    {
                        MessageBox.Show(err.ToString());
                    }
            }
        }
        #endregion
    }
}

Wenn der Eventhandler die SafetyStatusPropertyChanged Funktion aufruft und die Borders_.Background beschreiben sollte, tritt folgender Fehler auf:

Fehlermeldung:
System.InvalidOperationExeption: Der aufrufende Thread kann nicht auf dieses Objekt zugreifen, da sich das Objekt im Besitz eines anderen Threads befindet ....

Wie kann ich dies Thread übergreifend zuweisen?

4.930 Beiträge seit 2008
vor 5 Jahren

Hallo,

verwendest du denn eigene Threads (oder Tasks) in der Klasse SafetyStatus?

Schau in [FAQ] Controls von Thread aktualisieren lassen (Control.Invoke/Dispatcher.Invoke).

PS: Editiere deinen Beitrag und füge die Code (C#)-Tags hinzu.

2.207 Beiträge seit 2011
vor 5 Jahren

Hallo chhoelzle,

[Hinweis] Wie poste ich richtig? Bitte benutze Code-Tags.

Gruss

Coffeebean

C
chhoelzle Themenstarter:in
2 Beiträge seit 2018
vor 5 Jahren

Eigentlich brauche ich nach meiner Meinung keinen eigenen Thread

Das einzige ist der PropertyChangedEventHandler, mit welchem ich die Funktion benötige, gibt wohl einen eigenen Thread, nehme ich an.

1.029 Beiträge seit 2010
vor 5 Jahren

Hi,

was aus dem bereits verlinkten Artikel für dich hätte hervorgehen sollen:

Du hast offensichtlich neben deinem GUI-Thread wohl mindestens einen 2. Thread - und da du aus diesem 2. Thread heraus die GUI änderst - wirft er dir zu Recht einen Fehler um die Ohren. Wie man das korrigiert - ist im Artikel beschrieben.

LG

16.806 Beiträge seit 2008
vor 5 Jahren

Puh, also der Code ist deutlich verbesserungswürdig (besonders die Namespaces, Struktur, Namings und [Artikel] Drei-Schichten-Architektur )

Letzten Endes sieht der Code danach aus, dass der Event in SafetyStatus in einem anderen Thread läuft.
Das erklärt auch den Fehler.

Da für uns SafetyStatus nicht ersichtlich ist, solltest Du Dir die Doku oder dessen Code anschauen.
Letzten Endes ist aber wie gesagt auch [FAQ] Controls von Thread aktualisieren lassen (Control.Invoke/Dispatcher.Invoke) die Lösung - egal was in SafetyStatus steckt.