ho una DLL che gestisce un thread di lavoro e invia gli eventi indietro all'applicazione - ha funzionato perfettamente su Windows Form, passato a WPF e tutto smesso di funzionare. Sto sfondando la testa contro un muro di mattoni per 4 ore cercando di farlo funzionare. Ma la soluzione con cui ho finito, grazie all'intervento di sicurezza sicura del thread UI di Microsoft EnableCollectionSynchronization, offre un'implementazione davvero pulita per risolvere questo problema.
Questa raccolta estende ObservableCollection e implementa EnableCollectionSynchronization rendendo questi oggetti utilizzabili tra WPF e anche gli utenti in background.
Edit: Microsoft's docs dire quanto segue, quindi ho intenzione di assumere che la condivisione contesto dell'oggetto non importa.
Il parametro context è un oggetto arbitrario che è possibile utilizzare per le informazioni note quando si abilita la sincronizzazione di raccolta. Il contesto può essere null.
ThreadSafeCollection.cs
using System.Collections.ObjectModel;
using System.Windows.Data;
namespace NSYourApplication
{
/// <summary>
/// This ObservableCollection is thread safe
/// You can update it from any thread and the changes will be safely
/// marshalled to the UI Thread WPF bindings
/// Thanks Microsoft!
/// </summary>
/// <typeparam name="T">Whatever type of collection you want!</typeparam>
public class ThreadSafeCollection<T> : ObservableCollection<T>
{
private static object __threadsafelock = new object();
public ThreadSafeCollection()
{
BindingOperations.EnableCollectionSynchronization(this, __threadsafelock);
}
}
}
Esempio WindowViewModel WindowViewModel.cs
namespace NSYourApplication
{
/// <summary>
/// Example View
/// BaseModelView implements "PropertyChanged" to update WPF automagically
/// </summary>
class TestViewModel : BaseModelView
{
public ThreadSafeCollection<string> StringCollection { get; set; }
/// <summary>
/// background thread implemented elsewhere...
/// but it calls this method eventually ;)
/// Depending on the complexity you might want to implement
/// [MethodImpl(MethodImplOptions.Synchronized)]
/// to Synchronize multiple threads to prevent chase-conditions,deadlocks etc
/// </summary>
public void NonUIThreadMethod()
{
// No dispatchers or invokes required here!
StringCollection.Add("Some Text from a background worker");
}
/// <summary>
/// Somewhere in the UIThread code it'll call this method
/// </summary>
public void UIThreadMethod()
{
StringCollection.Add("This text come from UI Thread");
}
/// <summary>
/// Constructor, creates a thread-safe collection
/// </summary>
public TestViewModel()
{
StringCollection = new ThreadSafeCollection<string>();
}
}
}
utilizzo in una casella di riepilogo in una finestra XAML/controllo MainWindow.xaml
<ListBox x:Name="wpfStringCollection" ItemsSource="{Binding StringCollection,Mode=OneWay}">
</ListBox>
fonte
2017-08-21 23:21:11
Quindi aggiungendoli alla raccolta di elementi in un thread in background aggiornerà i controlli sul thread dell'interfaccia utente? Come funziona? – Mark
No, li aggiungi nel thread del dispatcher, ma con una priorità più bassa e in piccoli blocchi quindi l'interfaccia utente rimane reattiva – Bubblewrap
Vedo, grazie darò una prova – Mark