Перевод: Разработка вашего первого Metrostyle-приложение используя C++, C# или Visual Basic.Net

В Windows 8 вместе с новым меню пуск и новый класс приложений — Metro style Applications. Мне эта тема интересна, а русскоязычных хороших примеров еще слишком мало, поэтому я постараюсь перевести некоторые статьи с dev.windows.com на русский язык. Перевод будет достаточно вольный :)

Приложения Windows Metro style создаются с учетом нового пользовательского интерфейса представленного в Windows 8 Windows Developer Preview. Здесь представлен базовый код и основные концепты которые вам потребуются для создания Metro style приложений используя C++, C# или Visual Basic, так же используя Extensible Application Markup Language (XAML) что бы определить интерфейс и выбранный вами язык что бы написать логику приложения.

Замечание: если вам ближе JavaScript посмотрите Building your first Windows Metro style app using JavaScript.

Цели

В этой теме вы получите краткий обзор возможностей которые вы будете использовать для создания приложений  Metro. используя C++, C# или Visual Basic. Мы создадим простой читатель блогов, который скачивает и показывает информацию из лент RSS 2.0 или Atom 1.0, и покажем как сделать в приложении возможность персонализации. Мы представим концепты, которые являются ядром для платформы разработки, включая «Контролы», Возможности, Разметку, Шаблоны и привязку к данным. Со временем вы закончите это руководство и сможете написать ваше собственное приложение Metro используя C++, C# или Visual Basic. Эта тема может занять у вас около 20 минут на прочтение; Однако, если вы пройдете каждое из упражнений это может занять несколько больше времени.

Hello World

Когда вы создадаете ваше приложение Metro используя C++, C#, или Visual Basic, вы обычно определяете UI (интерфейс) используя XAML и пишете логику вашего приложения связывая логику и интерфейс на выбранном вами языке программирования. Вы найдете XAML UI framework для Metro приложений используя C++, C#, или Visual Basic в пространствах имен Windows.UI.Xaml.* среды выполнения Windows. Если вы писали приложения используя Windows Presentation Foundation (WPF), Silverlight, или Silverlight для Windows Phone, вы уже знакомы с этой моделью программирования, то многое из вашего опыта подойдет для создания и ваших приложений Metro, используя вышеозначенные языки.

Пример ниже демонстрирует XAML-код, который определяет интерфейс для простого приложения «Hello World» и этот код связывается и исходным кодом логики. Даже этот простой пример показывает некоторые концепты, которые так важны для основанного на XAML программной модели, включая частичные классы, разметку, «контролы», свойства и события.

[xml]

<!— XAML —>
<UserControl x:Class=»HelloWorld.MainPage»
xmlns=»http://schemas.microsoft.com/winfx/2006/xaml/presentation»
xmlns:x=»http://schemas.microsoft.com/winfx/2006/xaml»
xmlns:d=»http://schemas.microsoft.com/expression/blend/2008″
xmlns:mc=»http://schemas.openxmlformats.org/markup-compatibility/2006″
mc:Ignorable=»d»
d:DesignHeight=»768″ d:DesignWidth=»1366″>

<Grid x:Name=»LayoutRoot» Background=»#FF0C0C0C»>
<StackPanel>
<Button Content=»Click Me» FontSize=»24″ Width=»200″ Height=»60″ Click=»HelloButton_Click» />
<TextBlock x:Name=»DisplayText» FontSize=»48″ Foreground=»White» />
</StackPanel>
</Grid>
</UserControl>

[/xml]

[csharp]
// C#
namespace HelloWorld
{
partial class MainPage
{
public MainPage()
{
InitializeComponent();
}

private void HelloButton_Click(object sender, RoutedEventArgs e)
{
DisplayText.Text = «Hello World»;
}
}
}
[/csharp]

[vb]
‘ Visual Basic
Partial Public Class MainPage

Public Sub New()
Me.InitializeComponent()
End Sub

Private Sub HelloButton_Click(ByVal sender As Object, ByVal e As RoutedEventArgs)
DisplayText.Text = «Hello World»
End Sub

End Class
[/vb]

[cpp]
// C++
MainPage::MainPage()
{
InitializeComponent();
}

MainPage::~MainPage()
{
}

void HelloWorld::MainPage::HelloButton_Click(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e)
{
DisplayText->Text = «Hello World»;

}
[/cpp]

Приложение Hello World это хорошее начало. Но это очень далеко от реального приложения, есть несколько различных путей что бы изучить построение приложений Metro для Windows Developer Preview. Простое приложение, которое послужит началом это простое приложение для чтения блогов которое скачивает и отображает информацию из ленты RSS 2.0 или Atom 1.0. Представляется целесообразным использовать RSS обеспечиваемую одним из нескольких блогов команды Windows, здесь будет показан блог разработки для Windows.

