Silverlight является основной платформой разработки приложений для Windows Phone 7. В предыдущем уроке мы рассказали, как настроить систему для разработки под Windows Phone 7, а затем разработали очень простое приложение Silverlight, которое вращало кнопку вокруг сетки. Эта статья познакомит вас с более продвинутыми функциями Silverlight и позволит вам разрабатывать значимые приложения, которые отображают данные интересным и уникальным способом.
В этой статье вы познакомитесь с рядом функций Windows Phone 7 и Silverlight среднего уровня, включая ресурсы приложений, стили, шаблоны данных и навигацию по представлениям. Вы воспользуетесь преимуществами привязки данных и служб WP7, которые позволяют быстро и легко перемещаться между страницами. Вы должны иметь некоторое представление о XAML и C # перед началом этого урока.
Создание вашего проекта
В этом руководстве вы создадите простой клиент Digg, который позволит пользователю просматривать истории по темам. Вы воспользуетесь функциями Silverlight и Windows Phone 7 среднего уровня, включая ресурсы приложений, стили, шаблоны данных и службы навигации. Вы будете использовать привязку данных для отображения информации из Digg и различных служб WP7, чтобы пользователи могли обойти ваше приложение.
Для начала убедитесь, что на вашем компьютере установлены последние средства разработки для Windows Phone 7 . Инструменты были обновлены 12 июля 2010 года, поэтому вам может потребоваться удалить предыдущий CTP и установить бета-версию инструментов.
Откройте Visual Studio 2010 и нажмите «Новый проект» на левой боковой панели. В появившемся диалоговом окне выберите «Приложение для Windows Phone» из доступных шаблонов и присвойте своему проекту имя, например «SimpleDigg». Убедитесь, что установлен флажок «Создать каталог для решения», и нажмите «ОК». должно выглядеть следующим образом:
После создания проекта Visual Studio открывает файл MainPage.xaml для редактирования. Закройте этот файл сейчас.
Создание классов данных Digg
Для доступа к данным Digg мы будем использовать их официальный API . В частности, мы будем использовать методы story.getAll и topic.getAll . Примеры ответов на каждый звонок можно найти по следующим адресам:
Как видите, story.getAll возвращает элементы истории. Истории имеют много данных, связанных с ними, но мы собираемся сосредоточиться на 4 частях информации:
- заглавие
- Описание
- Диггс
- Ссылка на сайт
Давайте создадим класс для хранения этих данных. В обозревателе решений Visual Studio (который по умолчанию открыт на правой боковой панели) щелкните правой кнопкой мыши свой проект и выберите «Добавить> Новая папка». Назовите эту новую папку Digg
. Щелкните правой кнопкой мыши на только что созданной папке и выберите «Добавить> Класс…». Назовите свой класс Story
и нажмите кнопку Добавить.
Visual Studio откроет ваш новый класс для редактирования. Внутри определения класса добавьте четыре открытых свойства, таких как следующее:
публичная строка Title {get; устанавливать; } открытая строка Описание {get; устанавливать; } публичная строка Link {get; устанавливать; } public int Diggs {get; устанавливать; }
Теперь добавьте класс, который будет содержать данные темы. Снова щелкните правой кнопкой мыши папку Digg
и выберите «Добавить> Класс…». Назовите Topic
вашего класса и добавьте следующие свойства при открытии файла:
публичная строка Name {get; устанавливать; } открытая строка ShortName {get; устанавливать; }
На данный момент вы создали все классы данных, которые вам понадобятся для этого урока, и готовы разметить представления, необходимые для остальной части приложения.
Создание видов
У клиента SimpleDigg есть три разных представления, которые необходимо создать. Они есть:
- Список тем — список всех тем на Digg
- Список историй — список историй, полученных из Digg на основе определенной темы.
- Story Detail — Показывает детали о выбранной истории
Список тем
Список тем будет первым экраном, который увидят пользователи при запуске приложения. Он включает в себя список названий тем, который при нажатии на одну из тем приводит к списку тем в этой теме. Поскольку это будет первый экран, который увидят пользователи, мы продолжим и будем использовать ранее созданный файл MainPage.xaml, который уже существует в Проекте. Откройте MainPage.xaml, и вы должны увидеть визуальное представление слева и разметку для вида справа.
Нажмите на текст «Мое приложение» в визуальном представлении и обратите внимание, что элемент TextBlock
в представлении XAML выделен. Этот TextBlock
имеет атрибут Text
настоящее время занятый значением «МОЕ ПРИЛОЖЕНИЕ» . Измените это значение на любое другое. Я рекомендую «Simple Digg». Вы увидите, что визуальный дизайнер обновляется в соответствии с вашими изменениями.
Теперь повторите процесс со строкой «имя страницы». Нажмите на текст, найдите соответствующий TextBlock
и измените атрибут Text
. На этот раз я рекомендую изменить его на «Темы». Если вы все сделали правильно до этого момента, у вас должен быть элемент StackPanel
, содержащий два @ TextBlock @ s, каждый с соответствующим значением. XAML выглядит следующим образом:
01
02
03
04
05
06
07
08
09
10
11
|
<StackPanel x:Name=»TitlePanel» Grid.Row=»0″ Margin=»24,24,0,12″>
<TextBlock
x:Name=»ApplicationTitle»
Text=»Simple Digg»
Style=»{StaticResource PhoneTextNormalStyle}»/>
<TextBlock
x:Name=»PageTitle»
Text=»Topics»
Margin=»-3,-8,0,0″
Style=»{StaticResource PhoneTextTitle1Style}»/>
</StackPanel>
|
Теперь вам нужно добавить контейнер списка на вашу страницу. Откройте панель инструментов управления (расположена слева от Visual Studio) и перетащите элемент ListBox в большую пустую область на своей странице. Вам нужно изменить его, чтобы растянуть ширину и высоту его контейнера, поэтому поместите курсор в редактор XAML и измените элемент ListBox, чтобы он выглядел следующим образом:
1
2
|
<ListBox
Name=»TopicsList» />
|
Эта разметка удаляет все стили, представленные визуальным дизайнером, и переименовывает элемент, чтобы вы могли получить к нему доступ. К этому моменту вы завершили разметку для представления списка тем и теперь можете переходить к другим частям приложения.
Список рассказов
Представление списка историй очень похоже на список тем. В организационных целях мы собираемся поместить это представление (а затем представление Story Detail) в отдельную папку. Щелкните правой кнопкой мыши имя вашего проекта в обозревателе решений и выберите «Добавить> Новая папка». Назовите новую папку « Views
. Затем щелкните правой кнопкой мыши папку « Views
» и выберите «Добавить> Новый элемент…». Выберите шаблон Windows Phone Portrait Page
и назовите его Stories.xaml
. Ваше диалоговое окно должно выглядеть следующим образом:
Теперь, как и раньше, измените заголовок приложения на «Simple Digg», а имя страницы на «Stories». Затем перетащите ListBox на пустое пространство под заголовком вашей страницы и измените его разметку, чтобы он выглядел следующим образом:
1
2
|
<ListBox
Name=»StoriesList» />
|
На этом этапе ваш список рассказов выглядит почти идентично вашему списку тем. Реальные различия проявятся, когда вы заполните их элементами данных.
Детали истории
Финальным представлением для вашего приложения является представление Story Details. Представление Story Details представит 4 фрагмента данных, о которых мы говорили ранее:
- заглавие
- Описание
- Диггс
- Ссылка на сайт
Количество Diggs и заголовок будет занимать верхнюю часть представления, а описание истории будет следовать ниже. После этого ссылка позволит пользователю перейти к рассматриваемой истории, если он пожелает.
Как и раньше, щелкните правой кнопкой мыши папку Views
в вашем проекте и выберите Add> New Item. Выберите шаблон Windows Phone Portrait Page
и назовите новый вид Story.xaml
. Нажмите «Добавить», и Visual Studio создаст Story.xaml
и откроет его для редактирования.
Измените заголовки приложения и текстовые блоки заголовка страницы, чтобы они читались как «Простая Digg» и «История» соответственно. Теперь перетащите StackPanel
в пустое пространство под заголовком вашей страницы. Перетащите другую StackPanel
в предыдущую StackPanel
. Эта StackPanel
будет содержать заголовок истории и количество Digg. Вы хотите, чтобы эти элементы совпали рядом друг с другом, поэтому измените свойство Orientation
на Horizontal
.
Наконец, перетащите TextBlock
и Button
в вашу первую StackPanel
. TextBlock
будет содержать описание истории, в то время как Button
позволит пользователю посетить источник истории. Вам нужно будет сделать некоторые обширные изменения свойств для этих элементов и, вместо того, чтобы проходить через них один за другим, просто убедитесь, что ваша разметка выглядит следующим образом:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
|
<StackPanel Name=»StoryDetails»>
<StackPanel
Orientation=»Horizontal» Name=»StoryDetailsHeader»>
<TextBlock
Name=»NumberDiggs»
Text=»10″ />
<TextBlock
Name=»Title»
Text=»Story Title Goes Here» />
</StackPanel>
<TextBlock
Name=»Description»
Text=»The story description will go here. This text will wrap, as you can see right here.»
TextWrapping=»Wrap» />
<Button
Content=»Read Full Story»
Name=»Link»
Width=»200″ />
</StackPanel>
|
Вы можете видеть, что мы удалили наиболее явные свойства Height
и Width
и изменили свойства Text
и Name
на что-то более описательное. Это выглядит немного некрасиво прямо сейчас, но мы исправим это позже. Если вы все правильно разметили, то ваша панель визуального дизайнера должна выглядеть следующим образом:
На этом этапе основы всех необходимых представлений сделаны. Вы можете нажать F5, чтобы запустить приложение, чтобы убедиться, что все работает, но вы просто получите пустой экран с «Темами» вверху.
Настройка карты навигации
Следующее, что вам нужно сделать, это убедиться, что вы можете направлять пользователей вокруг вашего приложения. Для этого вы будете использовать навигационное отображение Silverlight с несколькими простыми правилами. Откройте файл App.xaml
вашего проекта и поместите курсор внутрь открывающегося элемента Application
и добавьте новое пространство имен следующим образом:
1
|
xmlns:nav=»clr-namespace:System.Windows.Navigation;assembly=Microsoft.Phone»
|
Это относится к пространству имен Windows System Navigation (функция Silverlight) и позволяет использовать различные классы библиотеки, которые существуют в нем. Теперь найдите элемент Application.Resources
в App.xaml
и добавьте следующие элементы:
1
2
3
4
5
6
7
|
<nav:UriMapper x:Key=»UriMapper»>
<nav:UriMapper.UriMappings>
<nav:UriMapping Uri=»/Topics» MappedUri=»/MainPage.xaml» />
<nav:UriMapping Uri=»/Topics/{topic}» MappedUri=»/Views/Stories.xaml?Topic={topic}» />
<nav:UriMapping Uri=»/Story» MappedUri=»/Views/Story.xaml» />
</nav:UriMapper.UriMappings>
</nav:UriMapper>
|
Введенный вами код создает множество отображений URI для представлений в вашем приложении. Они соответствуют списку тем, списку рассказов и подробному представлению истории соответственно. Как видите, навигационное отображение Silverlight позволяет вам определять переменные запроса внутри ваших пользовательских отображений. Это пригодится позже, когда мы начнем заполнять данные.
Вы еще не закончили с отображением URI . Вы должны указать приложению использовать этот UriMapper
, поэтому откройте код App.xaml
, щелкнув стрелку рядом с App.xaml
и открыв App.xaml.cs
Внутри метода App
после вызова InitializePhoneApplication()
добавьте следующий оператор:
RootFrame.UriMapper = Resources ["UriMapper"] как UriMapper;
Это утверждение указывает вашему приложению использовать UriMapper, который вы только что определили в XAML, для своего телефонного приложения. Теперь давайте начнем заполнять некоторые данные.
Заполнение списка тем
Первое, что нам нужно сделать, это заполнить список тем. Мы сделаем это, когда пользователь впервые перейдет на страницу MainPage.xaml
. Чтобы это OnNavigatedTo
, вы переопределите метод OnNavigatedTo
для класса MainPage
. Откройте MainPage.xaml.cs
, нажав на стрелку рядом с MainPage.xaml
. Поместите курсор после конструктора и добавьте следующий код:
защищенное переопределение void OnNavigatedTo (System.Windows.Navigation.NavigationEventArgs e) { base.OnNavigatedTo (е); WebClient digg = new WebClient (); digg.DownloadStringCompleted + = new DownloadStringCompletedEventHandler (digg_DownloadStringCompleted); digg.DownloadStringAsync (новый Uri ("http://services.digg.com/1.0/endpoint?method=topic.getAll")); } void digg_DownloadStringCompleted (отправитель объекта, DownloadStringCompletedEventArgs e) { }
Вы можете видеть, что внутри метода OnNavigatedTo
вы создаете объект WebClient
, назначаете ему обработчик событий для загрузки строки и затем поручаете ему загрузить строку из URL-адреса метода Digg topic.getAll
. Мы знаем, что загружаемая строка будет в формате XML , поэтому мы должны убедиться, что наш обработчик событий может анализировать XML . Для этого мы будем использовать библиотеки Linq, доступные в .NET Framework. Однако прежде чем мы сможем использовать эти библиотечные классы, нам нужно добавить ссылку на библиотеку. Щелкните правой кнопкой мыши элемент «Ссылки» на панели обозревателя решений и выберите «Добавить ссылку…». В System.Xml.Linq
списке выберите System.Xml.Linq
и нажмите «ОК».
Теперь вам просто нужно заполнить обработчик событий, который вы создали. Измените digg_DownloadStringCompleted
чтобы он выглядел следующим образом:
void digg_DownloadStringCompleted (отправитель объекта, DownloadStringCompletedEventArgs e) { if (e.Error! = null) { возвращение; } XElement topicXml = XElement.Parse (e.Result); var themes = из темы в topicXml.Descendants ("тема") выберите новую тему { Имя = тема. Атрибут ("имя"). Значение, ShortName = topic.Attribute ("short_name"). Значение }; TopicsList.ItemsSource = themes; }
Сначала вы проверяете, была ли загрузка успешно завершена. Если это так, то вы анализируете результирующую строку и генерируете набор тем, используя Linq to XML . Если вы заинтересованы, вы можете прочитать больше о Linq to XML на официальном сайте MSDN .
Наконец, вы назначаете свойство ItemsSource
TopicsList
темам, которые вы проанализировали. Если вы видите волнистую линию в разделе «Тема», поместите после нее курсор, щелкните стрелку вниз, которая появляется под словом, и выберите «использование SimpleDigg.Digg». На этом этапе ваши темы заполнены, поэтому запустите эмулятор телефона, нажав клавишу F5, и вы должны увидеть что-то вроде следующего:
Как видите, ваш список заполнен, но правильные данные не отображаются. Давайте позаботимся об этом сейчас.
Шаблоны данных
Шаблон данных — один из самых мощных инструментов в вашем наборе инструментов Silverlight. Они позволяют вам определять разметку, которая должна отображаться для произвольных объектов. На этом этапе мы определим DataTemplates для тем Digg. Откройте App.xaml
и поместите курсор в элемент Application.Resources
. Добавьте следующий элемент:
1
2
3
4
5
|
<DataTemplate x:Key=»TopicTemplate»>
<TextBlock
FontSize=»48″
Text=»{Binding Name}» />
</DataTemplate>
|
Этот DataTemplate содержит простой элемент TextBlock
который связан со свойством Name
отображаемого объекта. Если вы помните, класс Digg.Topic
содержит свойство Name
которого задан атрибут name
возвращаемый из вызова API тем Digg. Вернитесь в свой MainPage.xaml
и найдите элемент ListBox
. Добавьте новое свойство ItemTemplate
в ListBox
следующим образом:
1
|
ItemTemplate=»{StaticResource TopicTemplate}»
|
Эта строка кода указывает приложению использовать ранее созданный ресурс DataTemplate
для отображения объектов Topic, которые составляют коллекцию ListBox
. Если вы нажмете F5 и запустите свое приложение, вы увидите, что названия тем теперь правильно отображаются:
Извлечение и отображение историй
На данный момент мы готовы начать выбирать истории по темам и перечислять их. Во-первых, нам нужно сообщить приложению, что при нажатии на заголовок темы приложение должно перейти к списку рассказов. Откройте MainPage.xaml
и найдите свой элемент ListBox
. Добавьте свойство SelectionChanged
и дайте Visual Studio создать новый обработчик событий. В MainPage.xaml.cs
измените ваш обработчик событий так, чтобы он читал что-то вроде следующего:
private void TopicsList_SelectionChanged (отправитель объекта, SelectionChangedEventArgs e) { Тема раздела = TopicsList.SelectedItem в качестве темы; NavigationService.Navigate (новый Uri ("/ Topics /" + topic.ShortName, UriKind.Relative)); }
Если вы запустите приложение сейчас (нажав F5), вы увидите, что переходите на страницу «Истории» всякий раз, когда выбираете тему. Теперь нам просто нужно заполнить список рассказов и настроить их отображение соответствующим образом. Как мы делали ранее, мы собираемся переопределить метод OnNavigatedTo
чтобы это произошло. Откройте Views/Stories.xaml.cs
и добавьте следующий код:
защищенное переопределение void OnNavigatedTo (System.Windows.Navigation.NavigationEventArgs e) { base.OnNavigatedTo (е); Имя строки; NavigationContext.QueryString.TryGetValue («Тема», имя отсутствует); Клиент WebClient = новый WebClient (); client.DownloadStringCompleted + = new DownloadStringCompletedEventHandler (client_DownloadStringCompleted); client.DownloadStringAsync (новый Uri ("http://services.digg.com/1.0/endpoint?method=story.getAll&topic=" + name)); } void client_DownloadStringCompleted (отправитель объекта, DownloadStringCompletedEventArgs e) { if (e.Error! = null) { возвращение; } XElement storyXml = XElement.Parse (e.Result); var story = из истории в storyXml.Descendants ("история") выберите новый Digg.Story { Title = story.Element ("title"). Значение, Описание = рассказ. Элемент («описание»). Значение, Diggs = Int32.Parse (story.Attribute ("diggs"). Value), Ссылка = story.Attribute ("ссылка"). Значение }; StoriesList.ItemsSource = Stories; }
Многое из этого будет выглядеть знакомым. Единственная часть, которая может выглядеть странно, это получение названия темы. Если вы помните, вы сопоставили /Topics/{topic}
с /Views/Stories.xaml?Topic={topic}
. То есть вы разрешаете передавать строковую переменную запроса Topic в дружественном формате. Когда мы переходили из списка тем, мы передавали краткое имя темы в относительном Uri. В приведенном выше коде при навигации по списку рассказов мы извлекаем эту переменную и используем ее для вызова URL-адреса Digg API с определенной темой.
Мы знаем, что если мы запустим наше приложение в этот момент, мы не получим тот вид, который нам нужен для нашего списка рассказов. Давайте определим другой DataTemplate для использования в этом представлении. Откройте App.xaml
и добавьте следующий код в свой элемент Application.Resources
.
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
|
<DataTemplate x:Key=»StoryTemplate»>
<StackPanel Orientation=»Horizontal» Margin=»5″>
<Grid Background=»Yellow»>
<TextBlock
FontSize=»48″
Foreground=»DarkGray»
Height=»60″
TextAlignment=»Center»
Text=»{Binding Diggs}»
VerticalAlignment=»Center»
Width=»60″ />
</Grid>
<TextBlock
FontSize=»24″
Margin=»10,0,0,0″
MaxWidth=»400″
Padding=»5″
Text=»{Binding Title}»
TextWrapping=»Wrap» />
</StackPanel>
</DataTemplate>
|
Теперь откройте Views/Stories.xaml
и измените элемент ListBox
чтобы он выглядел следующим образом:
<ListBox ItemTemplate = "{StaticResource StoryTemplate}" Name = "StoriesList" ScrollViewer.HorizontalScrollBarVisibility = "Выключено" />
Запустите приложение, нажав клавишу F5, и нажмите на название темы. Подождите немного, и вы увидите ваши истории появляются. Следующее, что нам нужно сделать, это показать подробности истории на странице подробностей.
Отображение подробностей истории
Чтобы отобразить подробности истории, нам нужно сначала разрешить переход на страницу сведений истории, а затем мы обработаем отображение данных. В списке рассказов у нас есть несколько предметов. Когда один из них выбран, мы хотим сохранить этот объект Story
где-нибудь, а затем использовать его на странице сведений истории. Для этого мы добавим обработчик события в событие SelectionChanged
следующим образом:
private void StoriesList_SelectionChanged (отправитель объекта, SelectionChangedEventArgs e) { PhoneApplicationService.Current.State ["Story"] = StoriesList.SelectedItem; NavigationService.Navigate (новый Uri ("/ Story", UriKind.Relative)); }
Здесь вы сохраняете выбранную историю в PhoneApplicationService
класса PhoneApplicationService
в соответствии с рекомендациями лучших моделей выполнения. Если у вас есть красная волнистая линия под PhoneApplicationService
поместите курсор в слово, затем выберите PhoneApplicationService
раскрывающийся список и выберите «использование Microsoft.Phone.Shell».
Теперь нам нужно найти это на другом конце. Откройте файл Views/Story.xaml.cs
и добавьте следующий код, который переопределяет OnNavigatedTo
:
защищенное переопределение void OnNavigatedTo (System.Windows.Navigation.NavigationEventArgs e) { base.OnNavigatedTo (е); Digg.Story story = PhoneApplicationService.Current.State ["Story"] as Digg.Story; this.DataContext = story; }
Здесь вы перехватываете PhoneApplicationService
к представлению сведений истории, извлекаете историю, хранящуюся в PhoneApplicationService
State
в PhoneApplicationService
, а затем удаляете историю из коллекции State
в PhoneApplicationService
. Затем вы устанавливаете DataContext
для представления для извлеченной истории. Это ключ, так как мы будем использовать эту привязку для отображения соответствующих данных.
Откройте свою разметку для просмотра подробностей истории в Views/Story.xaml
. Измените его, чтобы использовать привязки следующим образом:
<StackPanel Name = "StoryDetails"> <StackPanel Name = "StoryDetailsHeader" Ориентация = «Горизонтальный»> <Grid Background = "Yellow" Margin = "5"> <TextBlock FontSize = "48" Foreground = "DarkGray" Высота = "60" TextAlignment = "Центр" Text = "{Binding Diggs}" VerticalAlignment = "Центр" Ширина = "60" /> </ Grid> <TextBlock Маржа = "5" Name = "Название" Text = "{Binding Title}" TextWrapping = "Wrap" /> </ StackPanel> <TextBlock Маржа = "10" Name = "Описание" Text = "{Binding Description}" TextWrapping = "Wrap" /> <Кнопка Содержание = "Читать всю историю" Name = "Ссылка" /> </ StackPanel>
Если вы запустите свое приложение сейчас (нажмите F5), вы сможете перейти от списка тем к списку рассказов до полной информации об истории. Представление подробностей истории должно выглядеть примерно так:
Есть только одна последняя вещь, которую нужно сделать. Добавьте обработчик события click к кнопке Link в Views/Story.xaml
следующим образом:
1
2
3
4
5
|
<Button
Content=»Read Full Story»
Name=»Link»
Click=»Link_Click»
/>
|
Измените ваш обработчик событий Link_Click
, чтобы он читался следующим образом:
private void Link_Click (отправитель объекта, RoutedEventArgs e) { WebBrowserTask task = new WebBrowserTask (); task.URL = (this.DataContext as Digg.Story) .Link; task.Show (); }
Если вы видите красную волнистую линию под WebBrowserTask
, поместите курсор на класс и затем выберите «using Microsoft.Phone.Tasks» из выпадающего списка. Этот код запускает веб-браузер Windows Phone 7 при нажатии на кнопку и перемещает его по URL-адресу статьи.
Заканчивать
На данный момент у вас есть полнофункциональный, хотя и простой, клиент Digg. Вы можете просматривать истории по темам, просматривать подробности и просматривать полную историю в веб-браузере WP7 . В этом уроке мы имеем:
- Созданы классы для хранения данных Digg
- Созданные и настроенные представления приложений с использованием визуального дизайнера
- Настраиваемые URI навигации и используемый сервис навигации Windows Phone 7
- Реализованы шаблоны данных и стили для отображения историй и тем
- Переопределите обработчики событий OnNavigatedTo и OnNavigatedFrmo, чтобы обеспечить соответствующую функциональность для каждой страницы.
- Использовал задачи Windows Phone 7 для запуска веб-браузера
Некоторые из затронутых нами тем далеки от того, чтобы их можно было описать в простом учебном пособии, поэтому вы, вероятно, захотите узнать о них больше. Следующие ресурсы должны помочь вам начать:
- Шаблоны данных
- Стили
- Программирование Windows Phone 7
Я надеюсь, вам понравился этот урок. Если у вас есть какие-либо вопросы или вы хотите увидеть что-то другое в будущем учебнике по Windows Phone 7, сообщите мне об этом в комментариях.