目录
[案例一: 启动与停止](#案例一: 启动与停止)
[案例二: 加热装置](#案例二: 加热装置)
在图形用户界面中,主线程负责界面更新,如果只在主线程中运行任务,容易造成UI卡顿。
案例一: 启动与停止
创建winform 项目
在界面中添加2个button

并设计点击事件,start按钮点击后会切换颜色。

我们定义一个action1(),一个简单的循环。
代码如下:
cs
using System;
using System.Windows.Forms;
using System.Drawing;
using System.Threading;
namespace WindowsFormsApp4
{
public partial class Form1 : Form
{
private static bool istart = false;//start 按钮是否按下
private static bool istop = false;//stop 按钮是否按下
public Form1()
{
InitializeComponent();
}
private void button_start_Click(object sender, EventArgs e)
{
istart = !istart;
if (istart){
button_start.BackColor = Color.Green;
MessageBox.Show("已启动");
action1();
}
else {
button_start.BackColor = Color.White;}
}
private void button_stop_Click(object sender, EventArgs e)
{
istop = !istop;
}
private void action1()
{
while (istart)
{
if (istop)
{
break;
}
}
}
}
}
运行,action1被成功调用了,但我们没法关闭它,UI界面卡住了。

原因很简单。
WinForms的UI操作必须在主线程(UI线程)执行,而while(istart)
循环在UI线程中无限运行,导致:
- 界面无法刷新(按钮状态不更新)
- 无法处理其他用户输入(如点击STOP按钮)
我们使用,线程的方式运行action1:
Thread th_action1 = new Thread(action1);
th_action1.Start();
cs
using System;
using System.Windows.Forms;
using System.Drawing;
using System.Threading;
namespace WindowsFormsApp4
{
public partial class Form1 : Form
{
private static bool istart = false;//start 按钮是否按下
private static bool istop = false;//stop 按钮是否按下
public Form1()
{
InitializeComponent();
}
private void button_start_Click(object sender, EventArgs e)
{
istart = !istart;
if (istart){
button_start.BackColor = Color.Green;
Thread th_action1 = new Thread(action1);
th_action1.Start();
}
else {
button_start.BackColor = Color.White;}
}
private void button_stop_Click(object sender, EventArgs e)
{
istop = !istop;
}
private void action1()
{
while (istart)
{
if (istop)
{
button_start.BackColor = Color.White;
break;
}
}
}
}
}
运行后,可以正常使用start 和 stop 按钮。
案例二: 加热装置
在案例1的基础上,添加textbox1

在action1 中,不断增加水温
cs
using System;
using System.Windows.Forms;
using System.Drawing;
using System.Threading;
namespace WindowsFormsApp4
{
public partial class Form1 : Form
{
private static bool istart = false;//start 按钮是否按下
private static bool istop = false;//stop 按钮是否按下
private static int temperature = 0;
public Form1()
{
InitializeComponent();
}
private void button_start_Click(object sender, EventArgs e)
{
istart = !istart;
if (istart){
button_start.BackColor = Color.Green;
Thread th_action1 = new Thread(action1);
th_action1.Start();
}
else {
button_start.BackColor = Color.White;}
}
private void button_stop_Click(object sender, EventArgs e)
{
istop = !istop;
}
private void action1()
{
while (istart)
{
temperature = temperature + 1;
textBox1.Text = temperature.ToString();
Thread.Sleep(500);
if (istop)
{
button_start.BackColor = Color.White;
break;
}
}
}
}
}
运行,
成功报错。

action1 已经进入新线程th_action1,,而操作ui我们得回主线程。
所以,做如下修改:
private void action1()
{
while (istart)
{
temperature = temperature + 1;
//textBox1.Text = temperature.ToString();//报错
//this.BeginInvoke(new Action(() => { textBox1.Text = temperature.ToString(); }));//法一
this.Invoke((MethodInvoker)delegate {textBox1.Text = temperature.ToString();});//法二
Thread.Sleep(1500);
if (istop)
{
break;
}
}
}
其中,Invoke
是同步的,BeginInvoke
是异步的。
也就是说,使用Invoke
时,如果UI线程正忙,调用action1会被阻塞。使用BeginInvoke
时,会继续执行后续代码,而委托会在UI线程的消息循环中排队等待执行。
cs
using System;
using System.Windows.Forms;
using System.Drawing;
using System.Threading;
namespace WindowsFormsApp4
{
public partial class Form1 : Form
{
private static bool istart = false;//start 按钮是否按下
private static bool istop = false;//stop 按钮是否按下
private static int temperature = 0;
public Form1()
{
InitializeComponent();
}
private void button_start_Click(object sender, EventArgs e)
{
istart = !istart;
if (istart){
button_start.BackColor = Color.Green;
Thread th_action1 = new Thread(action1);
th_action1.Start();
}
else {
button_start.BackColor = Color.White;}
}
private void button_stop_Click(object sender, EventArgs e)
{
istop = !istop;
}
private void action1()//加热
{
while (istart)
{
temperature = temperature + 1;
//textBox1.Text = temperature.ToString();//报错
//this.BeginInvoke(new Action(() => { textBox1.Text = temperature.ToString(); }));//法一
this.Invoke((MethodInvoker)delegate {textBox1.Text = temperature.ToString();});//法二
Thread.Sleep(1000);
if (istop)
{
button_start.BackColor = Color.White;
istop = false;
break;
}
}
}
}
}
现在,我们加入室温的降温(每三秒降低1度)。
private void action2()//降温
{
while (true) {
if (temperature > 0) {
temperature = temperature - 1;
this.BeginInvoke(new Action(() => { textBox1.Text = temperature.ToString(); }));
Thread.Sleep(3000);
}
}
}
在加载form1时 就开始运行。
cs
using System;
using System.Windows.Forms;
using System.Drawing;
using System.Threading;
namespace WindowsFormsApp4
{
public partial class Form1 : Form
{
private static bool istart = false;//start 按钮是否按下
private static bool istop = false;//stop 按钮是否按下
private static int temperature = 0;
public Form1()
{
InitializeComponent();
Thread th_action2 = new Thread(action2);
th_action2.Start();
}
private void button_start_Click(object sender, EventArgs e)
{
istart = !istart;
if (istart){
button_start.BackColor = Color.Green;
Thread th_action1 = new Thread(action1);
th_action1.Start();
}
else {
button_start.BackColor = Color.White;}
}
private void button_stop_Click(object sender, EventArgs e)
{
istop = !istop;
}
private void action1()//加热
{
while (istart)
{
temperature = temperature + 1;
//textBox1.Text = temperature.ToString();//报错
//this.BeginInvoke(new Action(() => { textBox1.Text = temperature.ToString(); }));//法一
this.Invoke((MethodInvoker)delegate {textBox1.Text = temperature.ToString();});//法二
Thread.Sleep(1000);
if (istop)
{
button_start.BackColor = Color.White;
istop = false;
break;
}
}
}
private void action2()//降温
{
while (true) {
if (temperature > 0) {
temperature = temperature - 1;
this.BeginInvoke(new Action(() => { textBox1.Text = temperature.ToString(); }));
Thread.Sleep(3000);
}
}
}
}
}
随着action越来越多,逻辑越来越复杂,这种写法并不规范。
对此,做出修改
1.使用lock同步机制保护共享变量_temperature,降低多线程抢变量风险。
2.采用async/await模式
完整代码如下:
cs
using System;
using System.Drawing;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace WindowsFormsApp4
{
public partial class Form1 : Form
{
private bool _istart;
private int _temperature;
private readonly object _tempLock = new object();
private CancellationTokenSource _cts;
public Form1()
{
InitializeComponent();
Load += Form1_Load;
}
private async void Form1_Load(object sender, EventArgs e)
{
await Task.Run(() => action2()); // 启动降温任务
}
private void button_start_Click(object sender, EventArgs e)
{
_istart = !_istart;
if (_istart)
{
_cts = new CancellationTokenSource();
button_start.BackColor = Color.Green;
_ = action1(_cts.Token); // 启动加热任务
}
else
{
_cts?.Cancel();
button_start.BackColor = Color.White;
}
}
private async Task action1(CancellationToken token)
{
while (!token.IsCancellationRequested)
{
lock (_tempLock)
{
_temperature++;
}
UpdateTemperatureText();
try
{
await Task.Delay(1000, token);
}
catch (TaskCanceledException)
{
break;
}
}
}
private async Task action2()
{
while (true)
{
lock (_tempLock)
{
if (_temperature > 0) _temperature--;
}
UpdateTemperatureText();
await Task.Delay(3000);
}
}
private void UpdateTemperatureText()
{
if (textBox1.InvokeRequired)
{
textBox1.Invoke((Action)UpdateTemperatureText);
return;
}
textBox1.Text = _temperature.ToString();
}
}
}
cs
namespace WindowsFormsApp4
{
partial class Form1
{
/// <summary>
/// 必需的设计器变量。
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// 清理所有正在使用的资源。
/// </summary>
/// <param name="disposing">如果应释放托管资源,为 true;否则为 false。</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows 窗体设计器生成的代码
/// <summary>
/// 设计器支持所需的方法 - 不要修改
/// 使用代码编辑器修改此方法的内容。
/// </summary>
private void InitializeComponent()
{
this.button_start = new System.Windows.Forms.Button();
this.button_stop = new System.Windows.Forms.Button();
this.textBox1 = new System.Windows.Forms.TextBox();
this.label1 = new System.Windows.Forms.Label();
this.SuspendLayout();
//
// button_start
//
this.button_start.Location = new System.Drawing.Point(209, 661);
this.button_start.Name = "button_start";
this.button_start.Size = new System.Drawing.Size(248, 128);
this.button_start.TabIndex = 0;
this.button_start.Text = "start";
this.button_start.UseVisualStyleBackColor = true;
this.button_start.Click += new System.EventHandler(this.button_start_Click);
//
// button_stop
//
this.button_stop.Location = new System.Drawing.Point(637, 661);
this.button_stop.Name = "button_stop";
this.button_stop.Size = new System.Drawing.Size(248, 128);
this.button_stop.TabIndex = 1;
this.button_stop.Text = "stop";
this.button_stop.UseVisualStyleBackColor = true;
//this.button_stop.Click += new System.EventHandler(this.button_stop_Click);
//
// textBox1
//
this.textBox1.Font = new System.Drawing.Font("宋体", 35F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134)));
this.textBox1.Location = new System.Drawing.Point(526, 245);
this.textBox1.Name = "textBox1";
this.textBox1.Size = new System.Drawing.Size(121, 87);
this.textBox1.TabIndex = 2;
this.textBox1.Text = "0";
//
// label1
//
this.label1.AutoSize = true;
this.label1.Font = new System.Drawing.Font("宋体", 35F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134)));
this.label1.Location = new System.Drawing.Point(292, 248);
this.label1.Name = "label1";
this.label1.Size = new System.Drawing.Size(240, 70);
this.label1.TabIndex = 3;
this.label1.Text = "水温:";
//
// Form1
//
this.AutoScaleDimensions = new System.Drawing.SizeF(9F, 18F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(1189, 881);
this.Controls.Add(this.label1);
this.Controls.Add(this.textBox1);
this.Controls.Add(this.button_stop);
this.Controls.Add(this.button_start);
this.Name = "Form1";
this.Text = "Form1";
this.ResumeLayout(false);
this.PerformLayout();
}
#endregion
private System.Windows.Forms.Button button_start;
private System.Windows.Forms.Button button_stop;
private System.Windows.Forms.TextBox textBox1;
private System.Windows.Forms.Label label1;
}
}
案例三:电梯
创建c# winform 项目 lift
添加几个button 和 textbox