Создание приложений Windows Metro style в Visual Studio

В этой секции вы узнаете как:

  • создать новый проект Windows Metro style в Microsoft Visual Studio 11 Express for Windows Developer Preview.

Visual Studio это мощная интегрированная среда разработки (IDE) для разработки приложений для Windows. Она обеспечивает управление файлами с исходным кодом; встроенную сборку, развертывание и поддержку при запуске; XAML, Visual Basic, C#, C++, графику и редактирование манифеста; Отладку и многое другое. Существует несколько редакций Visual Studio, но мы будем использовать Visual Studio 11 Express for Windows Developer Preview. Вы можете скачать ее бесплатно вместе с Windows Software Development Kit (SDK) для приложений Metro. В этом пакете содержится всё необходимое, что вам может потребоваться для сборки, упаковки и развертывания вашего приложения Metro.

Что бы создать новый проект Windows Metro style:

  1. Установите Visual Studio 11 Express for Windows Developer Preview. Замечание: Только участники конференции BUILD, а так же подписчики MSDN могут купить инструменты необходимые для построения приложений Metro.
  2. Выберите File > New Project. Откроется диалог New Project.
  3. На панели Installed выберите Visual C++, Visual C# или Visual Basic
  4. Выберите шиблон Windows Metro style 
  5. На центральной панели выберите Application.
  6. Введите имя для проекта.

    новый проект будет создан в Visual Studio 11 Express for Windows Developer Preview.

  7. Нажмите OK. Ваш проект будет создан.

Когда вы создадите ваш проект, Visual Studio создаст файлы проекта и отобразит их в Solution Explorer. Давайте взглянем на файлы которые были созданы шаблоном Application

Имя файла описание
AssemblyInfo (.vb or .cs) Этот файл содержит имя и версию метаданных, которые встраиваются в генерируемую сборку. Этот файл есть только в проектах на C# и Visual Basic
 Package.appxmanifest Этот файл содержит метаданные, которые поясняют ваше приложение. Содержит: отображаемое имя, описание, логотипы и возможности
 Images  Это файлы с логотипом и загрузочным экраном по умолчанию. Вы можете заменить их по своему усмотрению.
 App.xaml, App.xaml.* (.vb, .cs, .cpp)  Эти файлы содержат логику уровня приложения. Класс приложения требует их для того что бы он мог отображать пользовательский интерфейс.
 MainPage.xaml Этот файл — это стартовая страница по умолчанию. Создается для того, что бы вы могли создавать пользовательский интерфейс.
 MainPage.xaml.* (.vb, .cs, .cpp)  Это файл с исходным кодом, который содержит логику для стартовой страницы по умолчанию
 MainPage.xaml.h  Заголовочный файл для MainPage.xaml.cpp. Этот файл содержится только в проектах на C++
 pch.h, pch.cpp  Прекомпилированные заголовочные файлы. Так же содержатся только в проектах на C++.

Определение возможностей приложения

В этой секции вы узнаете как:

  • использовать возможности
  • определять возможности приложения в дизайнере манифеста.

Приложения Metro запускаются в контейнере с ограниченным доступом к файловой системе, ресурсам сети и аппаратному обеспечению. Всякий раз, когда пользователь устанавливает приложение из Windows Store, Windows  просматривает метаданные в файле Package.appxmanifest что бы выяснить, какие возможности нужны приложению для функционирования. Например, приложению нужно получить доступ к данным из интернета, документам из пользовательской библиотеки Документы или к камере и микрофону пользователя. Когда приложение установлено, оно показывает пользователю, какие возможности нужны, и пользователь дает доступ к этим ресурсам. Если приложение не запросило и не получило доступ к ресурса, которые ему нужны, ему не будет разрешен доступ к ресурсам когда пользователь его запустит.

Здесь представлены некоторые общие возможности приложений:

 

