Опубликован: 12.02.2013 | Доступ: свободный | Студентов: 791 / 47 | Длительность: 17:51:00
Специальности: Программист
Лекция 7:

Средства Windows Phone для работы с сетью

17.4. Подключение к сетевому ресурсу

Часто программам приходится получать информацию из различных сетевых ресурсов. Обычно это довольно утомительный процесс, но его можно упростить, используя класс WebClient.

Класс WebClient является частью сетевой библиотеки.NET, которую можно использовать как в программах для Windows Phone, так и в программах для компьютеров под управлением Windows. Можно использовать класс для взаимодействия с удалённым сервером по протоколу HTTP.

Создадим простую программу, которая при нажатии на кнопку выведет на экран код веб-страницы, адрес которой вводит пользователь в текстовое поле. Фактически, аналогичное действие выполняют веб-браузеры, только последние обрабатывают код страницы и выводят её в том виде, в каком её ожидает увидеть пользователь.

Сначала нужно объявить переменную типа WebClient в классе MainPage. Эта переменная будет использоваться для управления веб-запросами, которые будут использоваться в программе. Экземпляр класса WebClient создаётся в конструкторе страницы:

WebClient client;

public MainPage()
{
    InitializeComponent();

    client = new WebClient();
    client.DownloadStringCompleted +=
        new DownloadStringCompletedEventHandler(client_DownloadStringCompleted);
}

В конструкторе также создаётся обработчик события DownloadStringCompleted, который выводит код веб-страницы в визуальный элемент pageTextBlock, если загрузка веб-страницы выполнилась успешно:

void client_DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e)
{
    if (e.Error == null)
    {
        pageTextBlock.Text = e.Result;
    }
}

Остаётся добавить в программу обработчик нажатия на кнопку, в котором будет загружаться веб-страница, адрес которой ввёл пользователь:

private void loadButton_Click(object sender, RoutedEventArgs e)
{
    client.DownloadStringAsync(new Uri(urlTextBox.Text));
}

При нажатии на кнопку выполняются следующие действия:

  1. Строка, введённая в текстовое поле urlTextBox, используется для создания URI требуемой веб-страницы.
  2. Вызывается метод DownloadStringAsync класса WebClient, который запускает новую веб-транзакцию, после чего завершает свою работу и передаёт управление программе.
  3. Через какое-то время класс WebClient считает содержимое запрошенной веб-страницы и сгенерирует событие DownloadStringCompleted, которое сигнализирует об окончании приёма сообщения.
  4. Событие вызовет метод-обработчик client_DownloadStringCompleted, который проверит, возникли ли при получении данных ошибки, и если нет — выводит полученный код страницы в визуальный элемент pageTextBlock.

17.5. Чтение данных из XML-потока с помощью LINQ

Приложения могут взаимодействовать с различными информационными службами, например c Twitter, используя протокол передачи состояния представления REST. REST использует URL для указания необходимого действия. Например, если в браузере указать адрес http://twitter.com/statuses/user_timeline/user_name.xml, будет выдан XML-документ, который содержит новые сообщения пользователя "user_name". Если заменить в этой строке "user_name" на имя другого пользователя Twitter, будет выдана информация о сообщениях этого пользователя.

Можно изменить программу, созданную в предыдущем примере, так, чтобы она создавала запрос для Twitter и использовала его для получения информации об указанном пользователе. Достаточно изменить имя элемента текстового поля на nameTextBox (но можно этого не делать — имя элемента несёт только смысловую нагрузку) и изменить код метода loadButton_Click:

private void loadButton_Click(object sender, RoutedEventArgs e)
{
    string url = "http://twitter.com/statuses/user_timeline/" + nameTextBox.Text
        + ".xml";

    client.DownloadStringAsync(new Uri(url));
}

Twitter предоставляет информацию о состоянии в формате XML. XML представляет информацию в структурированном виде, и её можно обработать и вывести на экран в удобном виде. Для обработки XML можно использовать LINQ.

XML-документ похож на базу данных, в которой содержатся элементы и атрибутами. Кроме инструментов для создания запросов к базе данных и получения из них структурированной информации, LINQ также содержит инструменты для создания объектов на основе данных XML.

Информация, полученная от Twitter, является структурированным XML-документом, который содержит элементы и атрибуты, которые описывают содержание сообщений Twitter:

<?xml version="1.0" encoding="UTF-8"?>
<statuses type="array">
  <status>
    <created_at>Tue Oct 11 11:57:37 +0000 2011</created_at>
    <id>27131245083</id>
    <text>
        Had 12,000 hits on www.csharpcourse.com for my C# Yellow Book. No idea why.
    </text>
    <source>web</source>
    <truncated>false</truncated>
    <in_reply_to_status_id></in_reply_to_status_id>
    <in_reply_to_user_id></in_reply_to_user_id>
    <favorited>false</favorited>
    <in_reply_to_screen_name></in_reply_to_screen_name>
    <retweet_count>0</retweet_count>
    <retweeted>false</retweeted>
    <user>
      <id>2479801</id>
      <name>Rob Miles</name>
      <screen_name>robmiles</screen_name>
      <location>Hull, UK</location>
      <description>A Computer Science lecturer and Microsoft MVP.</description>
      <profile_image_url>
          http://a3.twimg.com/prof_im/157/me2_normal.jpg
      </profile_image_url>
      <url>http://www.robmiles.com</url>
      <protected>false</protected>
      <friends_count>21</friends_count>
      <created_at>Tue Mar 27 12:35:28 +0000 2007</created_at>
      <favourites_count>0</favourites_count>
      <utc_offset>0</utc_offset>
      <time_zone>London</time_zone>
      <profile_background_image_url>
          http://s.twimg.com/a/1286/images/themes/theme1/bg.png
      </profile_background_image_url>
      <notifications>false</notifications>
      <geo_enabled>true</geo_enabled>
      <verified>false</verified>
      <following>true</following>
      <statuses_count>731</statuses_count>
      <lang>en</lang>
      <contributors_enabled>false</contributors_enabled>
      <follow_request_sent>false</follow_request_sent>
      <listed_count>61</listed_count>
      <show_all_inline_media>false</show_all_inline_media>
    </user>
    <geo/>
    <coordinates/>
    <place/>
    <contributors/>
  </status>
