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

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

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

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

Q&A

解決済

2回答

3438閲覧

c# async、awaitを使わずにコードを書く方法

bybalsender

総合スコア33

C#

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

0グッド

0クリップ

投稿2016/09/25 03:46

編集2016/09/25 03:47

初心者的なことで申し訳ありません。
bybalsenderともうします。

先日async、awaitを使用したコードをもらいましたが、環境がvs2005のため動作しません、そこでasync、awaitを利用しない方法を教えてください。

取得したいのは翻訳結果です。
どのような方法でも構いません。

以下のコードでasync、awaitを削除したいです。

const string ur = "http://honyaku.yahoo.co.jp/transtext/";
List<string> _ant = new List<string>();
private void Form1_Shown(object sender, EventArgs e)
{
webBrowser1.ScriptErrorsSuppressed = true;
webBrowser1.Navigate(ur);
_ant.Add("日本語に翻訳");
_ant.Add("英語に翻訳");
_ant.Add("中国語に翻訳");
_ant.Add("ドイツ語に翻訳");
}
async private void webBrowser1_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
{
if (ur == e.Url.ToString())
{
var tasks = new List<Task>();
foreach (string htm in ant)
{
webBrowser1.Document.GetElementById("textText").InnerText = htm;
webBrowser1.Document.GetElementById("btn").InvokeMember("Click");
await Task.Run(() =>
{
Thread.Sleep(1000);
}).ContinueWith(
=> btn_click(),
TaskScheduler.FromCurrentSynchronizationContext());
}
Task.WaitAll(tasks.ToArray());
}
}
private void btn_click()
{
MessageBox.Show(webBrowser1.Document.GetElementById("trn_textText").InnerText);
}

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

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

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

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

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

退会済みユーザー

退会済みユーザー

2016/09/25 04:06

「先日async、awaitを使用したコードをもらいましたが」というのはどこでもらったのか、他のスレッドとかでしたらその URL を示せませんか?
guest

回答2

0

根本的な疑問なのですが、vs2005のような古いバージョンを使い続ける理由はなんでしょうか?
今はvs2015 community(基本無料 企業でも条件付きで使用可能)もありますし、
それを検討してみるのはいかがでしょうか?

投稿2016/09/26 01:32

ishi9

総合スコア1294

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

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

bybalsender

2016/10/07 23:06

返信が遅れてすいません。 >vs2005のような古いバージョンを使い続ける理由はなんでしょうか? 3D-CADに付属しているVisual Studio が2005なものですから、VS2005で対応できればと思っていました。
guest

0

ベストアンサー

何故先のスレッドの回答者の方が 1 秒待って[翻訳]ボタンをクリックするのを非同期で実装したのか真意が分かっていませんが、そんなことをする必要はなさそうな気がします。

前のスレッドの質問者さんのコードで 1 回目の「てすと1」がうまく行ったのは、1 回目だけは WebBrowser.DocumentCompleted イベントの発生(応答が返ってきてドキュメントの読み込みが完了)を待って InvokeMember("Click") メソッドで[翻訳]ボタンをクリックしたから、2 回目以降は 1 回目の応答が返ってこないのに foreach ループで[翻訳]ボタンを高速クリックしたからではないかと思います。

先のスレッドの回答者の方が 1 秒待つという案を出していますが、それは応答が返ってきてドキュメントの読み込みが完了するまで時間がかかるからそれを待つという話だと思います。

でも、それを非同期にやる必要はないと思います。また、1 秒で応答が返ってこない(混んでると 10 秒かかるかもしれない)ということもあるわけで、「1 秒」が適切かは疑問です。

たぶん、WebBrowser.DocumentCompleted ハンドラの中で InvokeMember("Click") メソッドで[翻訳]ボタンをクリックした場合、WebBrowser は再度同じ URL にナビゲートされると共に、id="textText" の原文を送信すると思われます。

その応答が返ってくると再度 WebBrowser.DocumentCompleted イベントが発生するはずです。

