[英]C# WinForm application UI freezes after long period
我已经在.NET 2.0上使用C#开发了Winform UI(编辑:我可以将其迁移到3.5,但不确定...因为服务器环境> <)。
长期操作应由后台工作人员进行适当包装,并且它定期通过事件“ ProgressChanged”将信息返回给用户,以在UI中显示。 到现在为止还挺好。
我的问题如下:长期操作可能是无限的(它在套接字上发送信息),因此用户必须通过“取消按钮”将其停止。 遗憾的是,UI变得无响应,有点死机,就像经过1个小时的运行之后。
我尝试设置一个计时器,以强制每5分钟刷新一次UI,但这似乎无济于事。
我的“主要”类具有[STAThread]
属性。
我该如何解决?
编辑-WinForm中的代码如下所示:
public MainForm()
{
InitializeComponent();
this._bw = new BackgroundWorker();
this._bw.WorkerReportsProgress = true;
this._bw.WorkerSupportsCancellation = true;
this._bw.DoWork += new DoWorkEventHandler(_bw_DoWork);
this._bw.ProgressChanged += new ProgressChangedEventHandler(_bw_ProgressChanged);
this._bw.RunWorkerCompleted += new RunWorkerCompletedEventHandler(_bw_RunWorkerCompleted);
//... more initialization
}
private void btn_sendMessagesContinuous_Click(object sender, EventArgs e)
{
//Argument construction
BackgroundWorkerArgument bwArgument = this.CheckParametersAndCreateBwArgument(BackgroundWorkerTaskEnum.ConnectionContinuous);
//Launch
if (this._bw.IsBusy == false)
{
//Activating ProgressBar and CancelButton
this.SetControlsBeforeWork();
this._bw.RunWorkerAsync(bwArgument);
}
}
private void _bw_DoWork(object sender, DoWorkEventArgs e)
{
BackgroundWorker worker = sender as BackgroundWorker;
RmessService rmessService = null;
//Timer for GUI refresh
_refreshTimer.Start();
//Getting the arguments
BackgroundWorkerArgument bwArgument = e.Argument as BackgroundWorkerArgument;
BackgroundWorkerTaskEnum bwTask = bwArgument.BackgroundWorkerTaskEnum;
try
{
switch (bwTask)
{
case BackgroundWorkerTaskEnum.ConnectionContinuous:
rmessService = new RmessService(worker);
bwArgument.ServiceMakesReports = true;
rmessService.ConnectToRmess(bwArgument);
while (worker.CancellationPending == false && rmessService.IsStillConnected())
{
// Used to lower the processor usage
System.Threading.Thread.Sleep(100);
}
break;
case ...
}
}
catch (Exception ex)
{ //... do the log and stuff ... }
finally
{
if (rmessService != null)
{ rmessService.Dispose(); }
}
现在,对于服务,我选择将backgroundWorker传递到服务的构造函数中。 我知道,应该已经经历了服务内部的事件,但这不是重点……希望吗?
因此,我在服务中有以下内容:
///Constructor
public RmessService(BackgroundWorker backgroundWorker)
{
this._bwMainForm = backgroundWorker;
this._dicoThreadSocketConnection = new Dictionary<BackgroundWorker, bool>();
}
///Main method of the service
public void ConnectToRmess(BackgroundWorkerArgument bwArguments)
{
this._bwMainForm.ReportProgress(0, new BackgroundWorkerProgressState(BackgroundWorkerProgressEnum.SetProgressInformation, "Test de connexion au socket en cours ..."));
Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
try
{
socket.Connect(bwArguments.AdresseIP, bwArguments.Port);
Thread.Sleep(100);
}
finally
{
if (socket.Connected)
{ socket.Disconnect(false); }
}
this._bwMainForm.ReportProgress(0, new BackgroundWorkerProgressState(BackgroundWorkerProgressEnum.SetProgressInformation, "Envoi des messages en cours ..."));
int index = 0;
long idBoitier = bwArguments.IdBoitier;
while (index < bwArguments.NombreConnexions)
{
BackgroundWorker bwSocket = new BackgroundWorker();
bwSocket.WorkerReportsProgress = true;
bwSocket.WorkerSupportsCancellation = true;
bwSocket.DoWork += new DoWorkEventHandler(bwSocket_DoWork);
bwSocket.ProgressChanged += new ProgressChangedEventHandler(bwSocket_ProgressChanged);
bwSocket.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bwSocket_RunWorkerCompleted);
//Ajout du BW à la liste
this._dicoThreadSocketConnection.Add(bwSocket, false);
//Construction des arguments à passer
List<object> listArguments = new List<object>() { bwArguments, idBoitier };
bwSocket.RunWorkerAsync(listArguments);
Thread.Sleep(100);
//Incrémentation
idBoitier++;
index++;
}
}
private void bwSocket_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
//Simple message transfer
this._bwMainForm.ReportProgress(0, e.UserState);
}
编辑2:这是其余的代码。
private void _bw_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
BackgroundWorkerProgressState bwProgressState = e.UserState as BackgroundWorkerProgressState;
switch (bwProgressState.BackgroundWorkerProgressEnum)
{
case BackgroundWorkerProgressEnum.SetProgressInformation:
this.lbl_progressInfo.Text = bwProgressState.State as string;
break;
case BackgroundWorkerProgressEnum.AddSocketProgressMessage:
this.richTextBox_generalInfo.Text += (bwProgressState.State as string) + "\r\n";
break;
default:
break;
}
}
private void _bw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
//Stopping ProgressBar animation
this.SetControlsAfterWork();
}
好像@groverboy先前的评论是一种简单的解决方案: 不幸的是,我经常用一些信息来更新“ richTextBox”(充当“即时日志”)……
频率更新所带来的问题要比所添加字符串的绝对数量少。 尽管如果我从许多套接字开始,更新频率也可能会成为问题。
我用许多可能的方法之一解决了它:更新较少的信息。 一句话记录的时间为一分钟,而不是每分钟1000个。
当然,保留日志的最佳方法是将其放入文件中。 就我而言,日志没有其他目的,只能立即说“一切都很好”。 另一种方法是剔除richTextBox中的文本。
感谢您的帮助!
编辑-
我将说明问题的出处:最初,我的软件可以测试特定IP:端口上的套接字连接。 给定IP上的接收服务应该处理多个连接。 对于一个连接,您可以有多个发送(对于一个发送,则可以有多个消息)。 对于每次发送,我都将在日志中写入日志,即GUI中的“ richTextBox”:“通知人X正确发送Y”。
只要定义了您的连接号和每个连接的发送,这种情况就没问题了。 该软件经过改进,可以保持连接,但发送数量不受限制。
在后一种情况下,即使连接数很小,文本也会增长得太快(一个连接大约发送10条消息,因此只有10条消息)。
当长度超过10.000个字符时,我已经在TextChanged
事件中测试了文本重置:使用使我的GUI冻结的相同设置完全没有问题。
这使我认为字符串长度是主要问题,尽管更新频率也可能使情况更糟。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.