[WPF] Modifier un contrôle depuis un autre thread en WPF

Dans une application WPF, l’utilisation de plusieurs threads pour la modification de contrôles est plus compliquée qu’il n’y parait. Un contrôle ne peut être modifier que par le thread à qui il appartient.

 

Par exemple :

 

– MainWindow.xaml

 

<Window x:Class="Threads.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525" Loaded="Window_Loaded">
  <Grid>
    <Label Content="Label" Height="28" HorizontalAlignment="Left" Name="label1" />
  </Grid>
</Window>

 

– MainWindow.xaml.cs

 

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
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.Navigation;
using System.Windows.Shapes;
using System.Threading;

namespace Threads
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }

        private void Window_Loaded(object sender, RoutedEventArgs e)
        {
            // Create Thread
            Thread myThread = new Thread(ModifyLabel);

            // Start Thread
            myThread.Start();

            // Wait for 3sec
            Thread.Sleep(3000);

            // Stop Thread
            myThread.Abort();
        }

        public void ModifyLabel()
        {
            label1.Content = "my content";
        }
    }
}

 

Lorsqu’on lance ce programme l’erreur suivante apparait :

 

The calling thread cannot access this object because a different thread owns it.

 

En fait le Label n’appartient pas à notre thread myThread.

Pour pallier à ce problème, il faut utiliser le Dispatcher du contrôle comme ci-dessous

 

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
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.Navigation;
using System.Windows.Shapes;
using System.Threading;

namespace Threads
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }

        private void Window_Loaded(object sender, RoutedEventArgs e)
        {
            // Create Thread
            Thread myThread = new Thread(ModifyLabel);

            // Start Thread
            myThread.Start();

            // Wait for 3sec
            Thread.Sleep(3000);

            // Stop Thread
            myThread.Abort();
        }

        public void ModifyLabel()
        {
            label1.Dispatcher.Invoke(
            System.Windows.Threading.DispatcherPriority.Normal,
            new Action(
            delegate()
            {
                label1.Content = "my content";
                label1.FontSize = 10;
            }
            ));
        }
    }
}

Le projet de cette article est disponible ici.