我在.NET 2.0上开发了一个带有C#的Winform UI(编辑:我可以将其迁移到3.5但不确定......因为服务器环境><)。 长期操作受到backgroundworker的限制,并且它会定期提供信息,以便通过事件" ProgressChanged"在UI中显示。到目前为止,非常好。
我的问题如下:长期操作可能是无限的(它在套接字上发送信息),因此用户必须通过"取消按钮"来停止它。唉,用户界面变得反应迟钝,有点冷冻,就像经过一个多小时的运行一样。
我试图设置一个计时器,每5分钟强制刷新一次UI,但这似乎没有帮助......
我的主要"顺便说一下,class有[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();
}
答案 0 :(得分:0)
似乎@groverboy之前发表的评论是一个简单的解决方案:我经常用一些信息更新“richTextBox”(充当“即时日志”)......太遗憾了。
频率更新不仅仅是添加字符串的绝对数量。虽然如果我从许多套接字开始,更新频率也可能成为一个问题。
我用许多可能的方法之一解决了它:更新更少的信息。一分钟记录一句话而不是每分钟约1000 当然,保存日志的最佳方法是将其放在文件中。在我的情况下,日志没有其他目的,只是立即说“一切都很好”。另一种方法是剔除richTextBox中的文本。
感谢您的帮助!
编辑 -
我将解释我的问题来自哪里:最初我的软件可以测试特定IP上的套接字连接:端口。给定IP的接收服务应该处理多个连接。对于一个连接,您可以有多个发送(对于一个发送,多个消息)。对于每次发送,我都会在日志中写入,即GUI中的“richTextBox”:“informer n°X正确发送Y”。
这种情况没问题......只要定义了每个连接的连接数和发送数。该软件的发展是为了能够保持连接,但发送的数量无限。
在最后一种情况下,文本增长得太快(一个连接大约发送10个,所以这是10个消息),即使只有一个小的连接数。
我已经在TextChanged
事件中测试了文本重置,当长度超过10.000个字符时:使用相同的设置使我的GUI冻结没有任何问题。
这让我觉得字符串长度是主要问题,尽管更新的频率也可能使事情变得更糟。