WPFでTwitterのタイムラインを表示するサンプル
TwitterのユーザータイムラインをXMLデータで取得して、WPFのフォームグリッドに表示させてみた。
WPFには標準でDataGridが付いてないので、WPF ToolkitのDataGridを使用している、こちらもMicrosoft製らしい。
最近はMVCを考慮したシステム構成をいろいろ考えていたのだが、WPFのXAML+C#の構造は、WEBブラウザ上で動作するHTML+JavaScriptの構造と同じといっていいと思う。WEBサービスをMVCレイヤーのモデル部分として考えたら、ビューコントローラであるプレゼンテーション部分は、取得したデータをどの様に表示するかを記述するだけでいい。
プレゼンテーションのマークアップ
Presentation.xaml
<!-- /////////////////////////////////////////////////////////////////////////////// // // WPF サンプル プレゼンテーションマークアップです。 // // Copyright 2009 hiroxpepe // Author hiroxpepe <hiroxpepe@gmail.com> // Version 1.0.0 // Since 09.08.14 // Update 09.08.14 --> <Window x:Class="WpfProtoType.Presentation" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:wtk="clr-namespace:Microsoft.Windows.Controls;assembly=WPFToolkit" Title="My TimeLine" Loaded="Window_Loaded" MaxWidth="600" MaxHeight="480"> <StackPanel Orientation="Vertical" VerticalAlignment="Top" Margin="10"> <!-- ユーザ名入力とデータ取得ボタン --> <Border BorderBrush="DarkGray" BorderThickness="1" Padding="5" CornerRadius="5"> <StackPanel Orientation="Horizontal"> <TextBlock Text="ユーザー名:" VerticalAlignment="center"/> <TextBox Name="userName" Width="100"/> <Button Name="updateButton" Click="UpdateButton_Click">データ取得</Button> </StackPanel> </Border> <Separator Height="10" Visibility="Hidden" /> <!-- XMLデータ表示用のグリッドコントロール --> <Border BorderBrush="DarkGray" BorderThickness="1" Padding="5" CornerRadius="5"> <wtk:DataGrid Name="dataGrid" ItemsSource="{Binding}" AutoGenerateColumns="False"> <wtk:DataGrid.Columns> <wtk:DataGridTextColumn Binding="{Binding Date}" Header="日付時刻"/> <wtk:DataGridTextColumn Binding="{Binding ID}" Header="投稿ID"/> <wtk:DataGridTextColumn Binding="{Binding Client}" Header="クライアント"/> <wtk:DataGridTextColumn Binding="{Binding Text}" Header="テキスト"/> </wtk:DataGrid.Columns> </wtk:DataGrid> </Border> </StackPanel> </Window>
プレゼンテーションのプロシージャコード
Presentation.xaml.cs
using System; using System.Collections.Generic; using System.Net; using System.Text; using System.Windows; using System.Xml; /////////////////////////////////////////////////////////////////////////////// // // WPF サンプル プレゼンテーションコードです。 // // Copyright 2009 hiroxpepe // Author hiroxpepe <hiroxpepe@gmail.com> // Version 1.0.0 // Since 09.08.14 // Update 09.08.14 namespace WpfProtoType { /// <summary> /// データ構造オブジェクト /// </summary> public class TimeLine { public string Date { get; set; } public string ID { get; set; } public string Client { get; set; } public string Text { get; set; } } /// <summary> /// Presentation.xaml の相互作用ロジック /// </summary> public partial class Presentation : Window { /////////////////////////////////////////////////////////////////////// #region 定数 /// <summary> /// WEBサービス取得用のURLを定義します。 /// </summary> //const string serviceUrl = "{0}.xml"; const string serviceUrl = "http://twitter.com/statuses/user_timeline/{0}.xml"; #endregion /////////////////////////////////////////////////////////////////////// #region フィールド /// <summary> /// XMLデータを読み込んで処理する、XmlDocumentオブジクトを保存します。 /// </summary> private XmlDocument xmlDoc; /// <summary> /// データ部分をDOMノードリストとして処理する、XmlNodeListオブジクトを保存します。 /// </summary> private XmlNodeList xmlNodes; #endregion /// <summary> /// 引数なしコンストラクタを実行します。 /// </summary> public Presentation() { InitializeComponent(); } /////////////////////////////////////////////////////////////////////// #region プロテクテッドメソッド /// <summary> /// フォームロード時に初期化処理を実行します。 /// </summary> /// <param name="sender">イベント送信オブジェクトが提供されます。</param> /// <param name="e">イベントのデータが提供されます。</param> protected void Window_Loaded(object sender, RoutedEventArgs e) { this.xmlDoc = new XmlDocument(); } /// <summary> /// XMLデータを取得してグリッド表示を更新します。 /// </summary> /// <param name="sender">イベント送信オブジェクトが提供されます。</param> /// <param name="e">イベントのデータが提供されます。</param> protected void UpdateButton_Click(object sender, RoutedEventArgs e) { try { // フォームからユーザ名取得 var userName = this.userName.Text; // バインドオブジェクトにデータを取得する this.DataContext = this.GetDataContext(userName); } catch (Exception err) { MessageBox.Show(err.Message); } } #endregion /////////////////////////////////////////////////////////////////////// #region プライベートメソッド /// <summary> /// リストデータを取得します。 /// </summary> /// <param name="userName">ユーザ名が提供されます。</param> /// <returns>データオブジェクトを格納したリストを返します。</returns> private List<TimeLine> GetDataContext(string userName) { try { // XMLドキュメントを読み込む this.LoadXmlDoc(userName); // DOMノードを抽出する this.SelectDomNodes(); // リストデータを返す return this.CreateList(); } catch (Exception err) { MessageBox.Show(err.Message); return null; } } /// <summary> /// XMLドキュメントを読み込みます。 /// </summary> /// <param name="userName">ユーザ名が提供されます。</param> private void LoadXmlDoc(string userName) { this.xmlDoc.LoadXml(this.GetXmlDate(userName)); } /// <summary> /// XMLドキュメントからDOMノードを抽出します。 /// </summary> private void SelectDomNodes() { this.xmlNodes = this.xmlDoc.SelectNodes("//statuses/status"); } /// <summary> /// XMLノードをイテレーションしてリストデータを作成します。 /// </summary> /// <returns>データオブジェクトを格納したリストを返します。</returns> private List<TimeLine> CreateList() { var list = new List<TimeLine>(); foreach (XmlNode node in this.xmlNodes) { list.Add(new TimeLine { Date = this.FormatDate(node), ID = this.FormatId(node), Client = this.FormatClient(node), Text = this.FormatText(node) }); } return list; } /// <summary> /// サーバーからXMLデータを取得します。 /// </summary> /// <param name="userName">ユーザ名が提供されます。</param> /// <returns>取得したXMLデータ文字列を返します。</returns> private string GetXmlDate(string userName) { var timelineUrl = string.Format(serviceUrl, userName); WebClient webClient = new WebClient(); webClient.Encoding = Encoding.UTF8; byte[] data = webClient.DownloadData(timelineUrl); return Encoding.UTF8.GetString(data); } /// <summary> /// 日付をフォーマットします。 /// </summary> /// <param name="node">イテレーション中のNodeオブジェクトが提供されます。</param> /// <returns>書式変換された日付文字列を返します。</returns> private string FormatDate(XmlNode node) { var date = node["created_at"].InnerText; return DateTime.ParseExact(date, "ddd MMM dd HH':'mm':'ss zzzz yyyy", System.Globalization.DateTimeFormatInfo.InvariantInfo, System.Globalization.DateTimeStyles.None ).ToString("yyyy/MM/dd HH:mm:ss"); } /// <summary> /// 投稿IDをフォーマットします。 /// </summary> /// <param name="node">イテレーション中のNodeオブジェクトが提供されます。</param> /// <returns>書式変換された投稿ID文字列を返します。</returns> private string FormatId(XmlNode node) { return node["id"].InnerText; } /// <summary> /// クライアントをフォーマットします。 /// </summary> /// <param name="node">イテレーション中のNodeオブジェクトが提供されます。</param> /// <returns>書式変換されたクライアント文字列を返します。</returns> private string FormatClient(XmlNode node) { try { return node["source"].InnerText.Split('>')[1].Split('<')[0]; } catch { return node["source"].InnerText; } } /// <summary> /// テキスト文をフォーマットします。 /// </summary> /// <param name="node">イテレーション中のNodeオブジェクトが提供されます。</param> /// <returns>書式変換されたテキスト文字列を返します。</returns> private string FormatText(XmlNode node) { return node["text"].InnerText; } #endregion } }