前回までで、見た目とRSS取得処理が完成した。
今回は、これを繋いでいってみようと思う。
とりあえず、WpfRssReaderプロジェクトに、RssReaderLibプロジェクトの参照を追加する。これが無いとはじまらないからね。
そして、画面のModelに相当するクラスを1つこさえる。名前は、なんのヒネリもなくRssReaderModelにしてみた。
namespace WpfRssReader
{
public class RssReaderModel
{
}
}
これを、画面のDataContextに設定しておく。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.ComponentModel;
namespace WpfRssReader
{
/// <summary>
/// Window1.xaml の相互作用ロジック
/// </summary>
public partial class RssReaderWindow : Window
{
public RssReaderWindow()
{
InitializeComponent();
var model = new RssReaderModel();
DataContext = model;
}
}
}
次は、Modelの実装!!
RSSのフィードは、RssInfosというプロパティで公開する形にしようと思う。
AddFeed(Uri)でフィードを追加する。
フィードの追加は、時間がかかると思うので、BackgroundWorkerを使ってバックグラウンドで行うようにしてみた。
ということでコード。
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using RssReaderLib;
namespace WpfRssReader
{
public class RssReaderModel
{
public IList<RssInfo> RssInfos { get; private set; }
public RssReaderModel()
{
RssInfos = new ObservableCollection<RssInfo>();
}
public void AddFeed(Uri uri)
{
var worker = new BackgroundWorker();
worker.DoWork += (sender, e) =>
{
var reader = new RssReader();
e.Result = reader.Read(uri);
};
worker.RunWorkerCompleted += (sender, e) =>
{
var info = e.Result as RssInfo;
RssInfos.Add(info);
};
worker.RunWorkerAsync();
}
}
}
画面のコンストラクタで、テスト用に自分のBlogと@ITのRSSフィードを追加するコードを足した。
public RssReaderWindow()
{
InitializeComponent();
var model = new RssReaderModel();
DataContext = model;
}
ということで画面にバインドしてみよう!!!
まず、RSS一覧の部分にRSSのTitleを表示してみようと思う。
ListBoxのBindingにさくっと追加。
<ListBox Style="{StaticResource rssListBoxStyle}"
ItemsSource="{Binding RssInfos}"
IsSynchronizedWithCurrentItem="True">
</ListBox>
これを実行すると、予想通りToStringされた結果が表示される。
これをTitleが表示されるようにしてみようと思う。
とりあえず、DataTemplateを定義してお茶を濁す。DataTemplateは、Styleを定義してあるRssReaderStyleDictionary.xamlに定義させてもらった。
<!-- DataTemplate -->
<DataTemplate DataType="{x:Type RssReaderLib:RssInfo}">
<TextBlock Text="{Binding Title}" />
</DataTemplate>
この状態で実行すると予定通りタイトルが表示されるようになった。
今度は、選択されたアイテムの記事の一覧を記事一覧のListViewに表示させる。
<ListView ItemsSource="{Binding RssInfos/Items}"
IsSynchronizedWithCurrentItem="True">
<ListView.View>
<GridView>
<GridViewColumn Header="日付" Width="120" DisplayMemberBinding="{Binding Date}" />
<GridViewColumn Header="タイトル" DisplayMemberBinding="{Binding Title}"/>
<GridViewColumn Header="リンク" DisplayMemberBinding="{Binding Link}"/>
</GridView>
</ListView.View>
</ListView>
ポイントは、最初のItemsSourceに指定してるBinding!!スラッシュを使うと、コレクションのコレクションの…的に指定できるみたい。
これを実行すると、日付がちょっと微妙だけど一応表示される。
日付は後回しにして、内容に選択された記事を表示してみようと思う。
これは、ListViewで選択された記事のLinkプロパティをFrameのSouceにバインドすればOK。
<Frame Source="{Binding RssInfos/Items/Link}"/>
うっし。後は日付列にある日付をフォーマッティングするだけだ!!!
これはコンバータにお願いする。
コンバータをとりあえず実装してみた。parameterで指定したフォーマットにフォーマッティングしてくれるものにしてみたよ。
using System;
using System.Windows.Data;
namespace WpfRssReader
{
public class DateTimeFormatConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
DateTime? date = value as DateTime?;
if (date == null) return string.Empty;
if (parameter == null)
{
return date.ToString();
}
return date.Value.ToString(parameter as string);
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}
}
これを日付の所のBindingに設定する。
<GridViewColumn Header="日付" Width="120">
<GridViewColumn.DisplayMemberBinding>
<Binding Path="Date" ConverterParameter="yyyy/MM/dd">
<Binding.Converter>
<WpfRssReader:DateTimeFormatConverter />
</Binding.Converter>
</Binding>
</GridViewColumn.DisplayMemberBinding>
</GridViewColumn>
これで、やっとモトネタの@ITの連載に追いついたっぽい。実行してみると、きちんと日付が出る!
満足満足。
ここまでの状態のプロジェクトはこちら。