2013-04-10 110 views
1

我有一个表单需要通过Web服务调用将未保存的数据保存到外部数据库。当用户手动保存数据时,RunWorkerCompleted被触发,但当我通过FormClosing事件调用方法时不会触发。从FormClosing触发时RunWorkerCompleted没有触发

计时器在用户修改表单中的某个值之后几秒钟后打勾,如果用户修改另一个值,则重置该计时器,该想法是'toSend'列表具有多个值,并且我可以发布多个自Web服务调用以来,每次更改的开销都很大。

private void timer1_Tick(object sender, EventArgs e) 
    { 
     if (PublishBackgroundWorker.IsBusy) 
      return; 

     List<object> toSend = new List<object>(); 

     // Figure out what changed and add it to toSend ... 
     toSend.Add(changedItems); 

     if (toSend.Count >= 1) 
      PublishBackgroundWorker.RunWorkerAsync(toSend); 
    } 

    private void PublishBackgroundWorker_DoWork(object sender, DoWorkEventArgs e) 
    { 
     if (((List<object>)(e.Argument)).Count > 0) 
     { 
      Service.SrvObjects[] ret = Svc.PublishItems(e.Argument)); 
     } 
    } 

    private void PublishBackgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) 
    { 
     Invoke(new UpdateStatusCallback(this.UpdateStatus), new object[] { "Ready" }); 
    } 

    private void IPTUserInterfaceForm_FormClosing(object sender, FormClosingEventArgs e) 
    { 
     timer1.Enabled = false; 
     timer1_Tick(this, new EventArgs()); 
     //Application.DoEvents(); 
     while (PublishBackgroundWorker.IsBusy) 
      System.Threading.Thread.Sleep(100); 
    } 

这是否有意义?当用户更改一个值并在计时器关闭之前关闭表单时,我手动勾选希望PublishBackgroundWorker.IsBusy在某个时刻为false,并且它永远不会因为RunWorkerCompleted从不被调用。

+0

我看不出一个理由,你为什么会叫'从内部'PublishBackgroundWorker_RunWorkerCompleted' Invoke'。 – 2013-04-10 19:12:17

+0

它只是发布到服务器的用户更新完成。因为它在一个单独的线程上,我需要一个代表来更新表单上的文本。 private void UpdateStatus(string text){StatusStripLabel.Text = text; System.Threading.Thread.Sleep(5); } – Tizz 2013-04-10 19:13:59

+1

第一本能:这听起来像缺少一个[Application.DoEvents](http://msdn.microsoft.com/en-us//library/system.windows.forms.application.doevents.aspx)调用。另请参见[这里](http://stackoverflow.com/questions/1115397/application-doevents-when-its-necessary-and-when-its-not) – 2013-04-10 19:14:22

回答

2

问题是您的Backgroundworker不是因为您调用timerTick方法而不忙。因此永远达不到这个代码的方法的其余部分运行前通过和形式被关闭,应用程序关闭:

while (PublishBackgroundWorker.IsBusy) 
     System.Threading.Thread.Sleep(100); 
+0

但是后台工作者RunWorkerAsync在Timer_Tick中被调用,不会触发工作者运行,因此该线程在DoWork完成后需要调用RunWorkerCompleted? – Tizz 2013-04-10 19:39:12

+1

尝试放置'Thread.Sleep(100);'在你的代码中有'//Application.DoEvents();'...我猜这是一个竞争条件。 – Akku 2013-04-10 19:56:36

+0

明白了......如果我把'Application.DoEvents'放在带Sleep的while循环中,它就可以工作。我知道了。谢谢! – Tizz 2013-04-10 20:05:50