Question

Dans l'exemple de code suivant, je souhaite modifier la couleur du texte de premier plan d'un TextBox dans mon BackgroundThread , mais l'erreur est renvoyée :

  

Ce fil ne peut pas accéder à cet objet   car il est dans un autre thread.

Que dois-je changer dans le code ci-dessous pour que le thread de travail d'arrière-plan puisse modifier la couleur de premier plan dans la zone de texte?

Réponse:

Merci Andy, c'était juste ce petit oubli, voici le code corrigé pour le bien de la postérité:

using System.Windows;
using System.ComponentModel;
using System.Threading;
using System.Windows.Media;

namespace TestBackgroundWorker7338
{
    public partial class Window1 : Window
    {
        private BackgroundWorker _worker;
        int _percentageFinished = 0;

        public Window1()
        {
            InitializeComponent();
            ButtonCancel.IsEnabled = false;
        }

        private void Button_Start(object sender, RoutedEventArgs e)
        {
            _worker = new BackgroundWorker();
            _worker.WorkerReportsProgress = true;
            _worker.WorkerSupportsCancellation = true;

            _worker.DoWork += (s, args) =>
            {
                BackgroundWorker worker = s as BackgroundWorker;
                int numberOfTasks = 300;
                for (int i = 1; i <= numberOfTasks; i++)
                {
                    if (worker.CancellationPending)
                    {
                        args.Cancel = true;
                        return;
                    }

                    Thread.Sleep(10);
                    float percentageDone = (i / (float)numberOfTasks) * 100f;
                    worker.ReportProgress((int)percentageDone);
                }
            };

            _worker.ProgressChanged += (s,args) =>
            {
                _percentageFinished = args.ProgressPercentage;
                ProgressBar.Value = _percentageFinished;
                Message.Text = _percentageFinished + "% finished";
                if (_percentageFinished < 500)
                {
                    Message.Text = "stopped at " + _percentageFinished + "%";
                }
                else
                {
                    Message.Text = "finished";
                }

                if (_percentageFinished >= 70)
                {
                    InputBox.Foreground = new SolidColorBrush(Colors.Red);
                }
                else if (_percentageFinished >= 40)
                {
                    InputBox.Foreground = new SolidColorBrush(Colors.Orange);
                }
                else if (_percentageFinished >= 10)
                {
                    InputBox.Foreground = new SolidColorBrush(Colors.Brown);
                }
                else
                {
                    InputBox.Foreground = new SolidColorBrush(Colors.Black);
                }

            };

            _worker.RunWorkerCompleted += (s,args) =>
            {
                ButtonStart.IsEnabled = true;
                ButtonCancel.IsEnabled = false;
                ProgressBar.Value = 0;
            };

            _worker.RunWorkerAsync();
            ButtonStart.IsEnabled = false;
            ButtonCancel.IsEnabled = true;

        }

        private void Button_Cancel(object sender, RoutedEventArgs e)
        {
            _worker.CancelAsync();
        }
    }
}
Était-ce utile?

La solution

Le délégué ProgressChanged est exécuté sur le thread d'interface utilisateur. Si vous définissez la BackgroundColor à la place de DoWork , cela devrait vous permettre de définir la couleur sans l'erreur.

Autres conseils

Comme Andy l'a dit, les propriétés des contrôles doivent être modifiées sur le thread d'interface utilisateur.

WPF fournit une classe Dispatcher qui facilite le routage des appels de contrôles vers le thread d'interface utilisateur approprié. Les contrôles dans WPF exposent un objet de propriété Dispatcher pour répartir l'appel vers un thread d'interface utilisateur approprié.

Vous pouvez utiliser ceci comme suit (j'ajouterais ceci après la ligne worker.ReportProgress ((int) percentDone); dans la méthode Button_Start ):

// the Window class exposes a Dispatcher property, alternatively you could use
// InputBox.Dispatcher to the same effect
if (!Dispatcher.CheckAccess())
     {
        Dispatcher.Invoke(new Action(() => ChangeForegroundColor(percentageDone));
     }
     else
     {
        ChangeForegroundColor(percentageDone);
     }

...
private void ChangeForegroundColor(int percentageDone)
{
    if (percentageDone >= 90)
    {
        InputBox.Foreground = new SolidColorBrush(Colors.Red);
    }
    else if(percentageDone >=10)
    {
        InputBox.Foreground = new SolidColorBrush(Colors.Orange);
    }
}
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top