我正在开发一个关于使用C#语言进行PDF渲染的项目。我将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进行渲染,但是我得到了一个异常:
调用线程无法访问此对象,因为它不同 线程拥有它。
我知道如果我使用UI线程我的问题可以解决,但我想在后台加载pdf页面,用户不等待加载所有页面,这可以用新线程。
答案 0 :(得分:2)
您可以使用线程,但必须使用Dispatcher
来访问UI元素。只有将项目传递给UserControl
的部分必须由调度员完成。
Application.Current.Dispatcher.BeginInvoke(new Action(() => AddItem()));
BeginInvoke
是异步调用,不会阻止执行以下代码。
编辑:如果我理解了您的应用程序的整个想法,我仍然不能100%确定,但是做了一个小样本,演示了如何使用线程和UI元素。
我制作了Window
(这是您的UserControl
),其中包含Button
和ListBox
。单击Button
启动一个线程并处理一些项目。在我的例子中,它只是将一些文本添加到列表中,我添加了Thread.Sleep(1000)
来模拟许多东西的处理。准备好文本后,它将被添加到ObservableCollection
,这必须由UI线程(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)));
}
}
}