質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

.NET Framework

.NET Framework は、Microsoft Windowsのオペレーティングシステムのために開発されたソフトウェア開発環境/実行環境です。多くのプログラミング言語をサポートしています。

Q&A

解決済

2回答

5689閲覧

C#でメイン処理途中でユーザからの入力画面に切り替えてまたメインの処理に戻る方法はありますか?

toshi0607

総合スコア56

C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

.NET Framework

.NET Framework は、Microsoft Windowsのオペレーティングシステムのために開発されたソフトウェア開発環境/実行環境です。多くのプログラミング言語をサポートしています。

0グッド

0クリップ

投稿2016/06/27 13:17

編集2016/06/27 14:37

概要

  • WebBrowserクラスを使用したスクレイピング中、特定の要素を見つけたときユーザ向けの画面を切り替えてパスワードを入力させます。
  • 入力後画面切り替え直後の処理を実行したいです。
  • 現状処理を続行させることができず、ユーザが情報入力後画面切り替え直後の処理と全く同じ処理を変えた別メソッドを呼んでいます。
  • これをユーザの入力後、処理を再開できるように修正したいのですが方法が見つかりません。

ソースコード

csharp

1// main.cs 2public void Click_DownloadFiles(object sender, RoutedEventArgs) e 3{ 4 // ユーザ向かいには「処理中」のような画面が出ている状態です。 5 A(); 6 7 // WebBrowserクラスを使用したスクレイピング処理中で、 8 // 特定の要素(パスワード入力画面入力フォームなどを見つけるとユーザに画面を返します。) 9 if (elementExist()) 10 { 11 url = string.Format("views/Pages/PasswordInput.xaml") 12 Frame.MainFrame.Navigate(new URI(url, UriKind.Relative)); 13 return; 14 } 15 // 入力後ここから処理を再開したい… 16 B(); 17} 18 19 20public void Click_DownloadFilesAfterInput(object sender, RoutedEventArgs) e 21{ 22 // 現状は入力が終わったら押すボタンを分けて別メソッドに元の処理の続きをコピーしている 23 B(); 24} 25

c#

1// PasswordInput.xaml.cs 2private void PasswordBoxChanged(object sender, RoutedEventArgs e) 3{ 4 if (this.DataContext != null) 5 { 6 // ユーザの入力を保持 7 ((dynamic)this.DataContext).Password = ((PasswordBox)sender).SecurePassword; 8 } 9} 10 11private void Click_DownloadFilesAfterInput(object sender, RoutedEventArgs e) 12{ 13 if (this.DataContext != null) 14 { 15 // メイン処理のクラスに戻る 16 ((dynamic)this.DataContext).Click_DownloadFilesAfterInput(sender, e); 17 Button_DownloadFiles.IsEnabled = false; 18 } 19} 20 21

試したこと

  • returnを使ったらメインの処理から抜けてしまうので使ったら無理そうです。
  • goto文を使う

csharp

1// main.cs 2public void Click_DownloadFiles(object sender, RoutedEventArgs) e 3{ 4 if (State == "PW" ) goto pw; 5 A(); 6 7 // WebBrowserクラスを使用したスクレイピング処理中で、 8 // 特定の要素(パスワード入力画面入力フォームなどを見つけるとユーザに画面を返します。) 9 if (elementExist()) 10 { 11 url = string.Format("views/Pages/PasswordInput.xaml") 12 Frame.MainFrame.Navigate(new URI(url, UriKind.Relative)); 13 return; 14 } 15 // 入力後ここから処理を再開したい… 16 pw; 17 B(); 18} 19

c#

1// PasswordInput.xaml.cs 2private void PasswordBoxChanged(object sender, RoutedEventArgs e) 3{ 4 if (this.DataContext != null) 5 { 6 ((dynamic)this.DataContext).Password = ((PasswordBox)sender).SecurePassword; 7 } 8} 9 10private void Click_DownloadFilesAfterInput(object sender, RoutedEventArgs e) 11{ 12 if (this.DataContext != null) 13 { 14 ((dynamic)this.DataContext).State = "PW"; 15 ((dynamic)this.DataContext).Click_DownloadFilesAfterInput(sender, e); 16 Button_DownloadFiles.IsEnabled = false; 17 } 18} 19 20

※ 処理は続行できるようになるものの、メインの処理でもともと定義していた変数参照できなくなる…

動作環境

  • WPFアプリケーション
  • .NET Frame Work 4.5
  • Visual Studio2013

という状態です。よろしくお願いします。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

Tak1wa

2016/06/27 14:04