Возможность Имя Описание
Internet (Client) internetClient Позволяет вашему приложению получать доступ к интернету и публичным сетям. Многие приложения, которым нужен доступ к интернету используют эту возможность
Internet (Client & Server) internetClientServer Позволяет вашему приложению получать доступ к интернету и публичным сетям,  а так же разрешает  входящие соединения из интернета к вашему приложению. Входящие запросы к критичным портам всё равно запрещены. Это расширение Internet (Client)  Вам не нужно запрашивать разрешение на обе возможности.
Home/Work Networking privateNetworkClientServer Разрешает входящий и исходящий доступ из вашего приложения к доверенным сетям пользователя, таким как домашние сети и сети организации. Входящие запросы к критичным портам всё равно запрещены.
Document Library Access documentsLibrary Предоставляет вашему приложению доступ к библиотеке Документы пользователя, с возможностью добавлять, изменять, или удалять файлы. Ваше приложение может получать доступ к тем типам файлов, которые вы определили в манифесте приложения. Вы не можете получить доступ к библиотеке Документы, на других компьютерах в домашней группе.
Picture Library Access picturesLibrary Предоставляет вашему приложению доступ к библиотеке Изображения пользователя, с возможностью добавлять, изменять, или удалять файлы. Это так же обеспечивает доступ к библиотекам «Изображения» в домашней группе, а так же к изображениям на локально подключенных меда-серверах
Video Library Access videosLibrary Предоставляет вашему приложению доступ к библиотеке Видеозаписи пользователя, с возможностью добавлять, изменять, или удалять файлы. Это так же обеспечивает доступ к библиотекам «Видеозаписи» в домашней группе, а так же к видеофайлам на локально подключенных меда-серверах
Music Library Access musicLibrary Предоставляет вашему приложению доступ к библиотеке Музыка пользователя, с возможностью добавлять, изменять, или удалять файлы. Это так же обеспечивает доступ к библиотекам «Музыка» в домашней группе, а так же к музыкальным файлам на локально подключенных меда-серверах
Default Windows Credentials defaultWindowsCredentials Позволяет приложению соединяться с ресурсами локальной сети, которые требуют полномочия домена
Shared User Certificates sharedUserCertificates Позволяет вашему приложению получить доступ к сертификатам программного и аппаратного обеспечения, таким как сертификаты смарт-карт.
Removable Storage removableStorage Разрешает вашему прилложению доступ к внешним съемным дискам, таким как внешние жесткие диски или USB-флешки. Позволяет добавлять изменять и удалять файлы на устройствах. Ваше приложение может получить доступ только к тем типам файлов, которые были определены в манифесте. Ваше приложение не может получить доступ к съемным дискам на компьютерах домашней группы
Location location Позволяет получать доступ к местоположению пользователя.
Microphone microphone Позволяет вашему приложению получать доступ к микрофону пользователя
Webcam webcam Позволяет вашему приложению получать доступ к веб-камере пользователя
Text Messaging sms Позволяет вашему приложению получить доступ к функциональности обмена текстовыми сообщениями
Near-field Proximity proximity Позволяет приложению использовать связь NFC на устройстве.

Что бы добавить возможность в приложение

  1. В Solution Explorer дважды кликните по файлу Package.appxmanifest. Файл откроется в Application Manifest Designer
  2.  В Application Manifest Designer выберите Capabilites
  3. Поставьте галочки напротив каждой возможности, которая необходима для вашего приложения
  4. Сохраните и закройте файл

Когда вы определите возможности, они будут записаны в Package.appxmanifest.xml в элементе Capabilities. Вы обычно устанавливаете возможности в Application Manifest Designer, как вы только что видели, но если кликнуть правой кнопкой мыши по файлу и выбрать View Code  вы сможете увидеть элемент Capabilites в XML.

[xml]
<Capabilities>
<Capability Name=»internetClient» />
</Capabilities>
[/xml]

Получение информации в приложение

В этой секции вы узнаете как:

  • Создать настраиваемый класс
  • Получать информацию из потока RSS или Atom асинхронно

Сейчас, когда наше приложение может получать информацию из интернета, мы можем написать код что бы получать ленту блога в нашем приложении. Developing for Windows blog экспортирует полный текст сообщений используя оба формата: RSS и Atom. Информация из блога, которую мы хотим отобразить в нашем приложении это: заголовок, автор, дата и содержимое из каждого последнего сообщения в блоге.

Чтобы начать, нам нужно получить информацию для каждого сообщения. К счастью, среда выполнения Windows содержит множество классов, которые делают много работы для получения информации для нас. Эти классы находятся в пространстве имен Windows.Web.Syndication. Эти классы возможно использовать что бы отображать данные напрямую в интерфейсе. Но, в нашем приложении мы создадим собственные классы. Это даст нам некоторую дополнительную гибкость и позволит нам исправлять ленты RSS и Arom каким-либо способом.

Наше приложение является простым, и нам нужно только 2 класса. класс FeedData, содержащий информацию о ленте RSS или Atom. Класс FeedItem содержит информацию о каждом сообщении ленты в отдельности. Здесь представлен код этих классов:
[csharp]// C#
public class FeedData
{
public string Title { get; set; }

// using System.Collections.ObjectModel;
private ObservableCollection<FeedItem> _Items = new ObservableCollection<FeedItem>();
public ObservableCollection<FeedItem> Items
{
get
{
return this._Items;
}
}
}

public class FeedItem
{
public string Title { get; set; }
public string Author { get; set; }
public string Content { get; set; }
public DateTime PubDate { get; set; }

}[/csharp]

 

