C# と VB.NET の質問掲示板

ASP.NET、C++/CLI、Java 何でもどうぞ

C# と VB.NET の入門サイト

非同期処理を同期処理にする方法

[トピック内 8 記事 (1 - 8 表示)]  << 0 >>

■100404 / inTopicNo.1)  非同期処理を同期処理にする方法
  
□投稿者/ furu (175回)-(2022/07/27(Wed) 21:20:23)

分類:[C#] 

VS2022 C#
.NET Framework 4.8
WindowsForm

非同期で動作する処理(具体的にはWebView2)を
簡単に同期処理にする方法はありますでしょうか?

Application.DoEventsを使う方法はわかっています。

    void webView21_NavigationCompleted(…) {isCompleted = true;}
    void 同期処理(…)
    {
        isCompleted = false;
        webView21.CoreWebView2.Navigate("…");
        do Application.DoEvents(); while (!isCompleted);
        MessageBox.Show("完了");
    }

以下の非同期処理のasyncを無くしたいです。

    void webView21_NavigationCompleted(…) {condition.Signal();}
    async void 非同期処理(…)
    {
        webView21.CoreWebView2.Navigate("…");
        await Task.Run(() => {condition.Wait();});
        MessageBox.Show("完了");
    }

同期処理にしたいのはライブラリとして提供するのに
同期メソッドにしたいからです。

引用返信 編集キー/
■100405 / inTopicNo.2)  Re[1]: 非同期処理を同期処理にする方法
□投稿者/ くま (220回)-(2022/07/27(Wed) 23:15:01)
> 非同期で動作する処理(具体的にはWebView2)を
> 簡単に同期処理にする方法はありますでしょうか?
簡単にはないよ。

私もライブラリ化してExcelとかで使ってるけど
結局System.Threading.CountdownEvent使って
非同期完了するまで待機する方法をとってます。

キチンと処理してあげないと相手側が同期処理しかない場合
変なエラーになるから注意してね。
引用返信 編集キー/
■100406 / inTopicNo.3)  Re[1]: 非同期処理を同期処理にする方法
□投稿者/ KOZ (305回)-(2022/07/28(Thu) 00:20:01)
2022/07/28(Thu) 00:43:38 編集(投稿者)

No100404 (furu さん) に返信
> 非同期で動作する処理(具体的にはWebView2)を
> 簡単に同期処理にする方法はありますでしょうか?

UIスレッドから呼び出した場合、待機してしまうとメッセージループを止めることになります。
ということは、なんらかの形でメッセージループを回す必要があります。

Application.DoEvents は、その方法のうちのひとつですが、別の方法を取ったとしても結局は同じような処理になります。

WebView2 側を、独立した UIスレッドで動かせば、同期メソッドとして実現できますが、その場合は複雑な処理になってしまうでしょうね。
引用返信 編集キー/
■100408 / inTopicNo.4)  Re[2]: 非同期処理を同期処理にする方法
□投稿者/ furu (176回)-(2022/07/28(Thu) 09:34:12)
くまさん、KOZさん
回答ありがとうございます。

Application.DoEventsを行うようにします。

No100405 (くま さん) に返信
> 簡単にはないよ。
ないということがわかっただけでありがたいです。

No100406 (KOZ さん) に返信
> なんらかの形でメッセージループを回す必要があります。
そうなんですよね。
メッセージループを止めないWaitがあったらと
期待してました。
解決済み
引用返信 編集キー/
■100409 / inTopicNo.5)  Re[1]: 非同期処理を同期処理にする方法
□投稿者/ 魔界の仮面弁士 (3442回)-(2022/07/28(Thu) 10:14:56)
No100404 (furu さん) に返信
> Application.DoEventsを使う方法はわかっています。
メッセージループは Application.Run や Application.DoEvents の他、
モーダルダイアログによっても回りますね。使いやすいかというと微妙ですが…。