なので、WebBrowser.DocumentCompleted イベントハンドラの中で foreach で回すのはやめて、[翻訳]ボタンクリックで「てすと1」を送信 ⇒ その応答が返ってきて DocumentCompleted イベントが発生した時「テスト2」を送信 ⇒ 同様に「test三」「test四」を繰り返す・・・とすればよさそうです。

お試しください。

【サンプルコード追記】

最初のスレッドにあった以下の質問者さんの DocumentCompleted イベントハンドラコードを、

private void webBrowser1_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e) { if (ur == e.Url.ToString()) { foreach (string htm in _ant) { webBrowser1.Document.GetElementById("textText").InnerText = htm; webBrowser1.Document.GetElementById("btn").InvokeMember("Click"); btn_click(); } test(); } }

を以下のようにしてみたらいかがでしょう? 頭の中で考えて書いただけで検証はしてないので、質問者さんの方でデバッガ等を使って期待通りの動きになるか十分検証してください。

int n = 0; private void webBrowser1_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e) { if (ur == e.Url.ToString()) { if (n < _ant.Count) { string htm = _ant[n]; webBrowser1.Document.GetElementById("textText").InnerText = htm; webBrowser1.Document.GetElementById("btn").InvokeMember("Click"); btn_click(); n++; } test(); } }

InvokeMember("Click") のあと、制御がまたこのハンドラに戻ってくるかがキモなのですが、うまく動かなかったらデバッガでそのあたりがどうなっているか調べて連絡ください。

【検証に使ったコードを追記】

検証に使ったコードを以下にアップしておきます。既存のコードを流用したので、手動で http://honyaku.yahoo.co.jp/transtext/ へのナビゲーションを開始するところがちょっと違いますが、基本は質問者さんがコードで示したやりたいことの通りのはずです。

実行結果は以下の画像の通りです。

http://surferonwww.info/BlogEngine/image.axd?picture=2016%2f9%2ftranstext.jpg

一応このサンプルでは期待通りの結果になりましたが、原文に入力している時に原文が何語かの判定を行うためサーバーとのやり取りをしているようで、プログラムで原文をセットして即送信では、場合によってはそのあたりがうまくいかないかもしれません。

対症療法的なことのカタマリのようなもので、Yahoo! は予告無しに html 要素の id、呼び出し先 url、その他いろいろ変えるでしょうから、明日は動かないかもしれません。

というわけで、最初のスレッドで htsign さんが書かれたように、自分もお勧めはできません。脅かすわけではないですが、クローラを作って図書館のサイトにアクセスしたら業務妨害で逮捕されたという例もあるようですし。

