我是c#程序的新手。我想创建在主UI中移动标签的线程,而不会粘贴UI直到移动完成 我建了一些东西,但它没有用 告诉我我的问题是什么
private void button1_Click(object sender, EventArgs e)
{
Thread t = new Thread(Movelb);
t.IsBackground = true;
t.Start();enter code here
}
private void DOsomeThing()
{
label2.Visible = true;
label2.Location = new Point(0, 205);
for (int i = 0; i < 533; i++)
{
label2.Location = new Point(i, 205);
Thread.Sleep(10);
}
label1.Text="false";
}
private void Movelb()
{
if (this.InvokeRequired)
{
threadDel d = new threadDel(DOsomeThing);
this.BeginInvoke(d);
}
else
DOsomeThing();
}
答案 0 :(得分:1)
您需要先了解事件模型。在Windows或Android或Linux等事件驱动的环境中......“自动”任务(如坐标动画或其他属性)通常使用定时器完成,定时器会将事件重新发送回推进动画/过程的处理程序。在您的特定示例中 - 如果您需要移动标签,请使用Widows.Forms.Timer。阻止处理具有冗长任务的事件的UI线程是不合适的,因为UI线程将停止并且您的应用程序将冻结或变得不稳定。现在,另一方面,在添加额外线程的情况下,有很多情况需要帮助很多,何时?不是在你的情况下,因为你只更改了与重绘相比没有任何CPU标签的坐标,所以你的解决方案与额外的线程相比,效率低,而且比使用计时器复杂得多。额外的线程只有在它对动画模型执行的逻辑工作具有可比性或超出绘画工作量时才有用 - 想象一下根据许多逻辑规则需要在屏幕上动画200个错误的游戏,在这种情况下,错误绘画可能是在UI线程中完成,但是如果那些计算很激烈,则可以在另一个线程中完成bug属性更改/动画。
活动如何运作?
操作系统内部存在无限循环,被键盘,鼠标和其他事件中断,但循环无限循环,直到关闭Windows(或Android或XWidnws ...)。在循环结束时,OS查看“原始”鼠标/键事件并将它们分派到适当的应用程序队列中。它通过检查每个应用程序窗口列表来了解它,该列表位于顶部,因此它知道哪个窗口/应用程序在这样的X,Y鼠标坐标下。当事件被调度到您的应用程序时,您的工作是非常快速地处理它并在队列中查找另一个事件(队列绑定到UI线程/ Windows)。
定时器如何工作? 计时器是一种特殊的事件,操作系统可以定期从其内部“无限循环”发送给您。操作系统会跟踪请求通知的应用程序以及频率 - 当时间到来时,它会在您的Windows队列中添加WM_TIMER(在MS Windows上)。这样你就不会阻塞任何东西,而是在你的代码中获得一个每X毫秒调用一次的方法。当您使用.NET Timer类时 - 它只是Windows用户API中的CreateTimer()KillTimer()(我不记得确切的函数名称)的包装器。 .NET Timer还知道如何吞下WM_TIMER并为您调用C#事件/委托。
我希望这有帮助!
答案 1 :(得分:1)
不要使用线程绘制表单或修改/更新表单内容。 Windows编程中推荐的范例是每个窗体一个线程或窗口。如果要创建从不同线程运行的表单,则必须
这样,新线程将作为新Form的消息处理程序。但即使这样,你仍然应该在该线程中对Form进行所有操作(如果表单想要修改在另一个线程上运行的另一种形式的内容,那么可能需要一些额外的线程安全通信技巧)。
要为窗口内容设置动画,您应该使用System.Windows.Forms.Timer
代替它,它在Form的线程上以锁定步骤与其他消息一起执行。但是,您需要将动画重新实现为状态机而不是for()
循环结构。这意味着Label位置的变量需要嵌入到Form类中,以便可以在Timer消息调用中保留更新。
答案 2 :(得分:0)
您的代码没有任何用处。它只是启动一个新的后台线程,它反过来调用一个委托,在同一个UI线程上执行,该线程已经启动......后台线程。
换句话说,你不能在工作线程中移动标签,因为移动标签会带来重新绘制,这是后台线程无法完成的。
答案 3 :(得分:0)
我也有过在线程中做一些工作的想法 - 虽然这项艰巨的工作 已执行... main-gui-form 应修改,因此用户将 发现进展。 做了一些查找并进入“委托”、“事件处理程序”和“非常高级的代码段”。 我花了一些时间来修复,我想出了这个非常简单的例子。看看。
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace ProcessingUI
// You will find a form with "button1": will do some work in a seperate thread, and
// therefore you are allowed to do action in main-gui-form while this work is done,
// due to async. operation.
// While work is done in seperate thread - the main-gui-form will have a label modified...
// having the steps: 1,2,3,0.
// Also found... "button2": will do some work in same thread as gui, and
// therefore you are not allowed to do action in main-gui-form while this work is done,
// due to sync. operation (only one thread is established).
// While work is done in one-and-only-thread - the main-gui-form will have a label modified...
// having the steps: 1,2,3,0.
{
public delegate void UpdateTextDelegate();
public partial class Form1 : Form
{
public delegate void SetStatusText(string statusText);
public SetStatusText mySetStatusTextDelegate;
public Form1()
{
InitializeComponent();
mySetStatusTextDelegate = new SetStatusText(SetStatusTextMethod);
}
private void button1_Click(object sender, EventArgs e) // do work from new thread.
{
Worker w = new Worker(this);
Thread thread1 = new Thread(new ThreadStart(w.DoWork));
thread1.Start();
}
private void button2_Click(object sender, EventArgs e) // do work from local class - form is locked during 1-3 steps.
{
SetStatusTextMethod("1");
Thread.Sleep(3000);
SetStatusTextMethod("2");
Thread.Sleep(3000);
SetStatusTextMethod("3");
Thread.Sleep(3000);
SetStatusTextMethod("0");
}
public void SetStatusTextMethod(string statusText)
{
label1.Text = statusText;
label1.Refresh();
}
}
public class Worker
{
Form1 guiForm; // holds form where "control-to-be-changes" is found.
public Worker(Form1 _guiForm)
{
guiForm = _guiForm;
}
public void DoWork() // while steps are being done - form can easily be moved around... is not locked!
{
// put "1/3" on form.
guiForm.Invoke(guiForm.mySetStatusTextDelegate, "1");
Thread.Sleep(3000);
// put "2/3" on form.
guiForm.Invoke(guiForm.mySetStatusTextDelegate, "2");
Thread.Sleep(3000);
// put "3/3" on form.
guiForm.Invoke(guiForm.mySetStatusTextDelegate, "3");
Thread.Sleep(3000);
guiForm.Invoke(guiForm.mySetStatusTextDelegate, "0");
}
}
}