[vb]

‘ Visual Basic
Public Class FeedData
Public Property Title() As String = String.Empty

‘ Imports System.Collections.ObjectModel
Private _Items As New ObservableCollection(Of FeedItem)()
Public ReadOnly Property Items() As ObservableCollection(Of FeedItem)
Get
Return Me._Items
End Get
End Property
End Class

Public Class FeedItem
Public Property Title() As String = String.Empty
Public Property Author() As String = String.Empty
Public Property Content() As String = String.Empty
Public Property PubDate() As DateTime

End Class

[/vb]

В C++ версии классов FeedData и FeedItem  мы реализуем интерфейс ICustomPropertyProvider что бы связывание данных работало правильно на Windows Developer Preview.

[cpp]

// C++
//
// FeedData.h
// Declaration of the FeedData and FeedItem classes
//

#pragma once

#include «pch.h»
#include <collection.h>

namespace SimpleBlogReader
{
// FeedData
ref class FeedData : public Windows::UI::Xaml::Data::ICustomPropertyProvider, public Platform::IDisposable
{
public:
FeedData();
void OnPropertyChanged(Platform::String^ propertyName);

// ICustomPropertyProvider interface
virtual Windows::UI::Xaml::Data::ICustomProperty^ GetCustomProperty(Platform::String^ name);
virtual Windows::UI::Xaml::Data::ICustomProperty^ GetIndexedProperty(Platform::String^ name, Windows::UI::Xaml::Interop::TypeName typeName);
virtual Platform::String^ GetStringRepresentation();
virtual property Windows::UI::Xaml::Interop::TypeName Type { Windows::UI::Xaml::Interop::TypeName get(); }

private:
Vector<Object^>^ _items;
Platform::String^ _title;

public:
property Vector<Object^>^ Items { Vector<Object^>^ get();  }
property Platform::String^ Title { Platform::String^ get(); void set(Platform::String^ value); }

Object^ TitleGetter(Object^ instance);
};

// FeedItem
ref class FeedItem : public Windows::UI::Xaml::Data::ICustomPropertyProvider, public Platform::IDisposable
{
public:
FeedItem();
void OnPropertyChanged(Platform::String^ propertyName);

// ICustomPropertyProvider interface
virtual Windows::UI::Xaml::Data::ICustomProperty^ GetCustomProperty(Platform::String^ name);
virtual Windows::UI::Xaml::Data::ICustomProperty^ GetIndexedProperty(Platform::String^ name, Windows::UI::Xaml::Interop::TypeName typeName);
virtual Platform::String^ GetStringRepresentation();
virtual property Windows::UI::Xaml::Interop::TypeName Type { Windows::UI::Xaml::Interop::TypeName get(); }

private:
Platform::String^ _title;
Platform::String^ _author;
Platform::String^ _pubDate;
Platform::String^ _content;

public:
property Platform::String^ Title { Platform::String^ get(); void set(Platform::String^ value); }
property Platform::String^ Author { Platform::String^ get(); void set(Platform::String^ value); }
property Platform::String^ PubDate { Platform::String^ get(); void set(Platform::String^ value); }
property Platform::String^ Content { Platform::String^ get(); void set(Platform::String^ value); }

Object^ TitleGetter(Object^ instance);
Object^ AuthorGetter(Object^ instance);
Object^ PubDateGetter(Object^ instance);
Object^ ContentGetter(Object^ instance);
};

// CustomDataProperty: helper class for implementation of ICustomPropertyProvider interface on FeedItem
delegate Platform::Object^ PropertyGetter(Platform::Object^ instance);
delegate void PropertySetter(Platform::Object^ instance, Platform::Object^ value);

ref class CustomDataProperty : public Windows::UI::Xaml::Data::ICustomProperty
{
private:
Platform::String^ _typeName;
Platform::String^ _name;
PropertyGetter^ _propertyGetter;
PropertySetter^ _propertySetter;

public:
CustomDataProperty(Platform::String^ typeName, Platform::String^ Name, PropertySetter^ PropertySetter, PropertyGetter^ PropertyGetter);
virtual property Windows::UI::Xaml::Interop::TypeName Type { virtual Windows::UI::Xaml::Interop::TypeName get(); }
virtual property Platform::String^ Name { virtual Platform::String^ get(); }
virtual property bool CanRead { virtual bool get(); }
virtual property bool CanWrite { virtual bool get(); }
virtual Platform::Object^ GetValue(Platform::Object^ instance);
virtual void SetValue(Object^ instance, Platform::Object^ value);
virtual void SetIndexedValue(Platform::Object^ instance, Platform::Object^ value, Platform::Object^ index);
virtual Platform::Object^ GetIndexedValue(Platform::Object^ instance, Platform::Object^ value);
};
}

