将dispatchertimer与异步调用结合使用

时间:2010-05-11 13:29:08

标签: silverlight dispatchertimer

我们的Silverlight应用程序中存在一个问题,它使用WCF和实体框架,我们需要在用户通过关闭网页或浏览器而不是关闭silverlight应用程序来关闭应用程序时捕获事件。这是为了验证是否进行了任何更改,在这种情况下,我们会在离开之前询问用户是否要保存。

我们能够完成捕获网页关闭的部分:我们在应用程序对象中编写了一些代码,这些代码使网页调用silverlight应用程序对象中的方法。问题开始时,在此方法中,我们对Web服务进行异步调用以验证是否发生了更改(IsDirty)。我们使用DispatcherTimer来检查异步调用的返回。问题是异步调用永远不会完成(在调试模式下,它永远不会最终进入_BfrServ_Customer_IsDirtyCompleted方法),而在我们添加这个新功能之前它曾经工作正常。

您将在下面找到我们正在使用的代码。

我不熟悉将定时器与异步调用结合起来,所以我可能做错了但我无法弄清楚是什么。我也尝试了其他的东西,但我们没有任何成功..

======================代码======================== ======================

''# Code in the application object 

Public Sub New()

  InitializeComponent()

  RegisterOnBeforeUnload()

  _DispatcherTimer.Interval = New TimeSpan(0, 0, 0, 0, 500)

End Sub


Public Sub RegisterOnBeforeUnload()

  ''# Register Silverlight object for availability in Javascript.

  Const scriptableObjectName As String = "Bridge"

  HtmlPage.RegisterScriptableObject(scriptableObjectName, Me)

  ''# Start listening to Javascript event.

  Dim pluginName As String = HtmlPage.Plugin.Id

  HtmlPage.Window.Eval(String.Format("window.onbeforeunload = function () {{ var slApp = document.getElementById('{0}'); var result = slApp.Content.{1}.OnBeforeUnload(); if(result.length > 0)return result;}}", pluginName, scriptableObjectName))

End Sub


Public Function OnBeforeUnload() As String

  Dim userControls As List(Of UserControl) = New List(Of UserControl)

  Dim test As Boolean = True

  If CType(Me.RootVisual, StartPage).LayoutRoot.Children.Item(0).GetType().Name = "MainPage" Then

    If Not CType(CType(Me.RootVisual, StartPage).LayoutRoot.Children.Item(0), MainPage).FindName("Tab") Is Nothing Then

      If CType(CType(Me.RootVisual, StartPage).LayoutRoot.Children.Item(0), MainPage).FindName("Tab").Items.Count >= 1 Then

        For Each item As TabItem In CType(CType(Me.RootVisual, StartPage).LayoutRoot.Children.Item(0), MainPage).Tab.Items

          If item.Content.GetType().Name = "CustomerDetailUI"

            _Item = item

            WaitHandle = New AutoResetEvent(False)

            DoAsyncCall()

            Exit

          End If

        Next

      End If

    End If

  End If

  If _IsDirty = True Then

    Return "Do you want to save before leaving."

  Else

    Return String.Empty

  End If

End Function


Private Sub DoAsyncCall()

  _Item.Content.CheckForIsDirty(WaitHandle) ''# This code resides in the CustomerDetailUI UserControl - see below for the code

End Sub


Private Sub _DispatcherTimer_Tick(ByVal sender As Object, ByVal e As System.EventArgs) Handles _DispatcherTimer.Tick

  If Not _Item.Content._IsDirtyCompleted = True Then

    Exit Sub

  End If

  _DispatcherTimerRunning = False

  _DispatcherTimer.Stop()

  ProcessAsyncCallResult()

End Sub


Private Sub ProcessAsyncCallResult()

  _IsDirty = _Item.Content._IsDirty

End Sub




''# CustomerDetailUI code

Public Sub CheckForIsDirty(ByVal myAutoResetEvent As AutoResetEvent)

  _AutoResetEvent = myAutoResetEvent

  _BfrServ.Customer_IsDirtyAsync(_Customer) ''# This method initiates asynchroneous call to the web service - all the details are not shown here 

  _AutoResetEvent.WaitOne()

End Sub


Private Sub _BfrServ_Customer_IsDirtyCompleted(ByVal sender As Object, ByVal e As BFRService.Customer_IsDirtyCompletedEventArgs) Handles _BfrServ.Customer_IsDirtyCompleted

  If _IsDirtyFromRefesh Then

    _IsDirtyFromRefesh = False

    If e.Result = True Then

      Me.Confirm("This customer has been modified. Are you sure you want to refresh your data ? " & vbNewLine & " Your changes will be lost.", "Yes", "No", Message.CheckIsDirtyRefresh)

    End If

    Busy.IsBusy = False

  Else

    If e.Result = True Then

      _IsDirty = True

      Me.Confirm("This customer has been modified. Would you like to save?", "Yes", "No", Message.CheckIsDirty)

    Else

      Me.Tab.Items.Remove(Me.Tab.SelectedItem)

      Busy.IsBusy = False

    End If

  End If

  _IsDirtyCompleted = True

  _AutoResetEvent.Set()

End Sub

1 个答案:

答案 0 :(得分:0)

您的问题是DispatchTimer正在尝试在您使用Wait阻止的同一线程上执行代码。因此它无法提供滴答声。

我不确定我是否清楚为什么你需要计时器。为什么不直接在OnBeforeUnload的调用中阻止UI线程(事实上你已经在做)。然后让异步回调函数在分配了值_IsDirty

之后设置等待句柄

点击等待消息框。