プラットフォームはなんですか?Frame.MainFrame.Navigateを使用しているのでWPFかUWPでしょうか。
toshi0607

2016/06/27 14:38

はい、WPFです!動作環境追記させていただきました。
guest

回答2

0

ベストアンサー

こういう実装はasync/awitを使うと簡単に実現できます。

C#

1public async void Click_DownloadFiles(object sender, RoutedEventArgs) e 2{ 3 // ユーザ向かいには「処理中」のような画面が出ている状態です。 4 A(); 5 6 // WebBrowserクラスを使用したスクレイピング処理中で、 7 // 特定の要素(パスワード入力画面入力フォームなどを見つけるとユーザに画面を返します。) 8 await Task.Run(new Action(()=>{ 9 if (elementExist()) 10 { 11 invoke(new Action(()=>{ 12 url = string.Format("views/Pages/PasswordInput.xaml") 13 Frame.MainFrame.Navigate(new URI(url, UriKind.Relative)); 14 })); 15 } 16 })); 17 // 入力後ここから処理を再開したい… 18 B(); 19}

試していないので上記コードで文法ミスや冗長な部分などがあるかもしれませんが,上記のような感じで実現できると思います。awaitで,非同期処理内で実行される処理が終わるまで待つという処理ができます。

投稿2016/06/28 02:28

退会済みユーザー

退会済みユーザー

総合スコア0

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

catsforepaw

2016/06/28 02:50

私も一瞬async/awaitを思い浮かべましたが、`Navigate`メソッドはページを展開するだけで入力待ちはしてくれませんし、そもそも非同期なので即座に戻ってきてスレッドが終了し、入力のないまま`B()`が実行されてしまうと思うのですが。
退会済みユーザー

退会済みユーザー

2016/06/28 14:47 編集

awaitはelementExist()がtrueの時入力待ちコード入れれば実行待機になりますね。 ただ,確かにnavigateの仕様は知らないので入力待ちにならないのならそのまますり抜けるのでDialogなどをつかわないとダメですね。 個人的にUIスレッドでボタンロジックを走らせるのが嫌いなので非同期で提案してみました。
toshi0607

2016/06/29 08:10

ありがとうございます! メインの処理が書いてあるメソッドはコードビハインドから呼び出した別クラスの処理なので、画面の切り替え自体は Frame.MainFrame.Dispatcher.Invoke(new Action(() =>...のように書くと tkow のおっしゃる通りできました! そしてcatsforepawさんの指摘くださった点はinvoke直後に待ち処理(this.State != "OTP"のときWaitする)を入れて回避できました。 ただ、PasswordInput.xaml.cs内のClick_DownloadFilesAfterInputの処理で ((dynamic)this.DataContext).Password = ((PasswordBox)sender).SecurePassword をしても呼び出し元のプロパティを非同期的に呼び出したフォームの入力値で書き換えられませんでした。 呼び出し元のDataContextにアクセスする方法ってあるのでしょうか...?
退会済みユーザー

退会済みユーザー

2016/06/30 00:57 編集

フォームをインスタンス化するかwpfなのでUIスレッドにinvokeしてデータバインディング経由で変更するかでも実現出来ると思いますがtaskで戻り値をメインスレッドで受け取れる http://blog.okazuki.jp/entry/20120528/1338214435 のでvar result = await Task〈string〉.Run としてメインスレッド側に暗号化したパスワードをを渡すのが一番簡単ではないでしょうか。
guest

0

どのような画面遷移にしたいのかにもよりますが、パスワード入力を別ウィンドウで行わせることが許容できるなら、モーダルダイアログとして実行すれば同じメソッド内で順番に処理することができ、処理が簡素化できます。

コード例

C#

1// main.cs 2public void Click_DownloadFiles(object sender, RoutedEventArgs) e 3{ 4 // ユーザ向かいには「処理中」のような画面が出ている状態です。 5 A(); 6 7 // WebBrowserクラスを使用したスクレイピング処理中で、 8 // 特定の要素(パスワード入力画面入力フォームなどを見つけるとユーザに画面を返します。) 9 if (elementExist()) 10 { 11 // パスワード入力ダイアログを実行 12 var dialog = new PasswordInputDialog(); 13 var res = dialog.ShowDialog(); // OKボタンでtrue、キャンセルボタンでfalseを返すと想定 14 if(res) 15 { 16 // OK処置 17 // returnせずに処理を継続 18 } 19 else 20 { 21 // キャンセル処理 22 return; 23 } 24 } 25 26 // 入力後ここから処理を再開したい… 27 B(); 28}

投稿2016/06/28 00:52

編集2016/06/28 00:54
catsforepaw

総合スコア5938

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問