</statuses>

В этой XML-структуре представлена небольшая часть информации, которую выдаёт Twitter в виде XML-файла. В действительности, этот файл бывает гораздо большего объёма.

С помощью LINQ можно создать запрос к базе данных, который возвратит коллекцию найденных объектов, а можно создать конструкцию, которая представляет содержание XML-документа:

XElement TwitterElement = XElement.Parse(twitterText);

Класс XElement является частью LINQ и представляет собой элемент XML. Строка twitterText содержит информацию, полученную от Twitter с помощью класса WebClient. Экземпляр класса XElement позволяет сохранить эту информацию в виде структурированного документа. Необходимо преобразовать эту информацию в форму, удобную для вывода на экран.

Как было рассмотрено в предыдущих лекциях, можно создать классы C# для хранения информации об объектах и применить привязку данных для связи этих классов с визуальными элементами Silverlight. В эти классы можно загружать данные как из базы данных, так и из XML-файла.

В нашем случае можно использовать не все элементы XML-структуры сообщения Twitter, а только те, которые представляют интерес: фотографию пользователя Twitter, который создал сообщение, дату и текст сообщения. Класс, который содержит эту информацию, может выглядеть так:

public class TwitterPost
{
    public string PostText { get; set; }

    public string DatePosted { get; set; }

    public string UserImage { get; set; }
}

Эти свойства будут содержать значения, полученные от Twitter, и пользователь не будет их изменять. Обратите внимание, что свойство UserImage имеет строковый тип и содержит URI изображения, которое будет загружаться из Интернета.

Теперь необходимо использовать LINQ для получения коллекции объектов из элемента XElement, который содержит всю информацию, полученную от Twitter.

var postList = from tweet in twitterElements.Descendants("status")
                select new TwitterPost
                {
                    UserImage =
                        tweet.Element("user").Element("profile_image_url").Value,
                    PostText = tweet.Element("text").Value,
                    DatePosted = tweet.Element("created_at").Value
                };

В этом коде в секции from выполняется перебор элементов с именем <status>. Эти элементы программа обрабатывает по очереди. В секции select для каждого элемента создаётся экземпляр класса TwitterPost, и его свойствам присваиваются значения указанных XML-элементов, вложенных в элемент <status>. Метод Element возвращает содержимое XML-элемента с заданным именем.

Результат запроса заносится в переменную postList, которая фактически будет являться коллекцией объектов класса TwitterPost. Если применить запрос к XML-документу, который был представлен выше, то запрос создаст список из одного элемента. Однако, в общем случае полученный список будет содержать несколько объектов.

Далее, необходимо вывести сообщения из списка на экран в виде, удобном для чтения сообщений. Например, одно сообщение может выглядеть так, как изображено на рис. 17.2.

Внешний вид сообщения, полученного из сети Twitter

Рис. 17.2. Внешний вид сообщения, полученного из сети Twitter

Это изображение можно разделить на три блока: слева будет размещена фотография пользователя, в верхней части — дата создания сообщения, по центру — текст сообщения (рис. 17.3).

Структура сообщения, полученного из сети Twitter

Рис. 17.3. Структура сообщения, полученного из сети Twitter

В Silverlight эту разметку можно выполнить, используя элементы-контейнеры StackPanel:

<StackPanel Orientation="Horizontal" Height="132">
  <Image Source="{Binding UserImage}" Height="73" Width="73" VerticalAlignment="Top"
      Margin="0,10,8,0"/>
  <StackPanel Width="370">
    <TextBlock Text="{Binding DatePosted}" Foreground="#FFC8AB14" FontSize="22" />
    <TextBlock Text="{Binding PostText}" TextWrapping="Wrap" FontSize="24" />
  </StackPanel>
</StackPanel>

Класс StackPanel позволяет автоматически располагать и выравнивать элементы на странице программы. В этом коде используется привязка данных, которая связывает элементы со свойствами класса TwitterPost.

Полученную разметку необходимо указать в качестве шаблона разметки элементов списка ListBox:

<ListBox Height="442" HorizontalAlignment="Left" Name="tweetsListBox"
    VerticalAlignment="Top" Width="468">
  <ListBox.ItemTemplate>
    <DataTemplate>
      <StackPanel Orientation="Horizontal" Height="132">
        <Image Source="{Binding UserImage}" Height="73" Width="73"
            VerticalAlignment="Top" Margin="0,10,8,0"/>
        <StackPanel Width="370">
          <TextBlock Text="{Binding DatePosted}" Foreground="#FFC8AB14"
              FontSize="22" />
          <TextBlock Text="{Binding PostText}" TextWrapping="Wrap" FontSize="24" />
        </StackPanel>
      </StackPanel>
    </DataTemplate>
  </ListBox.ItemTemplate>
</ListBox>

После этого остаётся только указать переменную postList, в которой хранятся сообщения из Twitter, в качестве источника данных для списка ListBox:

tweetsListBox.ItemsSource = postList;

Элемент ListBox предоставляет много полезных функций. В частности, он поддерживает автоматическое добавление прокрутки элементов списка вверх и вниз с её ускорением и остановкой пальцем.