2

WCF と Entity Framework を使用する Silverlight アプリケーションに問題があり、ユーザーが Silverlight アプリケーションを閉じる代わりに Web ページまたはブラウザーを閉じてアプリケーションをシャットダウンするたびに、イベントをトラップする必要があります。これは、変更が行われたかどうかを確認するためです。変更があった場合は、ユーザーが終了する前に保存するかどうかを尋ねます。

Web ページのクローズをトラップするという部分を達成することができました。Web ページが 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
4

1 に答える 1

0

あなたの問題は、 DispatchTimer が Wait でブロックしている同じスレッドでコードを実行しようとしていることです。したがって、ティックを配信できません。

なぜタイマーが必要なのか、はっきりとはわかりません。への呼び出しで UI スレッドを直接ブロックしないのはなぜですか (実際には既に行っているように) OnBeforeUnload。次に、 の値を割り当てた後、非同期コールバック関数に待機ハンドルを設定させます_IsDirty

メッセージ ボックスで待機に従います。

于 2010-05-11T15:45:27.090 に答える