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

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

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

【C#,VS2022,WPF】クリック待ちを実装したい

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

■100455 / inTopicNo.1)  【C#,VS2022,WPF】クリック待ちを実装したい
  
□投稿者/ エルデの王 (7回)-(2022/08/16(Tue) 03:10:20)

分類:[.NET 全般] 

2022/08/16(Tue) 03:18:02 編集(投稿者)


お世話になっております。
掲題の通り、C#のWPFです。

ボタン押下などイベント実行後、
ある程度処理をしたらクリックを行うまで処理を中断(つまり入力待ち)ということがしたいのですが、
方法はあるでしょうか?

※ダイアログ、メッセージウィンドウなどの別ウィンドウを表示することは使用出来ません。
※言い換えれば、FrameのPageをShowDialogで出したい、みたいな感じです。

ご指導ご鞭撻のほどよろしくお願いいたします……
引用返信 編集キー/
■100458 / inTopicNo.2)  Re[1]: 【C#,VS2022,WPF】クリック待ちを実装したい
□投稿者/ ぶなっぷ (289回)-(2022/08/16(Tue) 13:04:26)
たぶん、みなさん、以下の意味が分からないと思われ。
> ※言い換えれば、FrameのPageをShowDialogで出したい、みたいな感じです。

もう少し、分かりやすく解説お願いいたします。

引用返信 編集キー/
■100459 / inTopicNo.3)  Re[1]: 【C#,VS2022,WPF】クリック待ちを実装したい
□投稿者/ KOZ (311回)-(2022/08/16(Tue) 16:00:46)
No100455 (エルデの王 さん) に返信
> ボタン押下などイベント実行後、
> ある程度処理をしたらクリックを行うまで処理を中断(つまり入力待ち)ということがしたいのですが、
> 方法はあるでしょうか?

「C#でシグナル処理」
https://qiita.com/rawr/items/6888778b53fc95c41f00

ここが参考になりそうです。
引用返信 編集キー/
■100460 / inTopicNo.4)  Re[2]: 【C#,VS2022,WPF】クリック待ちを実装したい
□投稿者/ エルデの王 (8回)-(2022/08/16(Tue) 21:54:40)
2022/08/16(Tue) 21:58:31 編集(投稿者)
返信ありがとうございます。

■No100458 (ぶなっぷ さん) に返信
> たぶん、みなさん、以下の意味が分からないと思われ。
>>※言い換えれば、FrameのPageをShowDialogで出したい、みたいな感じです。
> 
> もう少し、分かりやすく解説お願いいたします。
> 

以下のようなことがしたいのです。
Uri uri = new Uri("/Page010_SortieMenu.xaml", UriKind.Relative);
using (Frame dlg = new Frame(uri))
{
    if (dlg.ShowDialog() == DialogResult.OK)
    {
        //OKがクリックされた場合
        MessageBox.Show("aaa");
    } else
    {
        //キャンセルがクリックされた場合
        MessageBox.Show("キャンセルされました。");
    }
}


URLでの情報提供ありがとうございます。

例を参考に記述したところ、画面は停止するものの、
クリックを促す画面が表示されず、またクリックそのものも出来ない状態となりました……

以下にコードを記しますので、何か不足の点がありましたら、お教えください。

        private readonly CountdownEvent condition = new CountdownEvent(1);
        private void Button_click(object sender, EventArgs e)
        {
        DoWork()
                //停止してここから先進まない
                MessageBox.Show("aaa");
        }
        private async void DoWork()
        {

            Uri uri = new Uri("/Page010_SortieMenu.xaml", UriKind.Relative);
      //以下が画面に表示されず
            await Task.Run(() =>
            {
                Application.Current.Dispatcher.Invoke((Action)(() =>
                {
                    Frame frame = new Frame();
                    frame.Source = uri;
                    frame.Margin = new Thickness(0, 0, 0, 0);
                    this.canvasMain.Children.Add(frame);
                }));
            });
      //アプリケーション全体が止まり、マウスを動かすことは出来るが、クリック出来ない
            condition.Wait();
        }

        private void Button_RightKeyDown(object sender, EventArgs e)
        {
      //wait後、クリック出来ないので意味がない
            condition.Signal();
            Thread.Sleep(1);
            condition.Reset();
        }

