我有一个项目,我需要从另一个类方法中更新标签文本。值得注意的是,此方法是从后台工作线程调用的。
我已尝试将文本传递给Workers ReportProgress()中的UserState Obj更新;方法,然后在主窗体上触发工作器进度更改事件时更新标签。这有效,但显然只会在引发进度更改事件时更新标签文本。
我的代码是不断加载/删除代理,我需要一个标签来显示它(因为只有当bg worker进展时才更新事件触发)。希望有人可以提供帮助。
由于
编辑*这里有一些代码可以让问题更容易理解: -
public string Request(string action)
{
if (string.IsNullOrWhiteSpace(action))
{
return "";
}
HttpWebRequest req;
string response = string.Empty;
while (response.Equals(string.Empty) && proxy != null)
{
try
{
req = (HttpWebRequest)WebRequest.Create(action);
req.Proxy = proxy;
response = new StreamReader(req.GetResponse().GetResponseStream()).ReadToEnd();
}
catch (Exception ex)
{
RemoveProxy(proxy);
MessageBox.Show("Proxy Removed: " + proxy.Address.ToString());
proxy = GenNewProx();
MessageBox.Show("New proxy" + proxy.Address.ToString());
}
}
return response;
}
^^^ - 我需要设置标签文本,目前使用Msgboxs,但更新主表单上的标签显然更可取
foreach (string url in URLs)
{
result.URL = url;
result.Shares = grabber.GetFacebookShares(url);
result.Tweets = grabber.GetTweetCount(url);
result.PlusOnes = grabber.GetPlusOnes(url);
bgWorker.ReportProgress((outputGridView.Rows.Count * 100) / importGridView.Rows.Count, result);
}
^^^ - 在主窗体上的bg worker do_work方法内。
第二次编辑*
我对事件有点新意,但是每次我切换代理并用新的代理/ msg传入一个字符串参数然后在主窗体中订阅此事件时,我就不会触发自定义事件,例如Proxy_Changed,然后在此事件触发时在主窗体上设置标签text =字符串args?我可能会说乱七八糟但是:/
答案 0 :(得分:3)
以下是我认为课程中需要完成背景工作的重要部分:
public class Grabber
{
public event EventHandler<MyArgs> NotifyParentUI;
// other code.....
public string Request(string action)
{
if (string.IsNullOrWhiteSpace(action))
{
return "";
}
HttpWebRequest req;
string response = string.Empty;
while (response.Equals(string.Empty) && proxy != null)
{
try
{
req = (HttpWebRequest)WebRequest.Create(action);
req.Proxy = proxy;
response = new StreamReader(req.GetResponse().GetResponseStream()).ReadToEnd();
}
catch (Exception ex)
{
RemoveProxy(proxy);
NotifyParentUI(this, new MyArgs()
{ Message = string.Format("Proxy Removed: {0}", proxy.Address.ToString()) });
proxy = GenNewProx();
NotifyParentUI(this, new MyArgs()
{ Message = string.Format("New Proxy: {0}", proxy.Address.ToString()) });
}
}
return response;
}
}
在您的主表单中,您有一种更新标签的方法,该方法是线程安全的:
public void UpdateMyLabel(object sender, MyArgs ea)
{
this.Invoke(new MethodInvoker(
delegate()
{
labelControl1.Text = ea.Message;
}
));
}
同样在主窗体中,您必须创建“抓取器”的实例:
Grabber grabber = new Grabber();
grabber.NotifyParentUI += UpdateMyLabel;
你应该有一个在自己的线程上运行的方法:
public void ThreadProc()
{
// other code before this....
foreach (string url in URLs)
{
result.URL = url;
result.Shares = grabber.GetFacebookShares(url);
Thread.Sleep(0); // may want to take the Sleeps out
result.Tweets = grabber.GetTweetCount(url);
Thread.Sleep(0);
result.PlusOnes = grabber.GetPlusOnes(url);
Thread.Sleep(0);
}
}
以下是您在主表单部分中启动主题的方法:
Thread t = new Thread(new ThreadStart(ThreadProc));
t.Start();
作为旁注,如果您需要将数据传递给您的线程,请查看此处: Passing Data to Threads and Retrieving Data from Threads
答案 1 :(得分:2)
使用Invoke方法在UI线程上运行匿名函数以更新标签。例如:
BackgroundWorker bw = new BackgroundWorker();
bw.DoWork += (sender, args) =>
{
for (int i = 0; i < 10000; ++i)
{
DoSomeWorkInBackground();
// Update the label in UI thread
MyOtherFormInstance.Invoke((MethodInvoker)delegate()
{
MyOtherFormInstance.SetLabelText(i);
});
DoSomOtherWorkInBackground();
}
};
在您的表格中:
public void SetLabelText(int i)
{
myLabel.Text = i.ToString();
// not sure that this needed, but try:
myLabel.Invalidate();
}
答案 2 :(得分:1)
从您的问题和随后的评论中听到您在WinForms项目中运行代码的其他答案,如果我错了,请纠正我?在winform中,主程序线程通常总是静态的(static void Main())因此你必须使你的EventHandler 静态也避免空异常。我相信这会解决您的问题,因为它听起来像您的其他代码是正确的吗?