0

所以我正在开发我的第一个多线程 WPF 应用程序。请记住,我对如何实现多线程几乎一无所知 - 我已经在一些应用程序中完成了它并且总是使用现有代码。这是我在 WPF 中的第一次尝试,这显然与 Windows 窗体完全不同......

所以基本上我正在研究这个例子,奇怪的是没有提到你必须实例化一个新线程并启动它——我猜作者觉得即使对像我这样的新手来说也是不言而喻的。

在任何情况下,它都可以正常工作,直到我想更新我的 UI 控件的属性,此时我遇到了一个InvalidOperationException调用线程无法访问该控件,因为该控件属于不同的线程

所以基本上这不是一种线程安全的工作方式,但我不知道应该如何解决这个问题......

这是我的代码:

string fn = "";

private void btnBrowse_Click(object sender, RoutedEventArgs e)
{
    if (lblActivity.Visibility != System.Windows.Visibility.Hidden)
    {
        lblActivity.Visibility = System.Windows.Visibility.Hidden;
    }
    if (lstResult.Items.Count != 0)
    {
        lstResult.Items.Clear();
    }

    OpenFileDialog ofd = new OpenFileDialog();

    Nullable<bool> result = ofd.ShowDialog();

    if (result == true)
    {
        txtSource.Text = ofd.FileName;
        txtDest.Text = ofd.FileName;
        fn = ofd.SafeFileName;

        PopulateControlsDuingLongRefreshCall("read");
    }
}

private void PopulateControlsDuingLongRefreshCall(string action)
{
    ShowProcessing();

    ThreadStart ts = delegate
    {
        switch (action)
        {
            case "format":
                Populate();
                CleanData();
                break;
            case "read":
                TextReader tr = new StreamReader(txtSource.Text);
                txtPreview.Text = tr.ReadToEnd();
                break;
        }

        Dispatcher.BeginInvoke(DispatcherPriority.Normal, (EventHandler)delegate
        {
            HideProcessing();
        }, null, null);

    };
    Thread thr = new Thread(ts);
    thr.Start();
}

private void ShowProcessing()
{
    recProcessing.Visibility = Visibility.Visible;
}
private void HideProcessing()
{
    recProcessing.Visibility = Visibility.Collapsed;
}

如果有人可以在这里提出一个解决方案或解释更多关于我正在使用的概念(我仍然很模糊),以便我能够理解到足以自己找到解决方案,那将不胜感激。

提前致谢!

编辑
如果我获取 UI 控件属性TextReader tr = new StreamReader(txtSource.Text);也会引发错误,也会引发异常。

4

2 回答 2

1

在您的委托中,不要直接访问 txtSource,而是尝试使用以下函数返回一个流读取器:

    private StreamReader GetTxtSource()
    {
        if (!this.Dispatcher.CheckAccess())
        {
            return this.Dispatcher.Invoke(new Func<StreamReader>(this.GetTxtSource)) as StreamReader;                
        }
        return new StreamReader(txtSource.Text);
    }

您可能需要改用 txtSource.Dispatcher.CheckAccess()。

于 2013-02-08T13:06:33.453 回答
0

您在这里真正需要了解的是,您不能从 UI 线程以外的其他线程访问任何控件。

所以当你在做

 case "read":
            TextReader tr = new StreamReader(txtSource.Text);
            txtPreview.Text = tr.ReadToEnd();
            break;

您正在尝试在后台线程中设置文本框 (txtPreview) 的值。

您需要做的是在后台线程中读取文件内容,然后使用 UI 线程通过使用 Dispatcher 更新文本框值:

 case "read":
            TextReader tr = new StreamReader(txtSource.Text);
            string content = tr.ReadToEnd();

            Dispatcher.Invoke((Action)(() =>
            {
                txtPreview.Text = content;
            }));
            txtPreview.Text = tr.ReadToEnd();
            break;
于 2013-02-08T16:25:12.920 回答