[/cpp]

[cpp]

// C++
// FeedData.cpp
// Implementation of the FeedData and FeedItem classes
//
#include «pch.h»
#include «FeedData.h»

using namespace Platform;
using namespace Windows::Foundation;
using namespace Windows::Foundation::Collections;
using namespace Windows::UI::Xaml;
using namespace Windows::UI::Xaml::Controls;
using namespace Windows::UI::Xaml::Data;
using namespace Windows::UI::Xaml::Interop;
using namespace SimpleBlogReader;

// FeedData
FeedData::FeedData()
{
_title = «»;
_items = ref new Vector<Object^>();
}

void FeedData::OnPropertyChanged(String^ propertyName)
{
}

Vector<Object^>^ FeedData::Items::get()
{
return this->_items;
}

Object^ FeedData::TitleGetter(Object^ instance)
{
auto object = (FeedData^)instance;
return PropertyValue::CreateString(object->Title);
}

String^ FeedData::Title::get()
{
return this->_title;
}

void FeedData::Title::set(String^ value)
{
if (this->_title != value)
{
this->_title = value;
this->OnPropertyChanged(«Title»);
}
}

// FeedData — ICustomPropertyProvider interface
ICustomProperty^ FeedData::GetIndexedProperty(String^ name, TypeName typeName)
{
throw ref new NotImplementedException();
}

String^ FeedData::GetStringRepresentation()
{
throw ref new NotImplementedException();
}

TypeName FeedData::Type::get()
{
throw ref new NotImplementedException();
}

ICustomProperty^ FeedData::GetCustomProperty(String^ name)
{
if (name == «Title»)
{
return ref new CustomDataProperty(«String», «Title», nullptr, ref new PropertyGetter(this, &FeedData::TitleGetter));
}
return nullptr;
}

//
// FeedItem
//
FeedItem::FeedItem()
{
_title = «»;
_author = «»;
_pubDate = «»;
_content = «»;
}

void FeedItem::OnPropertyChanged(String^ propertyName)
{
}

Object^ FeedItem::TitleGetter(Object^ instance)
{
auto object = (FeedItem^)instance;
return PropertyValue::CreateString(object->Title);
}

String^ FeedItem::Title::get()
{
return this->_title;
}

void FeedItem::Title::set(String^ value)
{
if (this->_title != value)
{
this->_title = value;
this->OnPropertyChanged(«Title»);
}
}

Object^ FeedItem::AuthorGetter(Object^ instance)
{
auto object = (FeedItem^)instance;
return PropertyValue::CreateString(object->Author);
}

String^ FeedItem::Author::get()
{
return this->_author;
}

void FeedItem::Author::set(String^ value)
{
if (this->_author != value)
{
this->_author = value;
this->OnPropertyChanged(«Author»);
}
}

Object^ FeedItem::PubDateGetter(Object^ instance)
{
auto object = (FeedItem^)instance;
return PropertyValue::CreateString(object->PubDate);
}

String^ FeedItem::PubDate::get()
{
return this->_pubDate;
}

void FeedItem::PubDate::set(String^ value)
{
if (this->_pubDate != value)
{
this->_pubDate = value;
this->OnPropertyChanged(«PubDate»);
}
}

Object^ FeedItem::ContentGetter(Object^ instance)
{
auto object = (FeedItem^)instance;
return PropertyValue::CreateString(object->Content);
}

String^ FeedItem::Content::get()
{
return this->_content;
}

void FeedItem::Content::set(String^ value)
{
if (this->_content != value)
{
this->_content = value;
this->OnPropertyChanged(«Content»);
}
}

//
// FeedItem — ICustomPropertyProvider interface
//
ICustomProperty^ FeedItem::GetIndexedProperty(String^ name, TypeName typeName)
{
throw ref new NotImplementedException();
}

String^ FeedItem::GetStringRepresentation()
{
throw ref new NotImplementedException();
}

TypeName FeedItem::Type::get()
{
throw ref new NotImplementedException();
}

ICustomProperty^ FeedItem::GetCustomProperty(String^ name)
{
if (name == «Title»)
{
return ref new CustomDataProperty(«String», «Title», nullptr, ref new PropertyGetter(this, &FeedItem::TitleGetter));
}
else if (name == «Author»)
{
return ref new CustomDataProperty(«String», «Author», nullptr, ref new PropertyGetter(this, &FeedItem::AuthorGetter));
}
else if (name == «PubDate»)
{
return ref new CustomDataProperty(«String», «PubDate», nullptr, ref new PropertyGetter(this, &FeedItem::PubDateGetter));
}
else if (name == «Content»)
{
return ref new CustomDataProperty(«String», «Content», nullptr, ref new PropertyGetter(this, &FeedItem::ContentGetter));
}
return nullptr;
}

