Использование диспетчера в сочетании с асинхронным вызовом - PullRequest
2 голосов
/ 11 мая 2010

У нас есть проблема в нашем приложении Silverlight, которое использует WCF и Entity Framework, где нам нужно перехватывать событие всякий раз, когда пользователь закрывает приложение, закрывая веб-страницу или браузер вместо закрытия приложения silverlight. Это делается для того, чтобы проверить, были ли внесены какие-либо изменения, и в этом случае мы спросим пользователя, хочет ли он сохранить, прежде чем уйти.

Мы смогли выполнить часть, заключающуюся в захвате закрытия веб-страницы: мы написали некоторый код в объекте приложения, в котором веб-страница вызывает метод в объекте приложения silverlight. Проблема начинается, когда в этом методе мы выполняем асинхронный вызов веб-службы, чтобы проверить, произошли ли изменения (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 голосов
/ 11 мая 2010

Ваша проблема в том, что DispatchTimer пытается выполнить код в том же потоке, который вы блокируете с помощью Wait. Следовательно, он не может поставить галочку.

Я не уверен, что понимаю, зачем тебе вообще нужен таймер. Почему бы просто не заблокировать поток пользовательского интерфейса (как на самом деле вы уже делаете) непосредственно при вызове OnBeforeUnload. Затем с помощью функции асинхронного обратного вызова установите дескриптор ожидания после присвоения ему значения _IsDirty.

.

Следуйте за ожиданиями с вашими сообщениями.

...