我在这个主题上找到article,但我无法理解如何实现所提出的答案。
我得到的是一个跨线程异常,我意识到GUI在一个线程中,而worker在另一个线程中。例外:
System.InvalidOperationException was unhandled by user code
HResult=-2146233079
Message=Cross-thread operation not valid: Control 'listBoxCodes' accessed from a thread other than the thread it was created on.
Source=System.Windows.Forms
StackTrace:
at System.Windows.Forms.Control.get_Handle()
at System.Windows.Forms.Control.SendMessage(Int32 msg, Int32 wparam, String lparam)
at System.Windows.Forms.ListBox.NativeInsert(Int32 index, Object item)
at System.Windows.Forms.ListBox.ObjectCollection.AddInternal(Object item)
at System.Windows.Forms.ListBox.ObjectCollection.Add(Object item)
at Find_Duplicate_MX_codes.MyThread.backgroundWorker_DoWork(Object sender, DoWorkEventArgs e) in D:\My Programs\Find Duplicate MX codes\Find Duplicate MX codes\MyThread.cs:line 69
at System.ComponentModel.BackgroundWorker.OnDoWork(DoWorkEventArgs e)
at System.ComponentModel.BackgroundWorker.WorkerThreadStart(Object argument)
InnerException:
现在,我试图通过编写如下代码来处理这个问题:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace Find_Duplicate_MX_codes
{
public struct ThreadSettings
{
public Find_Duplicate_MX_codes.Form1 pMainForm { get; set; }
public ProgressBar progressBar { get; set; }
public TextBox progressLabel { get; set; }
public String strFile { get; set; }
public ListBox lbCodes { get; set; }
public ListBox lbCodesDuplicate { get; set; }
}
class MyThread
{
private BackgroundWorker m_backgroundWorker;
ThreadSettings m_sThreadSettings;
public MyThread(ThreadSettings sThreadSettings)
{
m_sThreadSettings = sThreadSettings;
m_backgroundWorker = new BackgroundWorker();
m_backgroundWorker.DoWork += new DoWorkEventHandler(backgroundWorker_DoWork);
m_backgroundWorker.ProgressChanged += new ProgressChangedEventHandler(backgroundWorker_ProgressChanged);
m_backgroundWorker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(backgroundWorker_RunWorkerCompleted);
m_backgroundWorker.WorkerReportsProgress = true;
}
public void start()
{
if(m_sThreadSettings.pMainForm != null)
m_sThreadSettings.pMainForm.Enabled = false; // Stop user interacting with the form
m_backgroundWorker.RunWorkerAsync();
}
public void stop()
{
m_backgroundWorker.CancelAsync();
}
public void backgroundWorker_DoWork(object sender, DoWorkEventArgs e)
{
m_backgroundWorker.ReportProgress(0, "Extracting MX codes {0}%)");
using (var reader = new StreamReader(m_sThreadSettings.strFile))
{
Stream baseStream = reader.BaseStream;
long length = baseStream.Length;
string line;
while ((line = reader.ReadLine()) != null)
{
if (line.Length > 8 && line.Substring(0, 4) == "080,")
{
string strCode = line.Substring(4, 4);
if (m_sThreadSettings.lbCodes.FindStringExact(strCode) == -1)
{
m_sThreadSettings.lbCodes.Items.Add(strCode);
}
else
m_sThreadSettings.lbCodesDuplicate.Items.Add(strCode);
}
m_backgroundWorker.ReportProgress(Convert.ToInt32(baseStream.Position / length * 100), "Extracting MX codes {0}%)");
}
}
}
private void backgroundWorker_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
if(m_sThreadSettings.progressBar != null)
m_sThreadSettings.progressBar.Value = e.ProgressPercentage;
if(m_sThreadSettings.progressLabel != null)
m_sThreadSettings.progressLabel.Text = String.Format((string)e.UserState, e.ProgressPercentage);
}
private void backgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
int iResult = Convert.ToInt32(e.Result);
if (m_sThreadSettings.pMainForm != null)
m_sThreadSettings.pMainForm.Enabled = true; // User can interact with form again
}
}
}
如果我注释掉尝试将项添加到列表框的代码行是有效的。进度条/标签正在更新。当我尝试更新它失败的列表框时。
在另一篇文章的答案中建议:
UserContrl1_LOadDataMethod()
{
if(textbox1.text=="MyName") //<<======Now it wont give exception**
{
//Load data correspondin to "MyName"
//Populate a globale variable List<string> which will be
//bound to grid at some later stage
if(InvokeRequired)
{
// after we've done all the processing,
this.Invoke(new MethodInvoker(delegate {
// load the control with the appropriate data
}));
return;
}
}
}
但是我很难理解如何在我的代码行中使用这个答案:
m_sThreadSettings.lbCodes.Items.Add(strCode);
如何更改它以便我可以填充列表框:
a)没有得到跨线程异常 b)由于更新了列表框而没有阻塞GUI
谢谢!
更新:我试过这段代码:
Invoke(new MethodInvoker(delegate { m_sThreadSettings.lbCodes.Items.Add(strCode); }));
但我得到的警告是我不完全理解:
更新2:我现在意识到Invoke是Form对象的一部分。所以我将代码更改为:
if (m_sThreadSettings.lbCodes.FindStringExact(strCode) == -1)
m_sThreadSettings.pMainForm.Invoke(new MethodInvoker(delegate { m_sThreadSettings.lbCodes.Items.Add(strCode); }));
else
m_sThreadSettings.pMainForm.Invoke(new MethodInvoker(delegate { m_sThreadSettings.lbCodesDuplicate.Items.Add(strCode); }));
现在似乎有效。但看这个动画:
https://www.dropbox.com/s/mznoqhqll8m28x7/Results0001.mp4?dl=0
它并不像我期望的那样完全处理。一旦读取完成,它似乎仍在进行GUI的所有处理。困惑。
更新3:我使用Console.Beep()来确定何时触发了进度更改处理程序。此外,我确认进展实际发生了变化。并且它除了在结束时为100以外都为0。所以这个BaseSteam.Position可能是错误。
答案 0 :(得分:0)
结果证明与我的代码存在无关的问题。
问题1
这是如何从工作线程更新列表框:
public void backgroundWorker_DoWork(object sender, DoWorkEventArgs e)
{
m_backgroundWorker.ReportProgress(0, "Extracting MX codes {0}%");
using (var reader = new StreamReader(m_sThreadSettings.strFile))
{
Stream baseStream = reader.BaseStream;
long length = baseStream.Length;
string line;
while ((line = reader.ReadLine()) != null)
{
if (line.Length > 8 && line.Substring(0, 4) == "080,")
{
string strCode = line.Substring(4, 4);
if (m_sThreadSettings.lbCodes.FindStringExact(strCode) == -1)
m_sThreadSettings.pMainForm.Invoke(new MethodInvoker(delegate { m_sThreadSettings.lbCodes.Items.Add(strCode); }));
else
m_sThreadSettings.pMainForm.Invoke(new MethodInvoker(delegate { m_sThreadSettings.lbCodesDuplicate.Items.Add(strCode); }));
}
m_backgroundWorker.ReportProgress(Convert.ToInt32((100 / (double)length) * baseStream.Position), "Extracting MX codes {0}%");
}
}
}
您必须使用表单的调用方法。
第2期
计算进度的逻辑需要调整,因为在此上下文中,由于计算的工作方式,结果始终为0。所以我现在用:
m_backgroundWorker.ReportProgress(
Convert.ToInt32((100 / (double)length) * baseStream.Position),
"Extracting MX codes {0}%");
瞧!我的表单列表b ox内容正在进行更新,进度条正在预期更新......:)