我是Windows窗体中的新手。我正在开发一个单一的表单应用程序,它在Web浏览器中显示消息发送选项以及实时视频流,并使用图表显示实时脉冲图。我可以以其他形式单独成功运行这些进程,但现在我想将所有进程嵌入到一个表单中,但是只要应用程序运行,它就会挂起,只显示视频输入和光标无法移动。我需要一个人来引导我进行线程化。三江源
这是我想要的表格和代码。请帮忙。
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Windows.Forms;
using System.Windows.Forms.DataVisualization.Charting;
using System.Diagnostics;
namespace ClientApp
{
public partial class Form1 : Form
{
private string myMessage = "";
private TcpClient client = new TcpClient();
private IPEndPoint serverEndPoint = new
IPEndPoint(IPAddress.Parse("server
ip"), port1);
Socket socket = new Socket(AddressFamily.InterNetwork,
SocketType.Stream, ProtocolType.Tcp);
public Form1()
{
InitializeComponent();
client.Connect(serverEndPoint);
socket.Connect("server ip", port2);
//thread for running video stream
Thread t1 = new Thread(threadURL);
t1.Start();
}
void threadURL()
{
string URL = "server ip";
webBrowser2.Navigate(URL);
}
// now the chat part(send message to Rpi)
private void RtbClientKeyDown(object sender, KeyEventArgs e)
{
if (e.KeyData != Keys.Enter || e.KeyData != Keys.Return)
{
myMessage += (char)e.KeyValue;
}
else
{
SendMessage(myMessage);
myMessage = "";
}
}
private void SendMessage(string msg)
{
NetworkStream clientStream = client.GetStream();
ASCIIEncoding encoder = new ASCIIEncoding();
byte[] buffer = encoder.GetBytes(msg);
clientStream.Write(buffer, 0, buffer.Length);
clientStream.Flush();
}
//realtime pulse plot part received from socket
System.Windows.Forms.Timer chartTimer = new
System.Windows.Forms.Timer();
private void InitChart()
{
DateTime time = DateTime.Now;
chartTimer.Interval = 1000;
chartTimer.Tick += chartTimer_Tick;
chart1.DoubleClick += chartDemo_DoubleClick;
Series series = chart1.Series[0];
chartTimer.Start();
}
//socket receiving pulse values from Rpi
int ReceiveText()
{
byte[] buffer = new byte[1024];
int iRx = socket.Receive(buffer);
char[] chars = new char[iRx];
System.Text.Decoder d = System.Text.Encoding.UTF8.GetDecoder();
int charLen = d.GetChars(buffer, 0, iRx, chars, 0);
string recv = new string(chars);
int final = Convert.ToInt16(recv);
return final;
}
void chartDemo_DoubleClick(object sender, EventArgs e)
{
chart1.ChartAreas[0].AxisX.ScaleView.Size = 5;
chart1.ChartAreas[0].AxisX.ScrollBar.IsPositionedInside = true;
chart1.ChartAreas[0].AxisX.ScrollBar.Enabled = true;
}
private void LivePulseplot()
{
Series series = chart1.Series[0];
chartTimer.Start();
series.Points.AddXY(DateTime.Now.ToString("hh:mm:ss"),
ReceiveText());
chart1.ChartAreas[0].AxisX.ScaleView.Position = series.Points.Count - 5;
}
void chartTimer_Tick(object sender, EventArgs e)
{
Thread tP = new Thread(LivePulseplot);
tP.Start();
}
}
}
答案 0 :(得分:0)
表单挂起的原因是主线程(创建并呈现UI的主线程)始终在工作。
您有几种可能性可以防止这种情况发生。 一种是启动在后台执行操作的线程(尽管这可能很棘手,因为您需要确保更新UI的任何内容都将该责任委托给UI线程,因为其他线程不允许更改在主线程上创建的内容),就像在代码中一样,其他人正在使用async / await模式或者例如BackgroundWorkers。
您的实施中存在一些问题。 在chartTimer_Tick中,您将开始一个新线程。每次计时器滴答时(每1000毫秒)都会发生这种情况。您不应该在LivePulsePlot中调用chartTimer.Start(),因为计时器已在运行(或者您不会点击该功能)。一旦你在计时器上调用了Start(),它就会每1000毫秒继续执行'Tick'功能,直到你调用Stop()。
此外,System.Windows.Forms.Timer在UI线程上执行其方法,这将导致UI在函数运行时冻结。您可以使用其他计时器,例如System.Timers.Timer如果你想在后台运行一些东西。
在后台线程中执行此操作时需要考虑的一件事是,无论何时想要更新某个screen-element,都必须要求UI线程为您执行此操作(而不是后台线程) 。 在这里阅读更多相关信息: https://docs.microsoft.com/en-us/dotnet/framework/winforms/controls/how-to-make-thread-safe-calls-to-windows-forms-controls
更好的方法(虽然你现在需要投入更多的时间)是使用async / await或BackgroundWorkers,但是你开始实现它的方式也可以工作,有点努力。
希望这有帮助。