Reputation: 303
I'm working on a project about PDF rendering in the C# language. I convert each page of PDF file to Image and Adds it to a ObservableCollection
with a new thread by the below code:
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;
}
}
then pass the custom item of myObservableCollection to another UserControl for render it but I got an exception:
The calling thread cannot access this object because a different thread owns it.
I know if I use UI thread my problem could be solved but I want load pdf pages in the background and user doesn't wait for loading all pages and this is possible with a new thread.
Upvotes: 1
Views: 2497
Reputation: 4532
You can use threads but have to use the Dispatcher
to access UI elements. Only the part, where you pass the item to the UserControl
has to be done by the dispatcher.
Application.Current.Dispatcher.BeginInvoke(new Action(() => AddItem()));
BeginInvoke
is a asynchronous call and won't block the execution of the following code.
Edit: I'm still not 100% sure if I unterstood the whole idea of your application but made a small sample which demonstrates how you can use threads and UI elements.
I made a Window
(that would be your UserControl
) which contains a Button
and a ListBox
. When clicking the Button
a thread is started and processes some items. In my case it just adds some texts into a list, I added Thread.Sleep(1000)
to simulate the processing of lots of stuff. When the text is prepared, it will be added to the ObservableCollection
, which has to be done by the UI thread (Dispatcher
). There is nothing blocking the UI but this adding and this is done very fast. You can also start multiple threads at the same time.
This is the code-behind of the Window
(the Window
itsself just contains a Button
and a 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)));
}
}
}
Upvotes: 2