// CustomDataProperty
CustomDataProperty::CustomDataProperty(String^ typeName, String^ Name, PropertySetter^ PropertySetter, PropertyGetter^ PropertyGetter)
{
_typeName = typeName;
_name = Name;
_propertyGetter = PropertyGetter;
_propertySetter = PropertySetter;
}

TypeName CustomDataProperty::Type::get()
{
TypeName t;
t.Name = _typeName;
t.Kind = TypeKind::Primitive;
return t;
}

String^ CustomDataProperty::Name::get()
{
return _name;
}

bool CustomDataProperty::CanRead::get()
{
return (_propertyGetter != nullptr);
}

bool CustomDataProperty::CanWrite::get()
{
return (_propertySetter != nullptr);
}

Object^ CustomDataProperty::GetValue(Object^ instance)
{
return _propertyGetter(instance);
}

void CustomDataProperty::SetValue(Object^ instance, Object^ value)
{
_propertySetter(instance, value);
}

void CustomDataProperty::SetIndexedValue(Object^ instance, Object^ value, Object^ index)
{
throw ref new NotImplementedException;
}

Object^ CustomDataProperty::GetIndexedValue(Object^ instance, Object^ value)
{
throw ref new NotImplementedException;
}
[/cpp]

Получение информации из ленты

У нас есть классы для хранения информации, но давайте вернемся к получению ленты блога. Windows.Web.Syndication.SyndicationClient получает полный обработанный поток RSS или Atom, и вместо  утомительных объяснений по поводу обработки XML, мы можем переместиться к более интересным проблемам. Класс SyndicationClient обеспечивает только один путь получения ленты, и этот путь асинхронный. Асинхронная программная модель является ведущей в среде выполнения Windows, она помогает приложениям не зависать в ожидании ответа. Можно было ожидать наибольшую сложность при использовании асинхронных методов, но к счастью, эта работа сделана за нас.

Использование await in C# and Visual Basic

код использование ключевого слова await в C# и Visual Basic, для получения ленты асинхронным способом похож на код если бы мы хотели получить ленту синхронным способом. Давайте посмотрим.

[csharp]

// C#
private async Task GetFeedAsync(string feedUriString)
{
// using Windows.Web.Syndication;
SyndicationClient client = new SyndicationClient();
Uri feedUri = new Uri(feedUriString);

try
{
SyndicationFeed feed = await client.RetrieveFeedAsync(feedUri);
FeedData feedData = new FeedData();
feedData.Title = feed.Title.Text;

foreach (SyndicationItem item in feed.Items)
{
FeedItem feedItem = new FeedItem();
feedItem.Title = item.Title.Text;
feedItem.PubDate = item.PublishedDate.DateTime;
feedItem.Author = item.Authors[0].Name.ToString();
if (feed.SourceFormat == SyndicationFormat.Atom10)
{
feedItem.Content = item.Content.Text;
}
else if (feed.SourceFormat == SyndicationFormat.Rss20)
{
feedItem.Content = item.Summary.Text;
}
feedData.Items.Add(feedItem);
}
this.DataContext = feedData;
ItemListView.SelectedIndex = 0;
}
catch (Exception ex)
{
// Log Error.
TitleText.Text = ex.Message;
}
}

[/csharp]

[vb]

‘ Visual Basic
Private Async Function GetFeedAsync(FeedUriString As String) As Task
‘ Imports Windows.Web.Syndication
Dim Client As New SyndicationClient
Dim FeedUri As New Uri(FeedUriString)

Try
Dim Feed As SyndicationFeed = Await Client.RetrieveFeedAsync(FeedUri)
Dim FeedData As New FeedData
FeedData.Title = Feed.Title.Text

For Each Item As SyndicationItem In Feed.Items
Dim FeedItem As New FeedItem
FeedItem.Title = Item.Title.Text
FeedItem.PubDate = Item.PublishedDate.DateTime
FeedItem.Author = Item.Authors(0).Name.ToString()

If Feed.SourceFormat = SyndicationFormat.Atom10 Then
FeedItem.Content = Item.Content.Text
ElseIf Feed.SourceFormat = SyndicationFormat.Rss20 Then
FeedItem.Content = Item.Summary.Text
End If

FeedData.Items.Add(FeedItem)
Next

Me.DataContext = FeedData
ItemListView.SelectedIndex = 0
Catch Ex As Exception
‘ Log Error.
TitleText.Text = Ex.Message
End Try
End Function
[/vb]

Первое замечание заключается в том, что мы добавили ключевое слово async в сигнатуру метода. Вы можете использовать ключевое слово await только в методе, который объявлен как async.

[csharp]

// C#
private async Task GetFeedAsync(string feedUriString)
[/csharp]

