WPFでGoogle desktopの検索結果を出す
Google desktopの検索を実行して,その結果をリスト表示してみます.
サンプルコード
全コードはこちら.http://febhare.bake-neko.net/Src/Sample_GoogleDesktop_Search.zip
使用可能な検索APIと使用するAPI
検索方法はhttp://code.google.com/apis/desktop/docs/queryapi.html#httpxmlに書かれているように,COMを使う方法とHTTP/XML-Based Query APIとの2方法があります.COMを使うにはプログラムを登録する手間が必要です.そこでそのような登録が不要な分手軽なQuery APIを使います.
コード詳細
コードは,
の3段階です.
検索URLをレジストリから取得
string get_baseuri() { Microsoft.Win32.RegistryKey key = Microsoft.Win32.Registry.CurrentUser.OpenSubKey(@"Software\Google\Google Desktop\API"); string uri = key.GetValue("search_url") as string; key.Close(); return uri; }
空白で区切られた文字列から問い合わせURLを作る.
string get_query(string query) { StringBuilder sb = new StringBuilder(); foreach(String item in query.Split(new char [] { ' ' }, StringSplitOptions.RemoveEmptyEntries)) { sb.Append("+" + item); } string txt = sb.ToString().Trim(new char [] {'+'}); string baseuri = get_baseuri(); //サンプル http://127.0.0.1:4664/search&s=認証用の文字列?q=Google&format=xml return string.Format("{0}{1}&format=xml", get_baseuri(), txt); } ***検索結果をWebRequestで取得 >|java| string get_xml(string query) { WebRequest wreq = WebRequest.Create(get_query(query)); WebResponse wres = wreq.GetResponse(); using(Stream src = wres.GetResponseStream()) using (StreamReader rdr = new StreamReader(src)) { return rdr.ReadToEnd(); } }
結果を表示する
問い合わせ結果からXmlDataProviderのインスタンスを作りDataContextに入れます.
XAMLはこのように書いています.
<ListBox ItemsSource="{Binding XPath=//result}"> <ListBox.ItemTemplate> <DataTemplate> <Border> <StackPanel> <StackPanel Orientation="Horizontal"> <TextBlock Text="Title: "/> <local:HtmlTextBlock HtmlText="{Binding XPath=title}" /> </StackPanel> ...中略... </Border> </DataTemplate> </ListBox.ItemTemplate> </ListBox>
ちょっと困ったこと,文字列の書式変換をどうするか
Google desktopの結果文字列はHTMLでマークアップされていて,この書き方ではマークアップがそのまま表示されてしまいます.
<StackPanel Orientation="Horizontal"> <TextBlock Text="Title: "/> <TextBlock Text="{Binding XPath=title}"/> </StackPanel>
そのマークアップをちゃんと表記してやろうとしてはまりました.
文字列の書式設定をするにはTextBlockのInlinesに要素を追加していけばよいのですが,Inlinesは依存関係プロパティではないのでバインディングができません.Textbox with dynamic inlines - WPF Reflections,ここにあるとおりです.
イベントを拾いコードからInlinesを設定しようとしました.下記のようなコードを書いて,1.上記コードのバインディングをDataContextに設定してDataContextChangedイベントを拾う,2.ターゲット更新イベントを拾う,をそれぞれ試しましたがイベントが発生しませんでした.XPathで指定したXmlElementがBindされることを期待して,DataContextにXmlDataProviderの新しいインスタンスを与えてはいるのですが.
<StackPanel Orientation="Horizontal"> <TextBlock Text="Title: "/> <TextBlock Text="{Binding XPath=title, NotifyOnTargetUpdated=True}" TargetUpdated="TextBlock_TargetUpdated"/> </StackPanel>
仕方がないので,TextBlockを継承するクラスを作成して,HtmlTextという依存関係プロパティを入れました.このテキストに入力されたマークアップ文字列はInlinesに設定されるコードを追加しました.