后台工作者和不同的线程

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();
    }

}