모다의 윈도우폰7 뚝딱 팩토리(14)-LINQ to XML을 이용한 RSS 리더 만들기
한국마이크로소프트에서 초급 스마트폰 개발자 분들을 위해 공개하는 모다의 윈도우폰7 뚝딱 팩토리 열네번째 영상!
데이터를 “저장하는 기술”도 중요하지만 데이터를 저장하는 “형태” 역시 중요합니다. 그리고 이것을 “해석하는 기술” 역시 중요하죠. 3박자가 모두 맞아 떨어져야 멋진 어플리케이션이 만들어 지고 사용하시는 분들을 감동시킬 수 있죠.
이번에 다룰 내용은 바로 마지막에 해당하는 데이터를 해석하는 기술입니다. 마이크로소프트에서는 데이터를 해석하는 기술중의 하나인 LINQ(Language Integrated Query)를 제공하고 있으며 이번 영상에서 다루어 볼 내용은 LINQ를 이용해 XML문서를 해석하는 LINQ to XML 입니다. 그리고 이 기술을 적용하기 위해 이번 영상에서 예제로 들고 있는것이 바로 RSS이지요. 윈도우폰 공식 블로그의 RSS를 이용해 윈도우폰에서 열어보는 약간 복잡하지만 유용한 예제를 보여드립니다.
RSS는 XML 1.0 스팩을 이용하고 있으며, XML을 해석하기 위해서는 System.Xml.Linq 네임 스페이스를 Add Reference 기능을 이용해 추가한 다음 이용하셔야 합니다. 그리고 XML의 형태에 맞게 맵핑을 해서 사용할 수가 있지요. LINQ로 해석하는 부분은 다음과 같습니다.
var rssList = from rssTree in rssParser.Descendants("item")
select new BlogPost
{
Title = rssTree.Element("title").Value,
Contents = rssTree.Element("description").Value ,
Url = rssTree.Element("link").Value
};
이 코드는 미리 만들어 진 BlogPost 클래스의 Title / Contents / Url Property에 각각 <title></title> / <description></description> / <link></link> 태그 안에 포함 된 내용을 맵핑하는 부분입니다. 참고로 BlogPost 클래스의 선언은 다음과 같이 되어 있습니다. 맵핑용 클래스를 선언하실 때는 항상 접근이 용이하도록 public / get / set 등을 적절히 선언해 주셔야 합니다.
public class BlogPost
{
public string Title { get; set; }
public string Contents { get; set; }
public string Url { get; set; }
}
또한 이전에 보여드렸던 Data Binding에서 조금 더 발전된 방법을 보여드리고 있는데요, 직접적으로 ListBox 안에 들어가는 형태와 데이터를 직접 커스터마이징하는 방법을 담았습니다. XAML코드에서 ListBox 안에 출력할 템플릿을 추가하는 방법은 다음과 같습니다. 아래 코드에서 {Binding Title} / {Binding Contents} 부분은 앞서 적어드린 BlogPost 상의 Property 이름과 동일하게 적어주시면 됩니다. 그리고 이를 연동하실 때는 listBox1.ItemsSource = rssList 로 코딩 해 주시면 됩니다.
<ListBox Height="498" HorizontalAlignment="Left" Name="listBox1" VerticalAlignment="Top" Width="456" SelectionChanged="listBox1_SelectionChanged">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Vertical" Margin="0,0,0,10">
<TextBlock Text="{Binding Title}" Foreground="#FFE0C000" FontSize="30" />
<TextBlock Text="{Binding Contents}" TextWrapping="Wrap" />
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
이 외에도 로딩중 표시하기(ProgressBar), Linked List 활용하기 등 여러가지 기술들이 이번 동영상에 녹아있고 특히 Data Binding과 LINQ to XML은 윈도우폰 어플리케이션을 개발하는 데 있어서 단골로 사용하는 기술들입니다. 이번 영상이 많은 도움이 되시길 바랍니다.
1: using System;
2: using System.Collections.Generic;
3: using System.Linq;
4: using System.Net;
5: using System.Windows;
6: using System.Windows.Controls;
7: using System.Windows.Documents;
8: using System.Windows.Input;
9: using System.Windows.Media;
10: using System.Windows.Media.Animation;
11: using System.Windows.Shapes;
12: using Microsoft.Phone.Controls;
13:
14: using System.Xml.Linq;
15: using Microsoft.Phone.Tasks;
16:
17: namespace rssParserTest01
18: {
19: public partial class MainPage : PhoneApplicationPage
20: {
21: List<BlogPost> blogPosts = new List<BlogPost>();
22:
23: // Constructor
24: public MainPage()
25: {
26: InitializeComponent();
27: }
28:
29: private void button1_Click(object sender, RoutedEventArgs e)
30: {
31: progressBar1.Visibility = System.Windows.Visibility.Visible;
32: progressBar1.IsIndeterminate = true;
33:
34: WebClient rssDownloader = new WebClient();
35: rssDownloader.DownloadStringAsync(new Uri("https://blogs.msdn.com/b/jinhoseo/rss.aspx"));
36: rssDownloader.DownloadStringCompleted += new System.Net.DownloadStringCompletedEventHandler(rssDownloader_DownloadStringCompleted);
37: }
38:
39: void rssDownloader_DownloadStringCompleted(object sender, System.Net.DownloadStringCompletedEventArgs e)
40: {
41: // throw new NotImplementedException();
42: string rssContent = e.Result;
43:
44: XDocument rssParser = XDocument.Parse(rssContent);
45:
46: //LINQ
47: var rssList = from rssTree in rssParser.Descendants("item")
48: select new BlogPost
49: {
50: Title = rssTree.Element("title").Value,
51: Contents = rssTree.Element("description").Value ,
52: Url = rssTree.Element("link").Value
53: };
54:
55: listBox1.ItemsSource = rssList;
56: blogPosts = rssList.ToList();
57: progressBar1.Visibility = System.Windows.Visibility.Collapsed;
58: }
59:
60: private void listBox1_SelectionChanged(object sender, SelectionChangedEventArgs e)
61: {
62: WebBrowserTask blogViewer = new WebBrowserTask();
63: blogViewer.URL = blogPosts[listBox1.SelectedIndex].Url;
64: blogViewer.Show();
65: }
66: }
67:
68: public class BlogPost
69: {
70: public string Title { get; set; }
71: public string Contents { get; set; }
72: public string Url { get; set; }
73: }
74: }
1: <phone:PhoneApplicationPage
2: x:Class="rssParserTest01.MainPage"
3: xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
4: xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml"
5: xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone"
6: xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone"
7: xmlns:d="https://schemas.microsoft.com/expression/blend/2008"
8: xmlns:mc="https://schemas.openxmlformats.org/markup-compatibility/2006"
9: mc:Ignorable="d" d:DesignWidth="480" d:DesignHeight="768"
10: FontFamily="{StaticResource PhoneFontFamilyNormal}"
11: FontSize="{StaticResource PhoneFontSizeNormal}"
12: Foreground="{StaticResource PhoneForegroundBrush}"
13: SupportedOrientations="Portrait" Orientation="Portrait"
14: shell:SystemTray.IsVisible="True">
15:
16: <!--LayoutRoot is the root grid where all page content is placed-->
17: <Grid x:Name="LayoutRoot" Background="Transparent">
18: <Grid.RowDefinitions>
19: <RowDefinition Height="Auto"/>
20: <RowDefinition Height="*"/>
21: </Grid.RowDefinitions>
22:
23: <!--TitlePanel contains the name of the application and page title-->
24: <StackPanel x:Name="TitlePanel" Grid.Row="0" Margin="12,17,0,28">
25: <TextBlock x:Name="ApplicationTitle" Text="MY APPLICATION" Style="{StaticResource PhoneTextNormalStyle}"/>
26: <TextBlock x:Name="PageTitle" Text="page name" Margin="9,-7,0,0" Style="{StaticResource PhoneTextTitle1Style}"/>
27: </StackPanel>
28:
29: <!--ContentPanel - place additional content here-->
30: <Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
31: <Button Content="Button" Height="97" HorizontalAlignment="Left" Margin="6,504,0,0" Name="button1" VerticalAlignment="Top" Width="450" Click="button1_Click" />
32: <ListBox Height="498" HorizontalAlignment="Left" Name="listBox1" VerticalAlignment="Top" Width="456" SelectionChanged="listBox1_SelectionChanged">
33: <ListBox.ItemTemplate>
34: <DataTemplate>
35: <StackPanel Orientation="Vertical" Margin="0,0,0,10">
36: <TextBlock Text="{Binding Title}" Foreground="#FFE0C000" FontSize="30" />
37: <TextBlock Text="{Binding Contents}" TextWrapping="Wrap" />
38: </StackPanel>
39: </DataTemplate>
40: </ListBox.ItemTemplate>
41: </ListBox>
42: <ProgressBar Height="4" HorizontalAlignment="Left" Margin="10,200,0,0" Name="progressBar1" VerticalAlignment="Top" Width="460" Visibility="Collapsed" />
43: </Grid>
44: </Grid>
45: </phone:PhoneApplicationPage>