引用返信 編集キー/
■100461 / inTopicNo.5)  Re[3]: 【C#,VS2022,WPF】クリック待ちを実装したい
□投稿者/ Azulean (1250回)-(2022/08/16(Tue) 23:18:55)
No100460 (エルデの王 さん) に返信
> クリックを促す画面が表示されず、またクリックそのものも出来ない状態となりました……

プログラムは、書いた通りにしか動かないものです。
コードを理解せずに適当に切り貼りしたら動かないのはそういうものです。


>         private async void DoWork()
>         {
> 
>             Uri uri = new Uri("/Page010_SortieMenu.xaml", UriKind.Relative);
>       //以下が画面に表示されず
>             await Task.Run(() =>
>             {
>                 Application.Current.Dispatcher.Invoke((Action)(() =>
>                 {
>                     Frame frame = new Frame();
>                     frame.Source = uri;
>                     frame.Margin = new Thickness(0, 0, 0, 0);
>                     this.canvasMain.Children.Add(frame);
>                 }));
>             });
>       //アプリケーション全体が止まり、マウスを動かすことは出来るが、クリック出来ない
>             condition.Wait();
>         }


async キーワード内の await で処理再開した後(つまり元のスレッド=メインスレッド)で Wait したら固まるのはそうでしょう。
今回のケースで Wait を書けて良いのは、別スレッド(Task 内)でしょうから。

思うのですが、この内容なら別に DoWork とか await とかせず、Button_RightKeyDown の中に続きを書いたらよいのでは?
経験が浅いと、1シーケンス(1つの関数の中でユーザー操作イベントを待つ)で作るしかない、そう作るのが楽だと思い込みがちですが、実際にはそう書く方が難しいので。

引用返信 編集キー/
■100462 / inTopicNo.6)  Re[4]: 【C#,VS2022,WPF】クリック待ちを実装したい
□投稿者/ エルデの王 (9回)-(2022/08/17(Wed) 02:23:25)
返信ありがとうございます。

> async キーワード内の await で処理再開した後(つまり元のスレッド=メインスレッド)で Wait したら固まるのはそうでしょう。
> 今回のケースで Wait を書けて良いのは、別スレッド(Task 内)でしょうから。

つまり、メインスレッドでクリック待ちをすることは、
ダイアログボックスを用いることでしか出来ないということでしょうか?

> 思うのですが、この内容なら別に DoWork とか await とかせず、Button_RightKeyDown の中に続きを書いたらよいのでは?
> 経験が浅いと、1シーケンス(1つの関数の中でユーザー操作イベントを待つ)で作るしかない、そう作るのが楽だと思い込みがちですが、実際にはそう書く方が難しいので。

提示したコードは使用感を確かめる為に記述したもので、
実際にはゲームエンジンに内包されるコンパイラを実装する為にコードを書きます。
よろしくお願いいたします。
引用返信 編集キー/
■100463 / inTopicNo.7)  Re[5]: 【C#,VS2022,WPF】クリック待ちを実装したい
□投稿者/ Azulean (1251回)-(2022/08/17(Wed) 07:30:07)
No100462 (エルデの王 さん) に返信
> つまり、メインスレッドでクリック待ちをすることは、
> ダイアログボックスを用いることでしか出来ないということでしょうか?

基本的に、次の操作を受け付けるためには「メッセージループを回さないといけない」が Windows プログラミングの根底にあります。
Windows Forms や WPF ではそのメッセージループを自分で書けないので、イベントハンドラの中でループし続けるようなことは避けなければなりません。


ただし、async/await キーワードは擬似的に実現はできるでしょうね。
別スレッド(Task)が終わってから再開するというコードが書けるため。
ただし、右クリック以外のイベントも発生しますので、先にも書いたとおり、右クリックイベントに直接書いたら良いのでは?としました。


> 提示したコードは使用感を確かめる為に記述したもので、
> 実際にはゲームエンジンに内包されるコンパイラを実装する為にコードを書きます。

都合良く、特定のイベントだけを待ち受けることはできませんので、仕様、あるいは設計から見直しましょう。
引用返信 編集キー/
■100464 / inTopicNo.8)  Re[6]: 【C#,VS2022,WPF】クリック待ちを実装したい
□投稿者/ kiku (287回)-(2022/08/17(Wed) 09:45:30)
2022/08/17(Wed) 10:02:22 編集(投稿者)
No100463 (Azulean さん) に返信
> ■No100462 (エルデの王 さん) に返信
>>つまり、メインスレッドでクリック待ちをすることは、
>>ダイアログボックスを用いることでしか出来ないということでしょうか?

