前回 は Xamarin.Forms で TechCrunch の RSS フィードを取得したので、今度は ListView に表示してみたいと思います
まずはおなじみ UnityContainer と Prism を NuGet でパッケージインストール
インストールしたら App クラスを修正
/// <summary> /// Application class /// </summary> public class App : Application { /// <summary> /// Dependency injection container /// </summary> public IUnityContainer Container = new UnityContainer(); /// <summary> /// Costructor /// </summary> public App() { this.Container.RegisterType<INewsFeedService, NewsFeedService>(new ContainerControlledLifetimeManager()); this.MainPage = new TopPage(); } /// <summary> /// Application start event handler /// </summary> protected override void OnStart() { } /// <summary> /// Application suspend event handler /// </summary> protected override void OnSleep() { } /// <summary> /// Application resume event handler /// </summary> protected override void OnResume() { } }
前回作った NewsFeedService は INewsFeedService のインタフェースつきに変更して UnityContainer 経由でアクセスするようにしました
次に TopPage のコードビハインド
/// <summary> /// Top page /// </summary> public partial class TopPage : ContentPage { /// <summary> /// Remove html tag regex /// </summary> private static readonly Regex HtmlTagRegex = new Regex(@"<.*?>", RegexOptions.Singleline); /// <summary> /// News feed retrieve service /// </summary> private INewsFeedService newsFeed = null; /// <summary> /// ViewModel /// </summary> public TopPageViewModel ViewModel { get; private set; } /// <summary> /// Constructir /// </summary> public TopPage() { this.ViewModel = new TopPageViewModel(); this.newsFeed = ((App)App.Current).Container.Resolve<INewsFeedService>(); InitializeComponent(); } /// <summary> /// Appearing event handler /// </summary> protected override async void OnAppearing() { base.OnAppearing(); await this.newsFeed.Update(); // Add items on UI thread foreach (var item in this.newsFeed.Feed.Channel.Items) { this.ViewModel.Items.Add(new NewsItemViewModel { UniqueId = item.Guid, Categories = new ObservableCollection<string>(item.Categories), Title = item.Title, Link = item.Link, LastUpdated = item.PubDate, Description = WebUtility.HtmlDecode(HtmlTagRegex.Replace(item.Description, string.Empty)), }); } } }
Windows 10 のストアアプリの書き方にのってコードビハインドに ViewModel のプロパティを生やしました
画面表示のとき(OnAppearing)に、UnityContainer から NewsFeedService をとってきて TechCrunch のフィードを取得します
取得したフィードは ViewModel にデータを移し替えてます・・・Description の中身は HTML なので、タグを正規表現で削除したり、
などを WebUtility で変換したりしてます
TopPageViewModel は Prism の BindableBase を継承したただの ViewModel なので省略します!
さて XAML の方は
<?xml version="1.0" encoding="utf-8" ?> <ContentPage xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" x:Class="XamarinReader.Views.TopPage" x:Name="root" BindingContext="{Binding Path=ViewModel, Source={x:Reference Name=root}}"> <ListView ItemsSource="{Binding Items}" HasUnevenRows="True"> <ListView.ItemTemplate> <DataTemplate> <ViewCell> <StackLayout Orientation="Vertical" Padding="15,10" Spacing="10"> <Label Text="{Binding Title}" TextColor="Accent" FontSize="Medium"/> <Label Text="{Binding Description}" TextColor="Default" FontSize="Small"/> </StackLayout> </ViewCell> </DataTemplate> </ListView.ItemTemplate> </ListView> </ContentPage>
ListView で Title と Description を縦に並べて表示するレイアウト
BindingContext は コードビハインドの ViewModel プロパティにバインドするようにこんな感じで記述します
あと忘れちゃいけない ListView.HasUnevenRows="True"
これが指定されていないとリストの高さが固定されちゃうので注意
さくっと書いたら試してみました
ちゃんとリストごとにテキストの長さに合わせた高さになってますね