2010-05-11 5 views
2

Nous avons un problème dans notre application Silverlight qui utilise WCF et Entity Framework, où nous devons piéger l'événement lorsqu'un utilisateur ferme l'application en fermant la page Web ou le navigateur au lieu de la fermeture de l'application Silverlight. C'est afin de vérifier si des changements ont été faits, auquel cas nous demandons à l'utilisateur s'il veut enregistrer avant de partir.Utilisation de dispatchertimer en combinaison avec un appel asynchrone

Nous avons été en mesure d'accomplir la partie qui consiste à piéger la fermeture de la page web: nous avons écrit du code dans l'objet application dont la page web appelle une méthode dans l'objet application silverlight. Le problème commence lorsque dans cette méthode, nous effectuons un appel asynchrone au service Web pour vérifier si des modifications ont eu lieu (IsDirty). Nous utilisons un DispatcherTimer pour vérifier le retour de l'appel asynchrone. Le problème est que l'appel asynchrone ne se termine jamais (en mode de débogage, il ne finit jamais dans la méthode _BfrServ_Customer_IsDirtyCompleted), alors qu'il fonctionnait correctement avant d'ajouter cette nouvelle fonctionnalité.

Vous trouverez ci-dessous le code que nous utilisons.

Je suis nouveau à l'écriture de minuteries en combinaison avec un appel asynchrone, donc je peux faire quelque chose de mal, mais je ne peux pas comprendre quoi. J'ai essayé d'autres choses aussi, mais nous avons sans succès ..

====================== CODE =========== ===================================

''# 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 
+0

Bienvenue dans SO, veuillez prendre quelques minutes pour lire la FAQ et la documentation Markdown (un synoptique utile est disponible dans la marge de droite lors de la modification d'une question). – AnthonyWJones

Répondre

0

Votre problème est que le DispatchTimer tente pour exécuter du code sur le même thread que vous bloquez avec le Wait. Par conséquent, il ne peut pas livrer la tique.

Je ne suis pas sûr d'avoir compris pourquoi vous avez besoin du minuteur. Pourquoi ne pas simplement bloquer le thread UI (comme vous le faites déjà) directement dans l'appel à OnBeforeUnload. Ensuite, demandez à la fonction de rappel asynchrone de définir le gestionnaire d'attente après avoir affecté la valeur _IsDirty.

Suivez les zones d'attente avec vos messages.

Questions connexes