using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Windows.Forms; namespace WebBrowser { public partial class Form1 : Form { // 2016/9/26 teratail の検証用 // https://teratail.com/questions/49159 private string url = "http://honyaku.yahoo.co.jp/transtext/"; List<string> _ant = new List<string>() { "日本語に翻訳", "英語に翻訳", "中国語に翻訳", "ドイツ語に翻訳" }; List<string> translated = new List<string>(); int count = 0; public Form1() { InitializeComponent(); textBox1.Text = url; webBrowser1.ScriptErrorsSuppressed = true; } private void navigateButton_Click(object sender, EventArgs e) { webBrowser1.Navigate(textBox1.Text); } private void webBrowser1_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e) { // 初期画面 if (e.Url.ToString() == url) { if (count < _ant.Count) { // 最初の原文をセットして送信 webBrowser1.Document.GetElementById("textText").InnerText = _ant[count]; webBrowser1.Document.GetElementById("btn").InvokeMember("Click"); } } // 翻訳が返ってきたときの処理 if (e.Url.ToString().Contains("http://honyaku.yahoo.co.jp/darla/php/fc.php")) { count++; translated.Add(webBrowser1.Document.GetElementById("trn_textText").InnerText); // 次の原文をセットして送信 if (count < _ant.Count) { webBrowser1.Document.GetElementById("textText").InnerText = _ant[count]; webBrowser1.Document.GetElementById("btn").InvokeMember("Click"); } if (count == _ant.Count) { string result = ""; foreach (string s in translated) { result += s + "\n"; } MessageBox.Show(result); } } } } }

投稿2016/09/25 06:08

編集2016/09/26 03:45
退会済みユーザー

退会済みユーザー

総合スコア0

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

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

bybalsender

2016/09/25 06:24

お返事ありがとうございます。 困ったことに >「てすと1」を送信 ⇒ >応答が返ってきて次のイベントが発生した時 >テスト2」を送信 ⇒ のコードがわかりません。 サンプルを頂けないでしょうか? よろしくお願いします。
退会済みユーザー

退会済みユーザー

2016/09/25 07:02

上の解答欄に追記しておきます。
bybalsender

2016/09/25 07:51

サンプル有難う御座います。 >InvokeMember("Click") のあと、 >制御がまたこのハンドラに戻ってくるかがキモなのですが 帰ってきませんでした。 _ant[n]はインデックスも0で終了しました。 またInvokeMember("Click") のあと 翻訳結果のコード webBrowser1.Document.GetElementById("trn_textText").InnerText; はnullでした。 webBrowser1の翻訳側も空です。 メッセージボックスも空で表示されます。 翻訳してもurlが変更されることがないためwebBrowser1_DocumentCompletedイベントが発動しないのだと思います。 htmlのformですがmethod="post" になっていますが、 actionにファイル名がないのが気になります。cgiを使っていないかもです。 ↓ <form name="textFormEntry" accept-charset="utf-8" method="post" action="/transtext">
退会済みユーザー

退会済みユーザー

2016/09/25 12:33

ダメだと聞いて調べてみました。事前にもう少し調べてから回答すれば良かったですね。すみません。 [翻訳]ボタンクリックで http://honyaku.yahoo.co.jp/TranslationText という URL に原文が POST 送信されます(Fiddler4 で確認)。それを受けたサーバーは、翻訳後のデータを JSON 文字列で返します(これも Fiddler4 で確認)。その時は DocumentCompleted イベントは発生しません(Visual Studio のデバッガで確認)。 JSON 文字列を受け取った後、内部的に http://honyaku.yahoo.co.jp/darla/php/fc.php?tID... という URL を要求します。(これが何なのかは不明) その応答が返ってきた時は DocumentCompleted イベントは発生するのですが、if (ur == e.Url.ToString()) が true にならないのでダメでした。 上の DocumentCompleted イベントが発生した時点では id="trn_textText" の html 要素には翻訳後の文字列が設定済みです。 なので、if (ur == e.Url.ToString()) を if (e.Url.ToString().Contains("http://honyaku.yahoo.co.jp/darla/php/fc.php")) に変更すると翻訳後の文字列を取得できると思われます(自分の環境では取得できることを確認しています)。 ただ、全てのケース・将来的に "http://honyaku.yahoo.co.jp/darla/php/fc.php" で良いとは誰も言ってくれてませんので、多分に対症療法的ではありますが。 前のスレッドの回答者の方の方法で、そのあたりの問題がどうして回避できるのかは分かりません。もう少し調べてみます。
htsign

2016/09/25 13:33

横からすみません。 先の質問に回答させていただいた者です。 私の意図としては極力コードを改変しない方が理解が早いかな、と思ってのことでした。 またご指摘の通り、1秒という待ち時間は多分にサーバーとの通信の安定性に依存したもので、よくないことは承知していました。 WebBrowserクラスのMSHTMLレンダラがUIスレッドとは別に動作するようであればもう少しやりようもあったのかもしれませんが、今一つ上手く動かなかったため非同期に「逃げ」てしまいました。 また、XMLHttpRequestによる通信のC#側からのハンドリングに自信がなかったのもあります。 そのせいでbybalsenderさんにご迷惑をかけたようで、この場を借りてお詫びします。
退会済みユーザー

退会済みユーザー

2016/09/26 03:38

ご参考に、上のコメントを書いた時に検証に使ったコードを回答欄に追加しておきます
bybalsender

2016/09/27 12:51

SurferOnWwwさんへ お返事有難う御座いました。 お見事に表示成功です。 自分としては、これで解決にしたいと思います。 htsignさんへ お気ずかい有難う御座いました。 同期、非同期の勉強になりました。 みなさん有難う御座いました。 これで実装可能状態です。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.49%

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

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

質問する

関連した質問