我有两个类; - 一个名为Form1.cs,另一个名为NoteThreader.cs,以下是这两个类的内容:
Form1.cs中:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Threading;
namespace HitMachine
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
public void updateText(string theText)
{
label1.Text = theText;
}
private void Form1_Load(object sender, EventArgs e)
{
XML.LoadMP3.loadFile(XML.XmlParser.ParseDocument("music"));
Threading.NoteThreader.createTimer();
}
}
}
NoteThreader.cs:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Windows.Forms;
namespace HitMachine.Threading
{
public class NoteThreader
{
public static Thread createTimer()
{
Thread t = new Thread(threadDeligation);
t.Start();
return t;
}
public static int time = 0;
static void threadDeligation()
{
for (; ; )
{
Form1 a = new Form1();
a.updateText(time);
time++;
}
}
}
}
代码运行时没有任何异常或错误;但它不会更新文本。我猜这是因为调用方法的线程与更新文本的线程不同?
我试图调用它但未能这样做。我在threadDeligation中运行了一个MessageBox,并且工作正常。
答案 0 :(得分:2)
在threadDeligation
方法中,每次执行循环时都会创建Form1
的新实例。这不会更改您正在查看的Form1
实例中的文字。
您需要将Form1
的正确实例传递给createTimer
方法(然后将其传递给threadDeligation
方法)。
你可以这样做:
private void Form1_Load(object sender, EventArgs e)
{
XML.LoadMP3.loadFile(XML.XmlParser.ParseDocument("music"));
Threading.NoteThreader.createTimer(this);
}
然后:
public static Thread createTimer(Form1 theForm)
{
Thread t = new Thread(() => threadDeligation(theForm));
t.Start();
return t;
}
public static int time = 0;
static void threadDeligation(Form1 theForm)
{
for (; ; )
{
theForm.updateText(time);
time++;
}
}
这应该为您提供如何在代码中传递对象的一般概念,
但它将 NOT 工作,因为不支持从非ui线程更新UI元素。您需要改为使用BackgroundWorker
类。
答案 1 :(得分:1)
for (; ; )
{
Form1 a = new Form1();
a.updateText(time);
time++;
}
Form1
对象。a.Show();
在哪里?如果要显示计时器的值,则应该继续引用相应的Form1
对象。
答案 2 :(得分:1)
所以这里有很多问题。首先是其他答案提到的显而易见的问题。您正在创建Form1
的新实例并调用其方法,从而修改其标签。您没有修改向用户显示的表单;它没有变化。
如果您要获取正在使用的表单实例,那么您将遇到从另一个线程修改表单的问题。这是不允许的。在winform编程中,您只能从创建它们的线程中访问Control
个对象;否则他们会犯错。
要解决此问题,您可以调用主UI线程来执行更新。但是,您现在处于可以发送命令以更新标签的位置,就像您的计算机可能发送它们一样快。那是......非常,非常非常快。如此之快,以至于屏幕根本无法更新;由于您发送的命令数量庞大,您将开始滞后,甚至冻结。
似乎你想创建某种临时时钟,你可以在X时间间隔内增加一个数字。让我们说一次(但你可以很容易地将它改为10毫秒,或其他)。要在X时间间隔内做一些事情,我们要使用Timer
。
void Form1_Load(object sender, EventArgs e)
{
var timer = new System.Windows.Forms.Timer();
timer.Interval = 1000;
timer.Tick += timer_Tick;
timer.Start();
}
private int time = 0;
void timer_Tick(object sender, EventArgs e)
{
label1.Text = time.ToString();
time++;
}
如果不是每隔X个时间间隔执行一次你真正想要做的事情,不管你的命名约定,都要做一些富有成效的工作并根据工作进度更新用户界面,那么它就是一个不同的问题。这里的一个好选择是使用Progress
类来更新UI以及一些非UI任务的进度。它可能看起来像这样:
void Form1_Load(object sender, EventArgs e)
{
Progress<string> progress = new Progress<string>(updateText);
Thread thread = new Thread(() => NoteThreader.DoWork(progress));
thread.Start();
}
public class NoteThreader
{
public static void DoWork(IProgress<string> progress)
{
for (int i = 0; i < 10; i++)
{
Thread.Sleep(1000);//placeholder for real work
progress.Report(i.ToString());
}
}
}