后台工作者和不同的线程
backgroundworker and different thread
我有一个 WinForm
应用程序并想转换为 WPF
,在 200 个错误被清除后,我正在努力工作但总是有一个错误我无法做到解决。
在我的 BackgroundWorker1_DoWork
中,我正在尝试使用以下方法检索目录中的文件数量:
//Set the progress bar
Dispatcher.BeginInvoke(System.Windows.Threading.DispatcherPriority.Render,
new Action(() => {
Directory.GetFiles((textBox_UpdatedBuildPath.Text, "*",
SearchOption.AllDirectories).Length;
})
); //<-----------------HERE
并出现以下错误:
The calling thread cannot access this object because a different
thread owns it.
快速搜索后,似乎与用户要更新UI有关,但似乎不是我的情况,我需要Textbox
的信息并递归查找多少个文件文件夹可以包含。
感谢您以后的回答。
编辑:这里是带有完整注释的代码 -> http://codepaste.net/r1qejd
几乎每个 WPF 元素都具有线程关联。这意味着只能从创建该元素的线程访问此类元素。为了做到这一点,每个需要线程关联的元素最终都是从 DispatcherObject
class 派生的。此 class 提供了一个 属性 名为 Dispatcher
的 returns 与 WPF 元素关联的 Dispatcher
对象。
Dispatcher
class 用于在他的附加线程上执行工作。它有一个工作项队列,负责在调度程序线程上执行工作项。
You can find on the following link some more details on the subject.
正如 MSDN 所说:
Only one thread can modify the UI thread. But how do background
threads interact with the user? A background thread can ask the UI
thread to perform an operation on its behalf. It does this by
registering a work item with the Dispatcher of the UI thread. The
Dispatcher class provides two methods for registering work items:
Invoke and BeginInvoke. Both methods schedule a delegate for
execution. Invoke is a synchronous call – that is, it doesn’t return
until the UI thread actually finishes executing the delegate.
BeginInvoke is asynchronous and returns immediately.
所以尽量使用Dispatcher
。例如:
int CountFileToCheck;
textBox_UpdatedBuildPath.Dispatcher.Invoke(() => {
CountFileToCheck=Directory.GetFiles(textBox_UpdatedBuildPath.Text, "*", SearchOption.AllDirectories).Length;
});
更新:
我已经为你制作了一个示例并进行了测试。它完美运行。
XAML:
<StackPanel>
<Button Name="btn" Click="btn_Click" Content="Foo Button"/>
<TextBox Name="textBox" Text="123"/>
</StackPanel>
代码隐藏:
public partial class MainWindow : Window
{
BackgroundWorker bw;
public MainWindow()
{
InitializeComponent();
bw = new BackgroundWorker();
}
private void btn_Click(object sender, RoutedEventArgs e)
{
bw.DoWork += (o, a) =>
{
try
{
string str = "";
textBox.Dispatcher.Invoke(DispatcherPriority.Normal, new Action(() =>
{
str = textBox.Text;
MessageBox.Show(str);
}));
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
//e.Result = LoadXmlDoc();
};
bw.RunWorkerAsync();
}
}
我有一个 WinForm
应用程序并想转换为 WPF
,在 200 个错误被清除后,我正在努力工作但总是有一个错误我无法做到解决。
在我的 BackgroundWorker1_DoWork
中,我正在尝试使用以下方法检索目录中的文件数量:
//Set the progress bar
Dispatcher.BeginInvoke(System.Windows.Threading.DispatcherPriority.Render,
new Action(() => {
Directory.GetFiles((textBox_UpdatedBuildPath.Text, "*",
SearchOption.AllDirectories).Length;
})
); //<-----------------HERE
并出现以下错误:
The calling thread cannot access this object because a different thread owns it.
快速搜索后,似乎与用户要更新UI有关,但似乎不是我的情况,我需要Textbox
的信息并递归查找多少个文件文件夹可以包含。
感谢您以后的回答。
编辑:这里是带有完整注释的代码 -> http://codepaste.net/r1qejd
几乎每个 WPF 元素都具有线程关联。这意味着只能从创建该元素的线程访问此类元素。为了做到这一点,每个需要线程关联的元素最终都是从 DispatcherObject
class 派生的。此 class 提供了一个 属性 名为 Dispatcher
的 returns 与 WPF 元素关联的 Dispatcher
对象。
Dispatcher
class 用于在他的附加线程上执行工作。它有一个工作项队列,负责在调度程序线程上执行工作项。
You can find on the following link some more details on the subject.
正如 MSDN 所说:
Only one thread can modify the UI thread. But how do background threads interact with the user? A background thread can ask the UI thread to perform an operation on its behalf. It does this by registering a work item with the Dispatcher of the UI thread. The Dispatcher class provides two methods for registering work items: Invoke and BeginInvoke. Both methods schedule a delegate for execution. Invoke is a synchronous call – that is, it doesn’t return until the UI thread actually finishes executing the delegate. BeginInvoke is asynchronous and returns immediately.
所以尽量使用Dispatcher
。例如:
int CountFileToCheck;
textBox_UpdatedBuildPath.Dispatcher.Invoke(() => {
CountFileToCheck=Directory.GetFiles(textBox_UpdatedBuildPath.Text, "*", SearchOption.AllDirectories).Length;
});
更新:
我已经为你制作了一个示例并进行了测试。它完美运行。
XAML:
<StackPanel>
<Button Name="btn" Click="btn_Click" Content="Foo Button"/>
<TextBox Name="textBox" Text="123"/>
</StackPanel>
代码隐藏:
public partial class MainWindow : Window
{
BackgroundWorker bw;
public MainWindow()
{
InitializeComponent();
bw = new BackgroundWorker();
}
private void btn_Click(object sender, RoutedEventArgs e)
{
bw.DoWork += (o, a) =>
{
try
{
string str = "";
textBox.Dispatcher.Invoke(DispatcherPriority.Normal, new Action(() =>
{
str = textBox.Text;
MessageBox.Show(str);
}));
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
//e.Result = LoadXmlDoc();
};
bw.RunWorkerAsync();
}
}