2010-08-06 2 views
2

Я пытаюсь создать параллельное выполнение функции в wpf C#, которая также запускает действия в пользовательском интерфейсе. Но при запуске всегда существует исключение в методах в элементах управления UI: вызывающий поток не может получить доступ к этому объекту, потому что ему принадлежит другой поток. Исключение всегда вызывается во втором экземпляре цикла, который запущен, поэтому невозможно управлять UI в двух параллельных исполняемых экземплярах?Параллельное программирование: не удается получить доступ к параллельному интерфейсу?

Можно ли подключить интерфейс параллельно?

Код:

   do 
       { 
        if (listBox_Copy.SelectedIndex < listBox_Copy.Items.Count - 1) 
        { 
         listBox_Copy.SelectedIndex = listBox_Copy.SelectedIndex + 1; 
         listBox_Copy.ScrollIntoView(listBox_Copy.SelectedItem); 
        } listBox_Copy.Focus(); 
        huidigitem = listBox_Copy.SelectedItem as ListBoxItem; 
        currentitemindex = listBox_Copy.SelectedIndex; 
        currentitem = listBox_Copy.ItemContainerGenerator.ContainerFromIndex(currentitemindex) as ListBoxItem; 
        itemgrid = FindVisualChild<Grid>(currentitem); 
        senderbutton = (Button)sender; 
        Button playcues = itemgrid.FindName("Playbutton") as Button; 
        cuetrigger = itemgrid.FindName("cuetrigger") as TextBlock; 
        Jobs.Add(playcues); 
       } while (cuetrigger.Text != "go"); 
       Parallel.ForEach(Jobs, playcues => { play(playcues, new RoutedEventArgs()); }); 

      } 

И тогда он выходит из строя на функцию воспроизведения

  private void play(object sender, System.Windows.RoutedEventArgs e) 
      { Grid itemgrid = VisualTreeHelperExtensions.FindAncestor<Grid>(playcue); 

ответ

1

Это не представляется возможным доступ к пользовательскому интерфейсу из фонового потока, все ваши обновления должны быть в основном потоке , Вы можете сделать это с помощью диспетчера

Что-то вроде этого

 Action x = (Action)delegate { 
      //do my UI updating 
     }; 
     Dispatcher.Invoke(x, new object[] { }); 
0

Хитрость заключается в том, чтобы использовать IProgress<T> сообщать обновления в основной поток. Конструктор IProgress<T> принимает анонимную функцию, которая будет запускаться в основном потоке и, таким образом, может обновлять пользовательский интерфейс.

Цитируя https://blog.stephencleary.com/2012/02/reporting-progress-from-async-tasks.html:

public async void StartProcessingButton_Click(object sender, EventArgs e) 
{ 
    // The Progress<T> constructor captures our UI context, 
    // so the lambda will be run on the UI thread. 
    var progress = new Progress<int>(percent => 
    { 
    textBox1.Text = percent + "%"; 
    }); 

    // DoProcessing is run on the thread pool. 
    await Task.Run(() => DoProcessing(progress)); 
    textBox1.Text = "Done!"; 
} 

public void DoProcessing(IProgress<int> progress) 
{ 
    for (int i = 0; i != 100; ++i) 
    { 
    Thread.Sleep(100); // CPU-bound work 
    if (progress != null) 
     progress.Report(i); 
    } 
} 

Теперь немного саморекламы :) Я создал IEnumerable<T> расширение для запуска параллельно для обратных вызовов с событиями, которые могут непосредственно изменять пользовательский интерфейс. Вы можете посмотреть на него здесь:

https://github.com/jotaelesalinas/csharp-forallp

Надеется, что это помогает!

Смежные вопросы