事件处理程序不再触发
今天下午我一直在工作,试图使用后台工作者从位于我的程序集中的一个相当大的 xml 文件中读取数据。在我决定重命名后台工作者的对象名之前,它一直运行得很好。在我构建解决方案后,它告诉我它成功了。运行我的程序并对其进行测试后,我注意到后台工作者的 DoWork 事件根本拒绝触发。当我将下面的代码添加到Backgroundworker的RunWorkerCompleted事件中时,我得到的只是一个包含大内容的消息框。 MessageBox.Show(e.Result + " " + e.Error);
将其重命名回原来的名称也没有帮助。我自己编写了所有代码,因此这里不涉及第三方应用程序。
这是我用来与后台工作人员设置工作的代码,
private volatile List<string> listItems = new List<string>();
private BackgroundWorker _populateListItems = new BackgroundWorker();
private string currentConnection;
#endregion
public frmSettings()
{
InitializeComponent();
//I will be able to track how far the list is populated with the following command.
_populateListItems.WorkerReportsProgress = true;
//This will fire if there is an error in the xml file.
_populateListItems.WorkerSupportsCancellation = true;
//Assign the job to be done for the backgroundworker
_populateListItems.DoWork +=new DoWorkEventHandler(_populateListItems_DoWork);
_populateListItems.ProgressChanged += new ProgressChangedEventHandler(_populateListItems_ProgressChanged);
//When the worker is finished, the following event will fire: All UI controls will be updated.
_populateListItems.RunWorkerCompleted += new RunWorkerCompletedEventHandler(_populateListItems_RunWorkerCompleted);
_populateListItems.RunWorkerAsync();
}
void _populateListItems_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
prgProgress.Value = e.ProgressPercentage;
lblProgress.Text = e.ProgressPercentage.ToString() + "%";
}
private void _populateListItems_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
//The operation is completed/Cancelled/Erroneous. The list will now be populated with the available information.
MessageBox.Show(e.Result + " " + e.Error);
foreach (string item in listItems)
{
liConnections.Items.Add(item);
}
//This shows the user which connection is currently used.
lblCurrentSelection.Text = currentConnection;
}
private void _populateListItems_DoWork(object sender, DoWorkEventArgs e)
{
try
{
//The following lines of code are the variables that are going to be used.
// xReadSettings will make the XmlReader xRead Ignore whitespaces and comments, if any.
// assemblyExecuted will get information from which assembly gets Executed.
// filename Will get the filename of the settings.xml file that is going to be used.
// SettingsStream will open the stream for reading and writing, using the GetManifestResourceStream() method from the currently executed assembly.
XmlReaderSettings xReadSettings = new XmlReaderSettings();
Assembly assemblyExecuted = Assembly.GetExecutingAssembly();
string filename = String.Format("{0}.Settings.xml", assemblyExecuted.GetName().Name);
Stream settingsStream = assemblyExecuted.GetManifestResourceStream(filename);
xReadSettings.IgnoreComments = true;
xReadSettings.IgnoreWhitespace = true;
//Finally the xmlReader object is created using the settingstream, and its settings.
//While the stream reads, it checks whether the nodes accessed are elements of the xml file.
//if it is an element that is accessed, then we check whether the element which is accessed is a connection string to the database
//if it is a connectionstring to the database, we will check if the connection has a name.
//if it has a name, we get the name attribute, and add it to our list. The list is volatile, so it will be up to date, because this
//background thread is updating it.
//To Update the progress of the backgroundworker, we need to know the amount of elements in the XML File. Xpath will be used for this.
XmlDocument xdoc = new XmlDocument();
xdoc.Load(settingsStream);
XmlNodeList nodes = xdoc.SelectNodes("*"); //Xpath - select all.
int totalElementsToRead = nodes.Count;
int totalElementsRead = 0;
using (XmlReader xRead = XmlReader.Create(settingsStream, xReadSettings))
{
while (xRead.Read())
{
if (xRead.NodeType == XmlNodeType.Element)
{
if (xRead.Name == "ConnectionString")
{
if (xRead.HasAttributes)
{
string attribute = xRead.GetAttribute("name").ToString();
listItems.Add(attribute);
}
}
if (xRead.Name == "CurrentConnection")
{
xRead.Read(); //gets the value of <CurrentConnection>
currentConnection = xRead.Value.Trim();
}
totalElementsRead++;
_populateListItems.ReportProgress(totalElementsRead / totalElementsToRead * 100);
}
}
}
}
catch
{
_populateListItems.CancelAsync();
}
}
请原谅其背后评论中的理论。我正在尽我所能地解释它。
但我的问题是,有人能看出哪里出了问题吗?为什么事件突然不触发?它应该用我的 xml 文件中的项目填充列表(未触及,在重命名之前正在工作)。运行逐步调试也证明它跳过了我的 doWork 事件处理程序。
I have been at work this afternoon trying to use a backgroundworker to read from an pretty large xml File Located in my assembly. It has worked pretty well up till the point I decided to rename the backgroundworker's objectname. After I built my solution, it told me it was a success. After running my program and testing it, I noticed that the backgroundworker's DoWork Event refuses to fire at all. When I added the code below to the Backgroundworker's RunWorkerCompleted event, all i got was a messagebox containing a big fat nothing. MessageBox.Show(e.Result + " " + e.Error);
Renaming it back to what it was also didn't help. I wrote all the code myself, so there are no third party applications involved here.
Here is the code I used to set up the workings with the backgroundworker
private volatile List<string> listItems = new List<string>();
private BackgroundWorker _populateListItems = new BackgroundWorker();
private string currentConnection;
#endregion
public frmSettings()
{
InitializeComponent();
//I will be able to track how far the list is populated with the following command.
_populateListItems.WorkerReportsProgress = true;
//This will fire if there is an error in the xml file.
_populateListItems.WorkerSupportsCancellation = true;
//Assign the job to be done for the backgroundworker
_populateListItems.DoWork +=new DoWorkEventHandler(_populateListItems_DoWork);
_populateListItems.ProgressChanged += new ProgressChangedEventHandler(_populateListItems_ProgressChanged);
//When the worker is finished, the following event will fire: All UI controls will be updated.
_populateListItems.RunWorkerCompleted += new RunWorkerCompletedEventHandler(_populateListItems_RunWorkerCompleted);
_populateListItems.RunWorkerAsync();
}
void _populateListItems_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
prgProgress.Value = e.ProgressPercentage;
lblProgress.Text = e.ProgressPercentage.ToString() + "%";
}
private void _populateListItems_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
//The operation is completed/Cancelled/Erroneous. The list will now be populated with the available information.
MessageBox.Show(e.Result + " " + e.Error);
foreach (string item in listItems)
{
liConnections.Items.Add(item);
}
//This shows the user which connection is currently used.
lblCurrentSelection.Text = currentConnection;
}
private void _populateListItems_DoWork(object sender, DoWorkEventArgs e)
{
try
{
//The following lines of code are the variables that are going to be used.
// xReadSettings will make the XmlReader xRead Ignore whitespaces and comments, if any.
// assemblyExecuted will get information from which assembly gets Executed.
// filename Will get the filename of the settings.xml file that is going to be used.
// SettingsStream will open the stream for reading and writing, using the GetManifestResourceStream() method from the currently executed assembly.
XmlReaderSettings xReadSettings = new XmlReaderSettings();
Assembly assemblyExecuted = Assembly.GetExecutingAssembly();
string filename = String.Format("{0}.Settings.xml", assemblyExecuted.GetName().Name);
Stream settingsStream = assemblyExecuted.GetManifestResourceStream(filename);
xReadSettings.IgnoreComments = true;
xReadSettings.IgnoreWhitespace = true;
//Finally the xmlReader object is created using the settingstream, and its settings.
//While the stream reads, it checks whether the nodes accessed are elements of the xml file.
//if it is an element that is accessed, then we check whether the element which is accessed is a connection string to the database
//if it is a connectionstring to the database, we will check if the connection has a name.
//if it has a name, we get the name attribute, and add it to our list. The list is volatile, so it will be up to date, because this
//background thread is updating it.
//To Update the progress of the backgroundworker, we need to know the amount of elements in the XML File. Xpath will be used for this.
XmlDocument xdoc = new XmlDocument();
xdoc.Load(settingsStream);
XmlNodeList nodes = xdoc.SelectNodes("*"); //Xpath - select all.
int totalElementsToRead = nodes.Count;
int totalElementsRead = 0;
using (XmlReader xRead = XmlReader.Create(settingsStream, xReadSettings))
{
while (xRead.Read())
{
if (xRead.NodeType == XmlNodeType.Element)
{
if (xRead.Name == "ConnectionString")
{
if (xRead.HasAttributes)
{
string attribute = xRead.GetAttribute("name").ToString();
listItems.Add(attribute);
}
}
if (xRead.Name == "CurrentConnection")
{
xRead.Read(); //gets the value of <CurrentConnection>
currentConnection = xRead.Value.Trim();
}
totalElementsRead++;
_populateListItems.ReportProgress(totalElementsRead / totalElementsToRead * 100);
}
}
}
}
catch
{
_populateListItems.CancelAsync();
}
}
Pardon the theory in the comments behind it. I'm explaining it the best way that i can.
My question is though, can anyone see perhaps where this has gone wrong? Why the event suddenly does not fire? It is supposed to fill a list up with items from my xml file (untouched, was working before rename). Running a step-through debug also proved it was skipping my doWork event handler.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
我认为问题是您正在从构造函数调用RunWorkerAsync
并且ProgressChanged
由于表单尚不可见而失败。尝试将对RunWorkerAsync
的调用移至表单的Show
事件处理程序。好的,所以问题是
DoWork
事件内的异常被try..catch
块吃掉的处理程序。总结一下代码中的问题:
try..catch
块吞噬所有异常并使调试变得困难。DoWork
事件处理程序内部调用CancelAsync
。I think the problem is that you are callingRunWorkerAsync
from the constructor and theProgressChanged
fails due to the form not being visible yet. Try moving the call toRunWorkerAsync
to the form'sShow
event handler.OK, so the problem was an exception inside the
DoWork
event handler that was being eaten up by thetry..catch
block.To sum up the issues with your code:
try..catch
block that eats up all exceptions and makes debugging difficult.RunWorkerAsync
from inside the form constructor.CancelAsync
from inside theDoWork
event handler.