using(var dlg = new Form()) // [処理中]画面をモーダル表示することで待機させる
{
  dlg.Opacity = 0; // [処理中]画面を隠す
  var navigationCompleted = default(EventHandler<Microsoft.Web.WebView2.Core.CoreWebView2NavigationCompletedEventArgs>);
  navigationCompleted = (sender, e) =>
  {
    webView21.NavigationCompleted -= navigationCompleted;
    dlg.Close(); // 処理が完了したのでモーダル画面を閉じる
  };
  webView21.NavigationCompleted += navigationCompleted;
  dlg.Shown += delegate { webView21.Source = new Uri(url); };
  dlg.ShowDialog(this); // 内部で Application.RunDialog が呼ばれて待機される
}
return;
解決済み
引用返信 編集キー/
■100410 / inTopicNo.6)  Re[3]: 非同期処理を同期処理にする方法
□投稿者/ くま (221回)-(2022/07/28(Thu) 11:12:35)
一部抜粋だけどこんな感じ
   ※FmWebView2 はWebView2コントロール1つ張り付いているフォーム
   Friend Shadows _Fm As FmWebView2
   ※FmWebView2の各イベントで(Load、FormClosed)でシグナル設定
   Friend ReadOnly _opened As New System.Threading.CountdownEvent(1)    '状態
    ''' <summary>
    ''' WebView2を開きます。
    ''' </summary>
    Public Sub OpenWebView2() Implements IWebView2.OpenWebView2

        Dim result As Task(Of Integer) = OpenWebView2Async()

        '----- 非同期実行の完了まで待機
        Do Until result.Status = TaskStatus.RanToCompletion
            Application.DoEvents()
            System.Threading.Thread.Sleep(10)
        Loop

    End Sub
    ''' <summary>
    ''' WebView2を開きます。(非同期)
    ''' </summary>
    Private Async Function OpenWebView2Async() As Task(Of Integer)
        Try
            If Me._Fm IsNot Nothing Then
                Me._Fm.Close()
                Do Until Me._Fm Is Nothing
                    Application.DoEvents()
                    System.Threading.Thread.Sleep(10)
                Loop
            End If

            '----- シグナル初期化
            System.Threading.Thread.Sleep(1)
            Me._opened.Reset()

            Me._Fm = New FmWebView2
            Me._Fm.Show(Me)

            '----- フォーム設定完了まで待機
            Dim _openedTime As Integer = Await Task.Run(
                Function() As Integer
                    Dim millsec As Integer = 0
                    Do Until Me._opened.Wait(10)
                        millsec += 10
                        If millsec > 30000 Then '30秒 
                            millsec = -1
                            Exit Do
                        End If
                    Loop
                    Return millsec
                End Function
            )

            '----- シグナル初期化
            System.Threading.Thread.Sleep(1)
            Me._opened.Reset()

            Return _openedTime

        Catch ex As Exception
            'StartUp.ExceptionHandling(ex)
            Return -1
        End Try

    End Function

全部は載せられないのとあってるかな?
あとページ移動とかJS実行とかで同じような事しています。
とりあえず今のところ半年以上毎日使っているけど問題はないね。

解決済み
引用返信 編集キー/
■100414 / inTopicNo.7)  Re[2]: 非同期処理を同期処理にする方法
□投稿者/ furu (177回)-(2022/07/29(Fri) 08:42:35)
No100409 (魔界の仮面弁士 さん) に返信
>   dlg.ShowDialog(this); // 内部で Application.RunDialog が呼ばれて待機される
そうですね。
ShowDialogだとUIスレッド止めないで同期できますね。
解決済み
引用返信 編集キー/
■100415 / inTopicNo.8)  Re[4]: 非同期処理を同期処理にする方法
□投稿者/ furu (178回)-(2022/07/29(Fri) 08:49:22)
No100410 (くま さん) に返信
> 全部は載せられないのとあってるかな?
> あとページ移動とかJS実行とかで同じような事しています。
> とりあえず今のところ半年以上毎日使っているけど問題はないね。
ありがとうございます。
解決済み
引用返信 編集キー/

このトピックをツリーで一括表示


トピック内ページ移動 / << 0 >>

このトピックに書きこむ