Je suis au milieu d'une application MVVM. Ici, j'ai une collection (ObservableCollection) qui peut ajouter, supprimer des opérations effectuées à partir d'un thread différent. Voici le code. J'ai essayé de le garder aussi complet que possible:WPF Dispatcher ne fonctionne pas comme BGWorker
private Thread _thread = null;
private Dispatcher _UIDispatcher = null;
public ObservableCollection<string> ListOfStrings { get; private set; }
Le cteur:
public MainWindowViewModel(Dispatcher dispatcher)
{
this.ListOfStrings = new ObservableCollection<string>();
this.StartAsyncCall = new RelayCommand(AsyncCall, CanCallAsynch);
this._UIDispatcher = dispatcher;
}
Je prends comme référence le répartiteur de la vue (Il est pas une bonne pratique mais comme il fait des tests d'unité Gary Hall a suggéré une approche intéressante en utilisant AOP, mais je peux le changer plus tard quand même.). Et cette méthode que j'appelle via une commande
private void AsyncCall()
{
if (this.ListOfStrings.Count > 0)
this.ListOfStrings.Clear();
//_backgroundWorker.RunWorkerAsync();
this._thread = new Thread(new ThreadStart(AddNumbersToList));
this._thread.IsBackground = true;
this._thread.Start();
}
private void AddNumbersToList()
{
Action delAddNum = new Action(AddNumbersToList);
for (int i = 0; i < 100000000; i++)
{
if (null != this._UIDispatcher &&
!this._UIDispatcher.CheckAccess())
_UIDispatcher.Invoke(DispatcherPriority.Render,delAddNum);
else
{
this.ListOfStrings.Add(Convert.ToString(i.ToString()));
}
}
}
Le ObservableCollection est lié à une zone de liste dans la vue. L'effet que je m'attendais à ce que l'ObservableCollection reçoive de nouveaux numéros, ils devraient être affichés dans l'IU. L'interface utilisateur serait également sensible. Mais étrangement, l'interface utilisateur ne répond pas. La même chose quand j'essaie d'atteindre via un travailleur de fond est finement atteint. Est-ce que quelqu'un peut me dire où je me trompe? Je ne veux pas aller pour le travailleur d'arrière-plan car je veux la flexibilité d'utiliser la classe Thread plus granulaire. est sous le code que j'utilise avec BGWorker et il fonctionne très bien:
private BackgroundWorker _backgroundWorker = new BackgroundWorker();
Le CTOR:
public MainWindowViewModel()
{
this.ListOfStrings = new ObservableCollection<string>();
this.StartAsyncCall = new RelayCommand(AsyncCall, CanCallAsynch);
_backgroundWorker.DoWork += AddNumbersToList;
_backgroundWorker.RunWorkerCompleted += this.LoadResultsCompleted;
_backgroundWorker.WorkerReportsProgress = true;
_backgroundWorker.ProgressChanged += new ProgressChangedEventHandler(_backgroundWorker_ProgressChanged);
}
Les méthodes:
private void AsyncCall()
{
if (this.ListOfStrings.Count > 0)
this.ListOfStrings.Clear();
this._backgroundWorker.RunWorkerAsync();
}
private void AddNumbersToList(object sender, DoWorkEventArgs e)
{
BackgroundWorker bw = sender as BackgroundWorker;
if(null!=bw)
for (int i = 0; i < 10; i++)
{
bw.ReportProgress(0, i);
Thread.Sleep(1000);
}
}
private void LoadResultsCompleted(object sender, RunWorkerCompletedEventArgs e)
{
if (e.Error == null)
{
this.ListOfStrings.Add("Completed");
CommandManager.InvalidateRequerySuggested();
}
}
//This works just wonderful:
void _backgroundWorker_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
this.ListOfStrings.Add(Convert.ToString(e.UserState.ToString()));
}
Nous vous remercions à l'avance.
..James
ne pouvait pas le fait que vous ajoutez 100000000 éléments dans votre approche tracée vs 10 avec le BackgroundWorker ont quelque chose à voir avec ça? – madd0
Je ne pense pas. Vous pouvez remplacer le code du module de thread par celui du module BGWorker. Le résultat reste toujours le même. – James
Il m'est arrivé de lire quelque part que Dispatcher ne fournit pas de fonctionnalité de multithreading exactement. Mais je ne suis pas très clair à ce sujet. J'essaie de l'utiliser dans WPF comme j'ai utilisé "Invoke" en winforms. Mais alors, quelle devrait être mon approche à cela? – James