[vb]

‘ Visual Basic
Private Async Function GetFeedAsync(FeedUriString As String) As Task
[/vb]

Далее, мы вызываем метод SyndicationClient.RetrieveFeedAsync что бы получить SyndicationClient, который содержит информацию из RSS или Atom, которую мы хотим получить. Ключевое слово await здесь говорит компилятору, чтобы он сделал множество работы за нас «за кулисами»

[csharp]

// C#
SyndicationFeed feed = await client.RetrieveFeedAsync(feedUri);

[/csharp]

[vb]

‘ Visual Basic
Dim Feed As SyndicationFeed = Await Client.RetrieveFeedAsync(FeedUri)
[/vb]

По существу, компилятор планирует оставшуюся часть после вызова возврата чтобы выполнить, когда функция вернет значение. Затем оно сразу возвращает управление вызываемому потоку, обычно потоку интерфейса и приложение остается рабостоспособным. Когда возвращается RetrieveFeedAsync, другой код в нашем методе уже исполнен. И, что немаловажно, он выполнен в том же потоке, что и оригинальный вызов (из потока интерфейса), и нам не нужно беспокоиться о использовании диспетчера для обновления интерфейса в этом коде.

После того как, мы получили SyndicationFeed с информацией мы хотим скопировать интересующие нас части в наши классы FeedData и FeedItem. Мы определяем элемент FeedData как DataContext страницы, и мы должны  связать его с интерфейсом. Мы оборачиваем весь код в блок  Try… Catch, чтобы перехватывать любые исключения которые могут случиться при получении ленты

Мы хотим что бы наше приложение загружало Developing for Windows blog автоматически, при запуске. Для простоты мы можем вызвать наш метод GetFeedAsync из страницы конструктора чтобы это сделать. Мы вставили URL из экспорта Atom, потому, что он включает имя автора, которое мы хотим показать, а в RSS эти данные отсутствуют.

[csharp]

