none
WebBrowserのデータが更新できません。 RRS feed

  • 質問

  • Formベースのアプリにおいて、ボタンを押すことにより、Web上の絶えず変化しているデータを取得します。

    取得方法は、WebBrowserを用いてあるHPにログインし、データのあるpageに移動した後、Htmlを取得し、にこのHtmlからデータを抽出します。

    困っているのは、データが変化している(IEで確認)のに、ボタンを繰り返し押しても同じ値にしかならないことです。調べてみるとHtml自身が変化していません。但し一度アプリを再起動すると、ボタンを押した最初の時のみデータが更新されます。

    よろしくお願いいたします。

    データが存在するpageのUrlは同じなので、WebBrowserが一度取得したpageを繰り返し見せているみたいです。

    このため、ボタンを押す度にWebBrowserの新しいインスタンスを作成しても変わりません。

    但し一度

     

    2010年12月26日 7:02

回答

すべての返信

  • 自己レスです。

    慣れていないため、質問の文章がおかしなってすみません。

    意図は分かっていただけると思います。

    2010年12月26日 7:06
  • WebBrowser のキャッシュ関連でよく似たスレッドです。

     WebBrowserのページキャッシュ寿命
     http://social.msdn.microsoft.com/Forums/ja-JP/csharpexpressja/thread/817d2004-f3dd-4d51-a056-2f84f958bb7e

    ちなみに、ボタンを押すとどのようなコードが動くのでしょうか?

    2010年12月26日 7:16
  • Web上の絶えず変化しているデータを取得するとのことですから、キャッシュ機能自体が無効になってもかまわないですよね? であれば、以下のページに書かれているWebBrowserコントロールを使用して、RESYNCHRONIZEのビットを立てればキャッシュを行わなくなるようです。

    WebBrowserコントロールを制御する
    http://jumbofoot.cocolog-nifty.com/yass_vbnet_tips/2006/09/webbrowser_1de3.html

     


    ★良い回答には回答済みマークを付けよう! わんくま同盟 MVP - Visual C# http://d.hatena.ne.jp/trapemiya/
    • 回答としてマーク 山本春海 2011年1月11日 2:06
    2010年12月27日 2:22
    モデレータ
  • totoJoさん アドバイスありがとうございます。

    WebBrowserのページキャッシュ寿命について初めて知りました。

    Refresh()についても試してみたのですが、引数WebBrowserRefreshOption.Completelyを付けないといけなうようですね。試してみます。

    どのようなコードということですが、結構複雑なので、Refresh等を試して上手くいかなければ相談します。

    実は、HPが証券会社で、対象とするデータは取引時間しか変化しないため、今はテストできません。

    取り敢えずありがとうございました。

    2010年12月27日 9:59
  • trapemiyaさん アドバイスありがとうございます。

    教えて頂いたページの、

    RESYNCHRONIZE = &H2000

    というのは、キャシュ寿命を2000msにするという意味と理解しました。試してみます。

    totoJoさんへの返信に書いたように、今はテストできないので、また報告します。

    ありがとうございました。

     

    2010年12月27日 10:12
  • RESYNCHRONIZE = &H2000

    というのは、キャシュ寿命を2000msにするという意味と理解しました。試してみます。

    いえ、そういう意味ではなくて、&Hを付けると16進数を表します。つまり、16進数の2000です。C#ですと0x2000という表現になります。ビット演算を行ない、そのビットの位置(0x2000の位置)を1にすることにより、キャッシュを行なわなくなります。良い例を見つけましたのでご紹介しておきます。

    WebBrowser コントロールの Navigate と Refresh を
    使うと更新完了のタイミングが掴めない
    http://ap.atmarkit.co.jp/bbs/core/fdotnet/19040

    C#でビット演算などで調べられると良いと思います。

     


    ★良い回答には回答済みマークを付けよう! わんくま同盟 MVP - Visual C# http://d.hatena.ne.jp/trapemiya/
    2010年12月27日 15:03
    モデレータ
  • どのようなコードということですが、結構複雑なので、Refresh等を試して上手くいかなければ相談します。


    データ更新の際に WebBrowser コントロールをどのように呼び出しているかが気になっただけですので、あまり気にしないでください。(Refresh だとは思ったのですが、Navigate だったりするかもしれませんので、念のために。)

    実は、HPが証券会社で、対象とするデータは取引時間しか変化しないため、今はテストできません。


    直接は関係ないのですが、テストやデバッグのことを考えると、直接実データを参照しないでも動作する口を用意しておいた方がいいと思います。テスト用の Web サーバーを用意しておいて設定で本物サーバーと切り替えるとか、Fiddler のような類のツールを使ってあらかじめ用意しておいたレスポンスを返すとか。
    2010年12月27日 15:33
  • レスが遅れて申し訳ありません。

    皆さんのアドバイスは、私の知識レベルを超えていたため、教えていただいた文献の理解に時間がかかりました。
    今も理解は不十分ですが、目的を達成することはできました。
    本来アドバイスを頂いたコメントごとにレスを付けることが望ましいでしょうが、まとめて述べることをお許しください。


    (1)totojoさん紹介の
    http://social.msdn.microsoft.com/Forums/ja-JP/csharpexpressja/thread/817d2004-f3dd-4d51-a056-2f84f958bb7e
    にあるキャッシュ寿命については、Refresh()がうまくいかなかったので、深くは検討しませんでした。

    (2)trapemiyaさん紹介の
    http://jumbofoot.cocolog-nifty.com/yass_vbnet_tips/2006/09/webbrowser_1de3.html
    には、Yas'sさん作成の、WebBrowserControlerクラスがあり、RESYNCHRONIZE = &H2000 を使っています。
    しかしこれはVBなので(私はC#)参考程度にしました。
    なおこの文献は、VBでWebBrowserコントロールを制御するという意味では、よく引用されているようです。

    (3)結局C#でWebBrowserコントロールを制御する方法として、trapemiyaさん紹介の
    http://ap.atmarkit.co.jp/bbs/core/fdotnet/19040
    の後の方にある引用文献である
    http://slingkid.blogsome.com/2006/05/26/blocking-images-similar-to-outlook
    を参考にして目的を達しました。

    下記コードは、(3)の文献からコードをダウンロードし、私の目的の確認用に簡略化したものです。

    (a)オリジナルのコードは、urlを入力するTextBox、対象とするWebページへ飛ぶButton、WebPageのイメージをダウンロードするか否かを切り替えるLabelなどがありますが、下記コードではButtonを押すごとに(b)に記載のページを表示(異なる時間が表示)されるようにしています。

    (b)webページは、totojoさんご指摘の常時使用可能なサーバーということで、
    http://www2.nict.go.jp/w/w114/tsp/PubNtp/clients.html
    (日本標準時プロジェクト)にある、現在時間を表示するurl
    http://ntp-a1.nict.go.jp/cgi-bin/time
    を使っています。

    (b)コードは、Webページを繰り返し訪問しても、キャッシュを使用しないようにする機能のみに限定して簡略化しています。例えば、enum BrowserOptions内多くのフィールド、大部分のイベントハンドラーなどを削除しています。従って元コードを下記のコードで置き換えてビルドすると、イベントハンドラーが無いなどのエラーがでます。

    (c)VBのRESYNCHRONIZEビットをたてることに相当するのが下記コードの
    IgnoreCache = 0x00002000
    だということはすぐ分かりましたが、これはWebBrowserのプロパティーを設定することとは違うので、このIgnoreCache を利用している仕組みがわかりませんでした。
    色々調べたのですが、COMの運用に関係してるらしく、結局今も分かっておりません。

    そこで他の文献などを参考にし、オリジナルのコード修正していき、結局下記になりました。
    但し下記コードにおいて、
    #region COM Interfaces
    #endregion COM Interfaces

    #region IOleClientSite Members
    #endregion
    の各々内容は省略していますが、オリジナルと同じです。
    まだ当面の目的には不要なものがあるかもしれません。


    public enum BrowserOptions : uint
    {
        /// <summary>
        ///  Specifies that the browser should fetch the content from the server. If the server's
        ///  content is the same as the cache, the cache is used.Equivalent to DLCTL_RESYNCHRONIZE.
        /// </summary>
        IgnoreCache = 0x00002000,
    }

    #region COM Interfaces
    #endregion COM Interfaces

    [ComVisible(true)]
    public partial class Form1 : Form, IOleClientSite  
    {
        string _timeUrl = "http://ntp-a1.nict.go.jp/cgi-bin/time";
        BrowserOptions _options = BrowserOptions.IgnoreCache;

        public Form1()
        {
            InitializeComponent();

            webBrowser1.DocumentCompleted += delegate(object sender, WebBrowserDocumentCompletedEventArgs e)
            {
            };
        }

        [DispId(-5512)]
        public virtual int IDispatch_Invoke_Handler()
        {
            return (int)_options;
        }

        #region IOleClientSite Members
        #endregion

        private void Form1_Activated(object sender, EventArgs e)
        {
            IOleObject obj = (IOleObject)this.webBrowser1.ActiveXInstance;
            obj.SetClientSite(this);
            this.webBrowser1.Navigate(_timeUrl);
        }

        private void GoButton_Click(object sender, EventArgs e)
        {
            _options |= BrowserOptions.IgnoreCache;

            IOleControl obj = (IOleControl)this.webBrowser1.ActiveXInstance;

            //notify browser of change
            obj.OnAmbientPropertyChange(-5512);

            this.webBrowser1.Navigate(this.webBrowser1.Url);

            while (this.webBrowser1.ReadyState != WebBrowserReadyState.Complete)
            {
                Application.DoEvents();
            }

            this._options &= ~BrowserOptions.IgnoreCache;
            obj.OnAmbientPropertyChange(-5512);

        }
    }

    今開発中のアプリに適用するには、上記コードをさらに簡略化したほうが良いように思いますが、何れにしてもここまで到達できたのは皆さんのアドバイスのおかげです。
    大変感謝しております。

     

    2011年1月1日 12:35
  • F5

    Ctrl + F5

    で、満足してください。

    ではでは。

    2011年1月2日 6:49