Le problème est classique: vous créez un thread pour réaliser une opération, et vous voulez que ce thread modifie un composant graphique (comme une ProgressBar par exemple). La solution, que vous devez sûrement connaître, consiste à exécuter l'action en question sur le même thread que celui de l'UI, c'est à dire, en WPF, utiliser la fonction BeginInvoke de la propriété Dispatcher de votre contrôle. Si vous avez un grand nombre de modifications de votre interface utilisateur qui sont effectués depuis une ou plusieurs tâches, plutôt que d'appeler BeginInvoke de multiples fois, il existe une solution toute simple, qui consiste à créer et lancer vos tâches en utilisant une TaskFactory à laquelle vous aurez donné comme TaskScheduler celui chargé de gérer l'UI.
Pour cela, c'est très simple:
public partial class MyUserControl : UserControl
{
private TaskFactory _ui;
public MyUserControl()
{
InitializeComponent();
_ui = new TaskFactory(TaskScheduler.FromCurrentSynchronizationContext());
_ui.StartNew(() => { Width = 100; } );
}
}
Et donc toutes les tâches que vous créerez depuis cette TaskFactory seront "schedulées" (je ne sais pas trop comment traduire ça au mieux) sur le thread de l'UI, et donc vous dispensera d'utiliser Dispatcher.BeginInvoke à tout va.
A noter que le code suivant fonctionne tout aussi bien:
public partial class MyUserControl : UserControl
{
private TaskScheduler _ts;
public MyUserControl()
{
InitializeComponent();
_ts = TaskScheduler.FromCurrentSynchronizationContext();
Task.Factory.StartNew(() => { Width = 100; }, _ts);
}
}