Azuleanさんと同意見ですが、
下記で実現できませんか? ==> エルデの王さん
※検証していません。
※メインスレッドを停止させずに待つ方法がawaitなので

        private readonly CountdownEvent condition = new CountdownEvent(1);
        private void Button_click(object sender, EventArgs e)
        {
        DoWork()
                MessageBox.Show("aaa");
        }
        private async void DoWork()
        {

            Uri uri = new Uri("/Page010_SortieMenu.xaml", UriKind.Relative);
      //以下が画面に表示されず
            await Task.Run(() =>
            {
                Application.Current.Dispatcher.Invoke((Action)(() =>
                {
                    Frame frame = new Frame();
                    frame.Source = uri;
                    frame.Margin = new Thickness(0, 0, 0, 0);
                    this.canvasMain.Children.Add(frame);
                }));
            });
            await Task.Run(() =>
            {
                condition.Wait();
            });
        }

        private void Button_RightKeyDown(object sender, EventArgs e)
        {
            condition.Signal();
            Thread.Sleep(1);
            condition.Reset();
        }

引用返信 編集キー/
■100465 / inTopicNo.9)  Re[7]: 【C#,VS2022,WPF】クリック待ちを実装したい
□投稿者/ Azulean (1252回)-(2022/08/17(Wed) 10:44:09)
野暮ですが…。

No100464 (kiku さん) に返信
> await Task.Run(() =>
> {
> condition.Wait();
> });

No100461 に「今回のケースで Wait を書けて良いのは、別スレッド(Task 内)でしょうから」と書きましたとおり、
Dispatcher.Invoke である以上、メインスレッドの処理が終わるのを待つわけ(同期的実行)ですから、
Dispatcher.Invoke の直後にそのまま書けば良く、Task.Run を2つに分ける必要はない認識です。
引用返信 編集キー/
■100466 / inTopicNo.10)  Re[8]: 【C#,VS2022,WPF】クリック待ちを実装したい
□投稿者/ kiku (288回)-(2022/08/17(Wed) 11:00:55)
No100465 (Azulean さん) に返信
> 野暮ですが…。
>
> ■No100464 (kiku さん) に返信
>>await Task.Run(() =>
>>{
>> condition.Wait();
>>});
>
> No100461 に「今回のケースで Wait を書けて良いのは、別スレッド(Task 内)でしょうから」と書きましたとおり、
> Dispatcher.Invoke である以上、メインスレッドの処理が終わるのを待つわけ(同期的実行)ですから、
> Dispatcher.Invoke の直後にそのまま書けば良く、Task.Run を2つに分ける必要はない認識です。

同じ考えです。
あえて分けて書いた方が、質問者さんにわかりやすいかなと思ったしだいです。
自分も実際のコードでしたら、Invoke の直後に書くと思います。
引用返信 編集キー/
■100469 / inTopicNo.11)  Re[9]: 【C#,VS2022,WPF】クリック待ちを実装したい
□投稿者/ ぶなっぷ (290回)-(2022/08/17(Wed) 14:42:26)
非同期にすべきは、バックグラウンドで行われる処理なのでは?

WPFの仕様上、GUIはメインスレッドで行わないといけません。
なので、こんな感じでどうでしょう?

private void Button_click(object sender, EventArgs e)
{
    Uri uri = new Uri("/Page010_SortieMenu.xaml", UriKind.Relative);
    Frame frame = new Frame();
    frame.Source = uri;
    frame.Margin = new Thickness(0, 0, 0, 0);
    this.canvasMain.Children.Add(frame);
    frame.ContentRendered += MainWindow_ContentRendered;
    frame.OKButton.Click += OKButton_Click;
}

private async void MainWindow_ContentRendered(object sender, EventArgs e)
{
    await Task.Run(() =>
    {
        foreach(なんかループ)
        {
            // 非同期に行いたい処理

            // フラグが立っていたら、frameを閉じてbreak;
        }
    });
}

private void OKButton_Click(object sender, RoutedEventArgs e)
{
    // フラグを立てる
}

