Как обновить WPF Control из Задачи TPL? - PullRequest
2 голосов
/ 11 октября 2011

Как обновить элемент управления WPF из задачи TPL?

Хорошо, поэтому я попробовал некоторые сценарии использования Dispatcher, но в любом случае он выдает ошибку.Мне нужна помощь, ребята!

private void Window_Loaded(object sender, RoutedEventArgs e)
    {
        //Application.Current.Dispatcher.Invoke((Action)MyInit); 
        backgroundDBTask = Task.Factory.StartNew(() =>
            {
                DoSomething1();
            }, TaskCreationOptions.LongRunning);
        backgroundDBTask.ContinueWith((t) =>
        {
            // ... UI update work here ...
        },             
        TaskScheduler.FromCurrentSynchronizationContext());             
    }

    void DoSomething1()
    {
        // MyInit();
        int number = 0;
        while (true)
        {
            if (state)
            {
                Thread.Sleep(1000);
                Console.WriteLine("Begin second task... {0}", number++);
               // mostCommonWords = GetMostCommonWords(words) + string.Format("   Begin second task... {0}", number++);

                textBox2.Text = (number++).ToString(); // Gives the error

                Dispatcher.BeginInvoke(); // How it should be ?
            }
        }
    }

Спасибо!

Ответы [ 2 ]

5 голосов
/ 11 октября 2011

Вам необходимо передать делегата, который выполняет вашу работу, BeginInvoke.
BeginInvoke будет асинхронно запускать этого делегата в потоке пользовательского интерфейса.

Например:

Dispatcher.BeginInvoke(new Action(delegate {
    textBox2.Text = number.ToString(); 
}));
3 голосов
/ 10 марта 2014

Я знаю, что здесь уже есть ответ, и то, что Слэкс дал вам, исправит его, поскольку он будет использовать поток Dispatcher, поэтому не будет выдавать исключение для accessing a control from a different thread.

Но я замечаю это.

 backgroundDBTask = Task.Factory.StartNew(() =>
        {
            DoSomething1();
        }, TaskCreationOptions.LongRunning);

С этим

 backgroundDBTask.ContinueWith((t) =>
    {
        // ... UI update work here ...
    },             
    TaskScheduler.FromCurrentSynchronizationContext());   

У вас уже есть комментарий, где обновить пользовательский интерфейс, и вы также дали ему SynchronizationContext.Почему вы все еще пытаетесь обновить UI внутри вашего DoSomething1?

Если ваша цель Task не состоит в том, чтобы обновить UI, тогда нет необходимости использовать ContinueWith.Вместо этого просто передайте SynchronizationContext, и он должен работать без явного вызова Dispatcher.BeginInvoke.

backgroundDBTask = Task.Factory.StartNew(() =>
        {
            DoSomething1();
        },
    CancellationToken.None,
    TaskCreationOptions.None,
    TaskScheduler.FromCurrentSynchronizationContext()); 
...