cs
namespace lift
{
partial class Form1
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
textBox_layer = new TextBox();
label1 = new Label();
textBox_door = new TextBox();
label2 = new Label();
button_L1 = new Button();
button_L2 = new Button();
button_L3 = new Button();
button_L4 = new Button();
label3 = new Label();
SuspendLayout();
//
// textBox_layer
//
textBox_layer.Font = new Font("Microsoft YaHei UI", 40F);
textBox_layer.Location = new Point(228, 53);
textBox_layer.Name = "textBox_layer";
textBox_layer.Size = new Size(124, 109);
textBox_layer.TabIndex = 0;
textBox_layer.Text = "1";
//
// label1
//
label1.AutoSize = true;
label1.Font = new Font("Microsoft YaHei UI", 18F);
label1.Location = new Point(12, 85);
label1.Name = "label1";
label1.Size = new Size(200, 46);
label1.TabIndex = 1;
label1.Text = "目前楼层:";
//
// textBox_door
//
textBox_door.Font = new Font("Microsoft YaHei UI", 20F);
textBox_door.Location = new Point(196, 211);
textBox_door.Name = "textBox_door";
textBox_door.Size = new Size(170, 58);
textBox_door.TabIndex = 3;
textBox_door.Text = "CLOSE";
//
// label2
//
label2.AutoSize = true;
label2.Font = new Font("Microsoft YaHei UI", 18F);
label2.Location = new Point(112, 421);
label2.Name = "label2";
label2.Size = new Size(200, 46);
label2.TabIndex = 4;
label2.Text = "电梯按钮:";
//
// button_L1
//
button_L1.Location = new Point(85, 723);
button_L1.Name = "button_L1";
button_L1.Size = new Size(82, 72);
button_L1.TabIndex = 5;
button_L1.Text = "1";
button_L1.UseVisualStyleBackColor = true;
button_L1.Click += button_L1_Click;
//
// button_L2
//
button_L2.Location = new Point(295, 723);
button_L2.Name = "button_L2";
button_L2.Size = new Size(82, 72);
button_L2.TabIndex = 6;
button_L2.Text = "2";
button_L2.UseVisualStyleBackColor = true;
button_L2.Click += button_L2_Click;
//
// button_L3
//
button_L3.Location = new Point(85, 543);
button_L3.Name = "button_L3";
button_L3.Size = new Size(82, 72);
button_L3.TabIndex = 7;
button_L3.Text = "3";
button_L3.UseVisualStyleBackColor = true;
button_L3.Click += button_L3_Click;
//
// button_L4
//
button_L4.Location = new Point(295, 543);
button_L4.Name = "button_L4";
button_L4.Size = new Size(82, 72);
button_L4.TabIndex = 8;
button_L4.Text = "4";
button_L4.UseVisualStyleBackColor = true;
button_L4.Click += button_L4_Click;
//
// label3
//
label3.AutoSize = true;
label3.Font = new Font("Microsoft YaHei UI", 18F);
label3.Location = new Point(24, 211);
label3.Name = "label3";
label3.Size = new Size(128, 46);
label3.TabIndex = 9;
label3.Text = "电梯门";
//
// Form1
//
AutoScaleDimensions = new SizeF(11F, 24F);
AutoScaleMode = AutoScaleMode.Font;
ClientSize = new Size(925, 915);
Controls.Add(label3);
Controls.Add(button_L4);
Controls.Add(button_L3);
Controls.Add(button_L2);
Controls.Add(button_L1);
Controls.Add(label2);
Controls.Add(textBox_door);
Controls.Add(label1);
Controls.Add(textBox_layer);
Name = "Form1";
Text = "Form1";
ResumeLayout(false);
PerformLayout();
}
#endregion
private TextBox textBox_layer;
private Label label1;
private TextBox textBox_door;
private Label label2;
private Button button_L1;
private Button button_L2;
private Button button_L3;
private Button button_L4;
private Label label3;
}
}
和案例二差不多,使用异步的方式 操作 楼层。
最大的区别是,案例二只有一个start按钮,而这里有多个楼层按钮
当同时按下多个按钮时,多个任务会同时运行,导致currentFloor被多个线程修改,引发竞态。
cs
using System;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace lift
{
public partial class Form1 : Form
{
private int currentFloor = 1; // 当前楼层
private readonly object floorLock = new object();
public Form1()
{
InitializeComponent();
}
private async Task LiftUp()//上升
{
if (currentFloor < 4)
{
await Task.Delay(2000);
lock (floorLock)
{
currentFloor++;
}
UpdateFloorDisplay();
}
}
private async Task LiftDown()//下降
{
if (currentFloor > 1)
{
await Task.Delay(2000);
lock (floorLock)
{
currentFloor--;
}
UpdateFloorDisplay();
}
}
private void UpdateFloorDisplay()
{
if (textBox_layer.InvokeRequired)
{
textBox_layer.BeginInvoke((Action)UpdateFloorDisplay);
return;
}
textBox_layer.Text = currentFloor.ToString();
}
private async Task LiftRun(int targetFloor)//运行
{
while (currentFloor != targetFloor)
{
if (targetFloor > currentFloor)
{
await LiftUp();
}
else
{
await LiftDown();
}
}
await OpenDoor();
}
private async Task OpenDoor()//开门
{
await Task.Delay(1000);
if (textBox_door.InvokeRequired)
{
textBox_door.BeginInvoke((Action)(() => textBox_door.Text = "OPEN"));
}
else
{
textBox_door.Text = "OPEN";
}
await Task.Delay(2000);
if (textBox_door.InvokeRequired)
{
textBox_door.BeginInvoke((Action)(() => textBox_door.Text = "CLOSE"));
}
else
{
textBox_door.Text = "CLOSE";
}
}
private async void button_L1_Click(object sender, EventArgs e)
{
await LiftRun(1);
}
private async void button_L2_Click(object sender, EventArgs e)
{
await LiftRun(2);
}
private async void button_L3_Click(object sender, EventArgs e)
{
await LiftRun(3);
}
private async void button_L4_Click(object sender, EventArgs e)
{
await LiftRun(4);
}
}
}
为了解决多个按钮打架的问题。
我们只允许 一个事件在运行。
所以需要添加中断,后按的会中断之前的任务。
代码如下:
cs
using System;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace lift
{
public partial class Form1 : Form
{
private int currentFloor = 1; // 当前楼层
private readonly object floorLock = new object();
private CancellationTokenSource _cts;
private readonly object _targetLock = new object();
private int _targetFloor = 1;
public Form1()
{
InitializeComponent();
}
private async Task LiftRun(CancellationToken token)
{
while (!token.IsCancellationRequested)
{
int currentTarget;
lock (_targetLock)
{
currentTarget = _targetFloor;
}
if (currentFloor == currentTarget)
{
await OpenDoor();
return;
}
if (currentTarget > currentFloor)
{
await LiftUp(token);
}
else
{
await LiftDown(token);
}
}
}
// 修改后的上升方法
private async Task LiftUp(CancellationToken token)
{
if (currentFloor < 4)
{
await Task.Delay(2000, token); // 使用带取消令牌的延迟
token.ThrowIfCancellationRequested();
lock (floorLock)
{
currentFloor++;
}
UpdateFloorDisplay();
}
}
// 修改后的下降方法
private async Task LiftDown(CancellationToken token)
{
if (currentFloor > 1)
{
await Task.Delay(2000, token); // 使用带取消令牌的延迟
token.ThrowIfCancellationRequested();
lock (floorLock)
{
currentFloor--;
}
UpdateFloorDisplay();
}
}
private async Task OpenDoor()//开门
{
await Task.Delay(1000);
if (textBox_door.InvokeRequired)
{
textBox_door.BeginInvoke((Action)(() => textBox_door.Text = "OPEN"));
}
else
{
textBox_door.Text = "OPEN";
}
await Task.Delay(2000);
if (textBox_door.InvokeRequired)
{
textBox_door.BeginInvoke((Action)(() => textBox_door.Text = "CLOSE"));
}
else
{
textBox_door.Text = "CLOSE";
}
}
// 统一处理楼层请求的方法
private async Task HandleFloorRequest(int requestedFloor)
{
// 更新目标楼层
lock (_targetLock)
{
_targetFloor = requestedFloor;
}
// 取消当前运行的任务
_cts?.Cancel();
// 创建新的取消令牌
var newCts = new CancellationTokenSource();
_cts = newCts;
try
{
await LiftRun(newCts.Token);
}
catch (OperationCanceledException)
{
// 正常取消,无需处理
}
}
private async void button_L1_Click(object sender, EventArgs e)
{
await HandleFloorRequest(1);
}
private async void button_L2_Click(object sender, EventArgs e)
{
await HandleFloorRequest(2);
}
private async void button_L3_Click(object sender, EventArgs e)
{
await HandleFloorRequest(3);
}
private async void button_L4_Click(object sender, EventArgs e)
{
await HandleFloorRequest(4);
}
private void UpdateFloorDisplay()
{
if (textBox_layer.InvokeRequired)
{
textBox_layer.BeginInvoke((Action)UpdateFloorDisplay);
return;
}
textBox_layer.Text = currentFloor.ToString();
}
}
}
运行后:
屏幕录制 2025-08-11 112753
显然,视频中,后按的按钮直接打断了之前的任务。
为了能像现实中的电梯一样有序,进行改进:
cs
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace lift
{
public partial class Form1 : Form
{
private int currentFloor = 1;
private readonly object stateLock = new object();
private readonly SortedSet<int> upRequests = new SortedSet<int>();
private readonly SortedSet<int> downRequests = new SortedSet<int>(Comparer<int>.Create((x, y) => y.CompareTo(x)));
private bool isMoving = false;
private bool doorOpen = false;
public Form1()
{
InitializeComponent();
UpdateDisplay();
}
private void UpdateDisplay()
{
if (textBox_layer.InvokeRequired)
{
textBox_layer.BeginInvoke((Action)UpdateDisplay);
return;
}
textBox_layer.Text = currentFloor.ToString();
textBox_door.Text = doorOpen ? "OPEN" : "CLOSE";
}
private async Task ElevatorLoop()
{
while (true)
{
int nextFloor = GetNextDestination();
if (nextFloor == -1)
{
isMoving = false;
await Task.Delay(100);
continue;
}
isMoving = true;
await MoveToFloor(nextFloor);
await HandleStop(nextFloor);
}
}
private int GetNextDestination()
{
lock (stateLock)
{
// 优先处理当前楼层的请求
if (upRequests.Contains(currentFloor) || downRequests.Contains(currentFloor))
{
return currentFloor;
}
// 根据当前方向选择下一个目标
if (upRequests.Count > 0)
{
return upRequests.Min;
}
if (downRequests.Count > 0)
{
return downRequests.Max;
}
return -1; // 无请求
}
}
private async Task MoveToFloor(int targetFloor)
{
while (currentFloor != targetFloor)
{
await Task.Delay(1000); // 移动时间缩短为1秒便于测试
lock (stateLock)
{
if (currentFloor < targetFloor)
{
currentFloor++;
}
else
{
currentFloor--;
}
}
UpdateDisplay();
// 检查移动过程中是否有同方向的中间请求
await CheckIntermediateStops();
}
}
private async Task CheckIntermediateStops()
{
lock (stateLock)
{
// 如果是上行且当前楼层有上行请求
if (upRequests.Contains(currentFloor))
{
// 临时移除请求,会在HandleStop中重新添加
upRequests.Remove(currentFloor);
}
// 如果是下行且当前楼层有下行请求
else if (downRequests.Contains(currentFloor))
{
downRequests.Remove(currentFloor);
}
else
{
return;
}
}
// 立即处理当前楼层的请求
await HandleStop(currentFloor);
}
private async Task HandleStop(int floor)
{
// 开门
doorOpen = true;
UpdateDisplay();
await Task.Delay(1500); // 开门时间
// 处理当前楼层的所有请求
lock (stateLock)
{
upRequests.Remove(floor);
downRequests.Remove(floor);
}
// 关门
doorOpen = false;
UpdateDisplay();
await Task.Delay(1000); // 关门时间
// 重新评估方向
EvaluateDirection();
}
private void EvaluateDirection()
{
lock (stateLock)
{
// 如果没有请求了,保持静止
if (upRequests.Count == 0 && downRequests.Count == 0)
{
isMoving = false;
return;
}
// 如果有上行请求在当前楼层之上,或下行请求在当前楼层之下
isMoving = (upRequests.Count > 0 && upRequests.Min > currentFloor) ||
(downRequests.Count > 0 && downRequests.Max < currentFloor);
}
}
private void AddRequest(int floor)
{
if (floor < 1 || floor > 4)
{
MessageBox.Show("无效楼层请求");
return;
}
lock (stateLock)
{
// 根据当前位置和方向决定将请求加入哪个队列
if (floor > currentFloor)
{
upRequests.Add(floor);
downRequests.Remove(floor); // 确保请求不在两个队列中
}
else if (floor < currentFloor)
{
downRequests.Add(floor);
upRequests.Remove(floor);
}
else
{
// 当前楼层的请求立即处理
upRequests.Add(floor); // 随便加一个队列,会在HandleStop中处理
}
// 如果电梯静止,启动它
if (!isMoving && !doorOpen)
{
Task.Run(ElevatorLoop);
}
}
}
private void button_L1_Click(object sender, EventArgs e) => AddRequest(1);
private void button_L2_Click(object sender, EventArgs e) => AddRequest(2);
private void button_L3_Click(object sender, EventArgs e) => AddRequest(3);
private void button_L4_Click(object sender, EventArgs e) => AddRequest(4);
}
}