0

我有两个类;一个叫做 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 并且有效。

4

3 回答 3

2

在您的方法中,您将在每次循环执行时threadDeligation创建一个新实例。Form1这不会更改Form1您正在查看的实例中的文本。

您需要将正确的实例传递Form1createTimer方法(然后将其传递给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++;
    }
}

这应该让您大致了解如何在代码中传递对象,但它不会起作用,因为不支持从非 UI 线程更新 UI 元素。您将需要改用BackgroundWorker该类。

于 2013-09-05T16:43:11.533 回答
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());
        }
    }
}
于 2013-09-05T16:57:22.783 回答
1
for (; ; )
{
    Form1 a = new Form1();
    a.updateText(time);
    time++;
}
  1. Form1每次迭代都会创建新对象。
  2. 在哪里a.Show();

如果要显示计时器的值,则应保持对适当Form1对象的引用。

于 2013-09-05T16:38:36.950 回答