引用返信 編集キー/
■100477 / inTopicNo.12)  Re[7]: 【C#,VS2022,WPF】クリック待ちを実装したい
□投稿者/ エルデの王 (10回)-(2022/08/17(Wed) 17:41:39)
No100464 (kiku さん) に返信
> 2022/08/17(Wed) 10:02:22 編集(投稿者)
>
> ■No100463 (Azulean さん) に返信
>>■No100462 (エルデの王 さん) に返信
> >>つまり、メインスレッドでクリック待ちをすることは、
> >>ダイアログボックスを用いることでしか出来ないということでしょうか?
>
> Azuleanさんと同意見ですが、
> 下記で実現できませんか? ==> エルデの王さん

遅くなりました。すみません。
残念ですが検証した結果、待機状態になりませんでした。
案を頂きありがとうございます。
引用返信 編集キー/
■100479 / inTopicNo.13)  Re[10]: 【C#,VS2022,WPF】クリック待ちを実装したい
□投稿者/ エルデの王 (11回)-(2022/08/17(Wed) 17:53:05)
No100469 (ぶなっぷ さん) に返信
> 非同期にすべきは、バックグラウンドで行われる処理なのでは?
> 
> WPFの仕様上、GUIはメインスレッドで行わないといけません。
> なので、こんな感じでどうでしょう?

残念ですが、独自プログラミング言語を上から順番に実行していくものが作りたいので、、、

まあつまり、
event worldevent001
<-
	message("てst");
    if(true){
        	message("てstてst");
        }
	message("てstてstてst");
->
こういうコードがあるのですが、これを元に木構造を作り、
ユーザーがクリックして進めるものにしたかったのです。

案を頂きありがとうございます。

解決済み
引用返信 編集キー/
■100480 / inTopicNo.14)  Re[9]: 【C#,VS2022,WPF】クリック待ちを実装したい
□投稿者/ KOZ (313回)-(2022/08/17(Wed) 18:04:29)
2022/08/17(Wed) 18:04:56 編集(投稿者)
No100466 (kiku さん) に返信
> 同じ考えです。
> あえて分けて書いた方が、質問者さんにわかりやすいかなと思ったしだいです。
> 自分も実際のコードでしたら、Invoke の直後に書くと思います。

待つところが違うような・・・

private async void DoWork() {
    Uri uri = new Uri("/Page010_SortieMenu.xaml", UriKind.Relative);
    await Task.Run(() =>
    {
        condition.Reset();
        condition.Wait();    // ここで待つのでは?
        Application.Current.Dispatcher.Invoke((Action)(() =>
        {
            Frame frame = new Frame();
            frame.Source = uri;
            frame.Margin = new Thickness(0, 0, 0, 0);
            this.canvasMain.Children.Add(frame);
        }));
    });
}

解決済み
引用返信 編集キー/
■100481 / inTopicNo.15)  Re[8]: 【C#,VS2022,WPF】クリック待ちを実装したい
□投稿者/ Azulean (1253回)-(2022/08/17(Wed) 18:13:10)
2022/08/17(Wed) 18:13:22 編集(投稿者)
No100477 (エルデの王 さん) に返信
> 遅くなりました。すみません。
> 残念ですが検証した結果、待機状態になりませんでした。
> 案を頂きありがとうございます。


ああ、見逃していた。
DoWork 呼び出し元に Task 返していない& DoWork 呼び出し箇所で await してないので、待つことなく実行されますね。

private async void Button_click(object sender, EventArgs e)
{
  await DoWork()
  MessageBox.Show("aaa");
}
private async Task DoWork()
{
// 以下略


いずれにせよ、インタープリタを作っているなら、await(Task) を根っこまで返すのが面倒くさいような気がするので、難しいかもしれませんが。

解決済み
引用返信 編集キー/
■100482 / inTopicNo.16)  Re[9]: 【C#,VS2022,WPF】クリック待ちを実装したい
□投稿者/ エルデの王 (12回)-(2022/08/18(Thu) 04:47:31)

>
> ああ、見逃していた。
> DoWork 呼び出し元に Task 返していない& DoWork 呼び出し箇所で await してないので、待つことなく実行されますね。
>

ありがとうございます!望み通りの動きが出来ました!
解決済み
引用返信 編集キー/

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


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

このトピックに書きこむ