// C#
public MainPage()
{
InitializeComponent();
GetFeedAsync(«http://windowsteamblog.com/windows/b/developers/atom.aspx»);
}

[/csharp]

[vb]

‘ Visual Basic
Public Sub New()
InitializeComponent()
GetFeedAsync(«http://windowsteamblog.com/windows/b/developers/atom.aspx»)
End Sub

[/vb]

[cpp]

// C++
MainPage::MainPage()
{
InitializeComponent();
GetFeedAsync(«http://windowsteamblog.com/windows/b/developers/atom.aspx»);
}
[/cpp]

получение потока из C++

В C++, новостная лента доставляется асинхронно. Но вместо использования await, мы будем использовать делигат AsyncOperationWithProgressCompletedHandler  названный Feed_Done. Этот делигат содержит код который будет исполнться после возвращения ленты.

[cpp]

// C++
// Decalaration in MainPage.xaml.h
void GetFeedAsync(Platform::String^ feedUriString);
void Feed_Done(Windows::Foundation::IAsyncOperationWithProgress
<Windows::Web::Syndication::SyndicationFeed^,Windows::Web::Syndication::RetrievalProgress>^);

// Implementation in MainPage.xaml.cpp
void SimpleBlogReader::MainPage::GetFeedAsync(Platform::String^ feedUriString)
{
client = ref new SyndicationClient;
auto feedOperation = client->RetrieveFeedAsync(ref new Uri(feedUriString));

feedOperation->Completed = ref new AsyncOperationWithProgressCompletedHandler
<SyndicationFeed^,RetrievalProgress>(this, &MainPage::Feed_Done);
feedOperation->Start();
}

void MainPage::Feed_Done(IAsyncOperationWithProgress<SyndicationFeed^,RetrievalProgress>^ op)
{

if(op->Status == AsyncStatus::Completed) {
auto feed = op->GetResults();

FeedData^ feedData = ref new FeedData();
feedData -> Title = feed->Title->Text;

// Used to format PubDate
auto dtf = ref new Windows::Globalization::DateTimeFormatting::DateTimeFormatter
(YearFormat::Full, MonthFormat::Numeric, DayFormat::Default, DayOfWeekFormat::None);
for(int i=0; i< feed->Items->Size; i++) {
FeedItem^ feedItem = ref new FeedItem();
feedItem->Title = feed->Items->GetAt(i)->Title->Text;
feedItem->PubDate = dtf->Format(feed->Items->GetAt(i)->PublishedDate);
feedItem->Author = feed->Items->GetAt(i)->Authors->GetAt(0)->Name;
if (feed->SourceFormat == SyndicationFormat::Atom10)
{
feedItem->Content = feed->Items->GetAt(i)->Content->Text;
}
else if (feed->SourceFormat == SyndicationFormat::Rss20)
{
feedItem->Content = feed->Items->GetAt(i)->Summary->Text;
}
feedData->Items->Append(feedItem);
}

// Bind the collection to the list
this->DataContext = feedData;
this->ItemListView->ItemsSource = feedData->Items;
this->ItemListView->SelectedIndex = 0;
}
}

[/cpp]

Определение интерфейса используя XAML

В этой секции вы узнаете:

  • Какие панели вы можете использовать что бы определять разметку в XAML
  • Как определять строки и колонки в Grid
  • Как использовать StackPanel.

Разметка приложения определяет размер и позиционирование объектов в вашем приложении. Что бы определить местоположение визуальных объектов вы должны положить их на Panel или на другой объект, являющийся контейнером. Разметка XAML обеспечивает различные контролы для Panel, такие как Grid, Canvas, и StackPanel, которые служат контейнерами и в которых размещаются другие элементы управления (контролы)

Разметка XAML поддерживает как абсолютную так и динамическую разметку. В абсолютной разметке позиция ваших элементов управления определяется, используя координаты x и y (например при использования Canvas). В динамической разметке, контейнер разметки и элементов управления могут автоматически изменять размер и отвечать на изменения размера окна приложения (например при использовании в StackPanel или в Grid). На практике вы обычно определяете разметку вашего приложения, комбинируя абсолютные и динамические методы, и встраиваете панели в другие панели.

Типичная разметка, полезная для такого приложения, как наше, выглядит примерно так, с заголовком наверху, листом с сообщениями слева и содержанием выбранного сообщения справа.

По умолчанию чистое приложение содержит  Grid названный LayoutRoot. Чтобы добиться нашего намеченного интерфейса мы разделим Grid на две строки. Верхняя строка будет содержать заголовок блога, а в следующей мы встроим другой Grid, разделенный на 2 колонки, и добавим больше контейнеров для отображения содержимого блога.

[xml]

<!— XAML —>
<Grid x:Name=»LayoutRoot» Background=»#FF0C0C0C»>
<Grid.RowDefinitions>
<RowDefinition Height=»140″ />
<RowDefinition Height=»*» />
</Grid.RowDefinitions>

<!— Title —>

<!— Content —>
<Grid Grid.Row=»1″>
<Grid.ColumnDefinitions>
<ColumnDefinition Width=»2*» />
<ColumnDefinition Width=»3*» />
</Grid.ColumnDefinitions>

<!— Left column —>
<ListView x:Name=»ItemListView» />

<!— Right column —>
<Grid Grid.Column=»1″ >
<Grid.RowDefinitions>
<RowDefinition Height=»Auto» />
<RowDefinition Height=»*» />
</Grid.RowDefinitions>
</Grid>
</Grid>
</Grid>

[/xml]

Давайте взглянем на этот XAML код более подробно. Что бы определить строки в Grid, вы добавили объекты RowDefinition в коллекцию Grid.Rows. Вы можете настроить параметры RowDefinition для задания внешнего вида строк. Вы добавили колонки в некотром месте используя объекты ColumnDefinition, а так же коллекцию Grid.Columns.

В  XAML, определения строк выглядят так:

[xml]

<Grid.RowDefinitions>
<RowDefinition Height=»140″/>
<RowDefinition Height=»*»/>
</Grid.RowDefinitions>

[/xml]

Свойство Height="140 настраивает первою строку (row 0), устанавливая высоту в 100 пикселей. Эта высота не меняется независимо от размера содержимого строки, которое содержится в ней. Height="*" настраивает определение второй строки (row 1), говоря, что всё место, которое осталось после row 0 будет занято. Этот выбор называется «звездное изменение размера». Мы так же используем его в определении колонок во втором Grid. Настройки ширины Width="2*" and Width="3*" говорят элементу Grid делить себя на 5 равных частей. Две части используются для первой колонки, и третья часть используется для второй колонки.

Чтобы позиционировать элемент в Grid, вы должны настроить Grid.Row и Grid.Column так как он использует настройки таблицы. Запомните, что нумерация сток и столбцов начинается с ноля, и если вы не определили ничего, то элемент будет помещен в первую строку и первый стобец.

Элемент <Grid Grid.Row="1"> встраивает Grid в нижнюю строку LayoutRoot. Этот Grid разделен на две колонки.

Элемент <ListView Grid.Column="0"> добавляет ListView в левую ведущую колонку под Grid. Элемент <Grid Grid.Column="1"> добавляет другой Grid в правую ведущую колонку под Grid. Мы делим этот Grid на две строки. Настройка Height="Auto" говорит, что нужно растягивать строку в зависимости от содержащегося контента.

Последняя часть нашего интерфейса нуждается в панели, на которой можно отображать сообщения из блога.

Добавить комментарий