Как обновить ObservableCollection новым потоком и получить доступ к его элементам из другого UserControl? - PullRequest
1 голос
/ 28 марта 2012

Я работаю над проектом о рендеринге PDF на языке C #.Я конвертирую каждую страницу PDF-файла в изображение и добавляю его в ObservableCollection с новым потоком по следующему коду:

  ThreadStart myThreadDelegate = new ThreadStart(DoWork);
  myThread = new Thread(myThreadDelegate);
  myThread.SetApartmentState(ApartmentState.STA);

  void DoWork()
    {
        for (int i = 0; i < pdfFile.Pages.Count; i++)
        {
            PdfPage page=pdfFile.LoadPage(i);
            myObservableCollection[i]=page;
        }
    }

, а затем передаю пользовательский элемент myObservableCollection в другой UserControl для его рендеринга, но яполучено исключение:

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

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

1 Ответ

2 голосов
/ 28 марта 2012

Вы можете использовать потоки, но должны использовать Dispatcher для доступа к элементам пользовательского интерфейса.Диспетчер должен выполнить только ту часть, где вы передаете элемент в UserControl.

Application.Current.Dispatcher.BeginInvoke(new Action(() => AddItem()));

BeginInvoke - это асинхронный вызов, который не будет блокировать выполнение следующего кода.

Редактировать: Я все еще не уверен на 100%, если я полностью понял идею вашего приложения, но сделал небольшой пример, который демонстрирует, как вы можете использовать потоки и элементы пользовательского интерфейса.

Я сделал Window (это будет ваш UserControl), который содержит Button и ListBox.При нажатии Button запускается поток, который обрабатывает некоторые элементы.В моем случае это просто добавляет некоторые тексты в список, я добавил Thread.Sleep(1000), чтобы имитировать обработку большого количества материала.Когда текст подготовлен, он будет добавлен в ObservableCollection, что должно быть сделано потоком пользовательского интерфейса (Dispatcher).Ничто не блокирует пользовательский интерфейс, кроме этого добавления, и это делается очень быстро.Вы также можете запускать несколько потоков одновременно.

Это код для Window (сам Window содержит только Button и ListBox):

public partial class MainWindow : Window
{
    private ObservableCollection<string> textList;

    public MainWindow()
    {
        textList = new ObservableCollection<string>();
        InitializeComponent();
        btnStartWork.Click += BtnStartWorkClick;
        lstTextList.ItemsSource = textList;
    }

    private void BtnStartWorkClick(object sender, RoutedEventArgs e)
    {
        Thread myThread;
        ThreadStart myThreadDelegate = DoWork;
        myThread = new Thread(myThreadDelegate);
        myThread.SetApartmentState(ApartmentState.STA);
        myThread.Start();
    }

    private void DoWork()
    {
        for (int i = 0; i < 5; i++)
        {
            string text = string.Format("Text {0}", i);
            // block the thread (but not the UI)
            Thread.Sleep(1000);
            // use the dispatcher to add the item to the list, which will block the UI, but just for a very short time
            Application.Current.Dispatcher.BeginInvoke(new Action(() => textList.Add(text)));
        }
    }
}
...