445 Stimmen

Der aufrufende Thread kann auf dieses Objekt nicht zugreifen, da es einem anderen Thread gehört

Mein Code lautet wie folgt

public CountryStandards()
{
    InitializeComponent();
    try
    {
        FillPageControls();
    }
    catch (Exception ex)
    {
        MessageBox.Show(ex.Message, "Country Standards", MessageBoxButton.OK, MessageBoxImage.Error);
    }
}

/// <summary>
/// Fills the page controls.
/// </summary>
private void FillPageControls()
{
    popUpProgressBar.IsOpen = true;
    lblProgress.Content = "Loading. Please wait...";
    progress.IsIndeterminate = true;
    worker = new BackgroundWorker();
    worker.DoWork += new System.ComponentModel.DoWorkEventHandler(worker_DoWork);
    worker.ProgressChanged += new System.ComponentModel.ProgressChangedEventHandler(worker_ProgressChanged);
    worker.WorkerReportsProgress = true;
    worker.WorkerSupportsCancellation = true;
    worker.RunWorkerCompleted += new System.ComponentModel.RunWorkerCompletedEventHandler(worker_RunWorkerCompleted);
    worker.RunWorkerAsync();                    
}

private void worker_DoWork(object sender, System.ComponentModel.DoWorkEventArgs e)
{
    GetGridData(null, 0); // filling grid
}

private void worker_ProgressChanged(object sender, System.ComponentModel.ProgressChangedEventArgs e)
{
    progress.Value = e.ProgressPercentage;
}

private void worker_RunWorkerCompleted(object sender, System.ComponentModel.RunWorkerCompletedEventArgs e)
{
    worker = null;
    popUpProgressBar.IsOpen = false;
    //filling Region dropdown
    Standards.UDMCountryStandards objUDMCountryStandards = new Standards.UDMCountryStandards();
    objUDMCountryStandards.Operation = "SELECT_REGION";
    DataSet dsRegionStandards = objStandardsBusinessLayer.GetCountryStandards(objUDMCountryStandards);
    if (!StandardsDefault.IsNullOrEmptyDataTable(dsRegionStandards, 0))
        StandardsDefault.FillComboBox(cmbRegion, dsRegionStandards.Tables[0], "Region", "RegionId");

    //filling Currency dropdown
    objUDMCountryStandards = new Standards.UDMCountryStandards();
    objUDMCountryStandards.Operation = "SELECT_CURRENCY";
    DataSet dsCurrencyStandards = objStandardsBusinessLayer.GetCountryStandards(objUDMCountryStandards);
    if (!StandardsDefault.IsNullOrEmptyDataTable(dsCurrencyStandards, 0))
        StandardsDefault.FillComboBox(cmbCurrency, dsCurrencyStandards.Tables[0], "CurrencyName", "CurrencyId");

    if (Users.UserRole != "Admin")
        btnSave.IsEnabled = false;

}

/// <summary>
/// Gets the grid data.
/// </summary>
/// <param name="sender">The sender.</param>
/// <param name="pageIndex">Index of the page.( used in case of paging)   </pamam>
private void GetGridData(object sender, int pageIndex)
{
    Standards.UDMCountryStandards objUDMCountryStandards = new Standards.UDMCountryStandards();
    objUDMCountryStandards.Operation = "SELECT";
    objUDMCountryStandards.Country = txtSearchCountry.Text.Trim() != string.Empty ? txtSearchCountry.Text : null;
    DataSet dsCountryStandards = objStandardsBusinessLayer.GetCountryStandards(objUDMCountryStandards);
    if (!StandardsDefault.IsNullOrEmptyDataTable(dsCountryStandards, 0) && (chkbxMarketsSearch.IsChecked == true || chkbxBudgetsSearch.IsChecked == true || chkbxProgramsSearch.IsChecked == true))
    {
        DataTable objDataTable = StandardsDefault.FilterDatatableForModules(dsCountryStandards.Tables[0], "Country", chkbxMarketsSearch, chkbxBudgetsSearch, chkbxProgramsSearch);
        dgCountryList.ItemsSource = objDataTable.DefaultView;
    }
    else
    {
        MessageBox.Show("No Records Found", "Country Standards", MessageBoxButton.OK, MessageBoxImage.Information);
        btnClear_Click(null, null);
    }
}

Der Schritt objUDMCountryStandards.Country = txtSearchCountry.Text.Trim() != string.Empty ? txtSearchCountry.Text : null; in get grid data löst eine Ausnahme aus

Der aufrufende Thread kann auf dieses Objekt nicht zugreifen, da ein anderer Thread es besitzt.

Was ist hier los?

3voto

Jonathan Plumb Punkte 417

Es gibt definitiv verschiedene Möglichkeiten, dies zu tun, je nach Ihren Bedürfnissen.

Eine Möglichkeit, wie ich einen UI-Aktualisierungsthread (der nicht der Haupt-UI-Thread ist) verwende, besteht darin, dass der Thread eine Schleife startet, in der die gesamte logische Verarbeitungsschleife auf dem UI-Thread aufgerufen wird.

Ejemplo:

public SomeFunction()
{
    bool working = true;
    Thread t = new Thread(() =>
    {
        // Don't put the working bool in here, otherwise it will 
        // belong to the new thread and not the main UI thread.
        while (working)
        {
            Application.Current.Dispatcher.Invoke(() =>
            {
                // Put your entire logic code in here.
                // All of this code will process on the main UI thread because
                //  of the Invoke.
                // By doing it this way, you don't have to worry about Invoking individual
                //  elements as they are needed.
            });
        }
    });
}

Damit wird der Code vollständig im Haupt-UI-Thread ausgeführt. Dies kann ein Vorteil für Amateurprogrammierer sein, die Schwierigkeiten haben, sich mit Thread-übergreifenden Operationen zurechtzufinden. Bei komplexeren Benutzeroberflächen kann dies jedoch leicht zum Nachteil werden (vor allem, wenn Animationen ausgeführt werden). In Wirklichkeit geht es nur darum, ein System zur Aktualisierung der Benutzeroberfläche vorzutäuschen und dann zurückzukehren, um alle Ereignisse zu behandeln, die anstelle von effizienten Cross-Threading-Operationen ausgelöst wurden.

1voto

Bart Vanseer Punkte 299

Manchmal kann es das von Ihnen erstellte Objekt sein, das die Ausnahme auslöst, und nicht das Ziel, auf das ich offensichtlich geschaut habe.

In meinem Code hier:

xaml-Datei:

<Grid Margin="0,0,0,0" VerticalAlignment="Stretch" HorizontalAlignment="Stretch" >
    <TextBlock x:Name="tbScreenLog" VerticalAlignment="Stretch" Background="Black" FontSize="12" Foreground="#FF919191" HorizontalAlignment="Stretch"/>
</Grid>

xaml.cs-Datei:

System.Windows.Documents.Run rnLine = new System.Windows.Documents.Run(Message.Item2 + "\r\n");
rnLine.Foreground = LineAlternate ? Brushes.Green : Brushes.Orange;

Dispatcher.Invoke(()=> {
    tbScreenLog.Inlines.Add(rnLine);
});
LineAlternate = !LineAlternate;

Ich bekam die Ausnahme über den Zugriff auf ein Objekt von einem anderen Thread, aber ich war es auf dem UI-Thread aufrufen?

Nach einer Weile wurde mir klar, dass es nicht um das TextBlock-Objekt ging, sondern um das Run-Objekt, das ich vor dem Aufruf erstellt hatte.

Die Änderung des Codes hat mein Problem gelöst:

Dispatcher.Invoke(()=> {
    Run rnLine = new Run(Message.Item2 + "\r\n");
    rnLine.Foreground = LineAlternate ? Brushes.Green : Brushes.Orange;
    tbScreenLog.Inlines.Add(rnLine);
});
LineAlternate = !LineAlternate;

0voto

FindOutIslamNow Punkte 1014

Eine weitere Lösung besteht darin, sicherzustellen, dass Ihre Steuerelemente im UI-Thread erstellt werden und nicht beispielsweise von einem Hintergrund-Worker-Thread.

0voto

user8128167 Punkte 5968

Ich habe immer den Fehler, wenn ich kaskadierende Comboboxen zu meiner WPF-Anwendung hinzugefügt, und behoben den Fehler, indem Sie diese API:

    using System.Windows.Data;

    private readonly object _lock = new object();
    private CustomObservableCollection<string> _myUiBoundProperty;
    public CustomObservableCollection<string> MyUiBoundProperty
    {
        get { return _myUiBoundProperty; }
        set
        {
            if (value == _myUiBoundProperty) return;
            _myUiBoundProperty = value;
            NotifyPropertyChanged(nameof(MyUiBoundProperty));
        }
    }

    public MyViewModelCtor(INavigationService navigationService) 
    {
       // Other code...
       BindingOperations.EnableCollectionSynchronization(AvailableDefectSubCategories, _lock );

    }

Für weitere Informationen, siehe https://msdn.microsoft.com/query/dev14.query?appId=Dev14IDEF1&l=EN-US&k=k(System.Windows.Data.BindingOperations.EnableCollectionSynchronization);k(TargetFrameworkMoniker-.NETFramework,Version%3Dv4.7);k(DevLang-csharp)&rd=true

0voto

RonnyR Punkte 178

Ich stieß auf diesen Fehler seltsam auf das zweite Element aus einem WPF-Steuerelement ausgewählt.

Der Grund dafür war, dass ich die Daten in einen RX SourceCache geladen hatte und die geladenen Elemente ObservableCollections als Navigationseigenschaften hatten, die in eine CollectionView gewickelt waren. Die ObservableCollections sind mit dem UIThread verbunden und die Daten wurden durch den WorkerThread geladen. Da die CollectionView nur bei der Anzeige des ersten Elements befüllt wurde, trat das Problem mit dem anderen Thread erst bei der Auswahl des zweiten Elements auf.

Die Lösung wäre, die Unterlisten als ReadOnlyObservableCollections in das ViewModel zu verschieben und die vollständige Liste der Unterelementtabelle nach dem aktuell ausgewählten Hauptelement zu filtern.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X