Статьи

Использование переносимых библиотек классов с Windows 8 / Windows Phone 8 MVVM

Вступление

Portable Class Libraries (PCL) поддерживают кросс-платформенную разработку приложений .NET Framework. С помощью Portable Class Libraries вы можете создавать переносимые сборки, которые совместно используют код с Windows 8, Windows Phone, Xbox 360 и другими приложениями .NET. Если вы решите не использовать их, то вы должны указать один тип приложения и при необходимости переработать библиотеку классов для других типов приложений. PCL сохраняют эту работу, позволяя создавать сборки, совместно используемые на разных платформах. В этой статье мы собираемся использовать шаблон MVVM (Model-View-View-Model) с переносимыми библиотеками классов, предназначенными для приложений Windows 8 и многого другого! Давайте начнем.

Что требуется?

Перед тем, как начать, нам нужно убедиться, что у вас есть необходимые инструменты, чтобы начать использовать Portable Class Libraries. Пожалуйста, посмотрите на таблицу, указанную ниже, чтобы узнать, какие действия необходимо выполнить перед началом этого урока.

Версия Visual Studio

Необходимые файлы для загрузки

VS2012

Ничего — все уже установлено.

VS2010

Портативные библиотечные инструменты

VS2008 и ранее

Не поддерживается.

Из этой таблицы мы можем быстро увидеть, что для использования PCL требуется VS2010 или новее. Более ранние версии Visual Studio не поддерживаются, так как они не поддерживают более поздние версии .NET Framework.

Начиная

После того, как все установлено или вы используете Visual Studio 2012 (в этом случае все уже установлено), настало время начать. В моем примере приложения я буду использовать Visual Studio 2012, но функциональность останется прежней, даже если вы используете Visual Studio 2010 и у вас установлены Portable Library Tools.

Далее выберите File-> New Project и в разделе «Шаблоны» выберите Visual C #, а затем Portable Class Library, как показано на рисунке 1.

Рисунок 1: Диалог нового проекта в Visual Studio 2012.

Я собираюсь назвать свой проект DZonePCL и нажать кнопку ОК. (Я рекомендую вам сделать то же самое, если вы планируете копировать / вставлять фрагменты кода). Следующее диалоговое окно, которое мы видим, это «Добавить Portable Class Library», как показано на рисунке №2.

Рисунок 2: Диалог «Добавить переносимую библиотеку классов».

Отсюда мы видим, что у нас есть несколько целевых платформ, доступных нам: .NET Framework, Silverlight, Windows Phone, приложения Window Store и даже Xbox 360. Мы собираемся оставить здесь настройки по умолчанию и нацелить все, кроме Xbox 360, и нажать ОК. Результат моего выбора будет диктовать доступные мне эталонные сборки, которые отвечают всем требованиям этих платформ.

После запуска нашего проекта у нас будет просто содержать пустую библиотеку классов и одну ссылку на .NET Portable Subset.

Давайте продолжим и создадим новый класс под названием DelegateCommand. Вставьте в него следующий фрагмент кода, перезаписав все.

Примечание. Если вы не назвали свой проект DZonePCL, вам нужно изменить пространство имен, чтобы оно соответствовало названию вашего проекта.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Input;

namespace DZonePCL
{
    public class DelegateCommand : ICommand
    {
        Func<object, bool> _canExecute;
        Action<object> _execute;

        public DelegateCommand(Action<object> execute, Func<object, bool> canExecute)
        {
            this._canExecute = canExecute;
            this._execute = execute;
        }

        public bool CanExecute(object parameter)
        {
            return true;
        }

        public event EventHandler CanExecuteChanged;

        public void Execute(object parameter)
        {
            _execute(parameter);
        }
    }
}

Это стандартный код, который можно найти во многих проектах, реализующих MVVM. Команды являются критически важной частью для проектов, в которых реализован шаблон MVVM, поскольку они обеспечивают разделение между пользовательским интерфейсом и логикой. Думайте о командах в MVVM как о способе избежать выделения кода на ваших страницах.

Теперь пришло время пойти дальше и создать нашу ViewModel, которая будет использоваться в различных приложениях. Сначала переименуйте Class1.cs в CustomerViewModel.cs, затем вставьте следующий код, перезаписав все в файле:

using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Windows.Input;

namespace DZonePCL
{
    public class CustomerViewModel : INotifyPropertyChanged
    {
        private ObservableCollection<string> _messages = new ObservableCollection<string>();

        public ObservableCollection<string> Messages
        {
            get { return _messages; }
            set { _messages = value; RaisePropertyChanged("Messages"); }
        }

        public CustomerViewModel()
        {
            SaveCustomerCommand = new DelegateCommand((obj) =>
                {
                    Messages.Add("Saved: " + obj.ToString());
                }, null);
        }

        public ICommand SaveCustomerCommand { get; set; }

        private void RaisePropertyChanged(string propertyName)
        {
            if (null != PropertyChanged)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }
        }
        public event PropertyChangedEventHandler PropertyChanged;        
    }
}

Отсюда вы можете видеть, что у нас есть очень простая реализация CustomerViewModel. Этот класс реализует интерфейс INotifyPropertyChanged и содержит коллекцию ObservableCollection, которая поддерживает список клиентов, сохраняемых пользователем. Следует отметить, что конструктор CustomerViewModel содержит SaveCustomerCommand, который создает новый экземпляр нашей DelegateCommand, добавляя объект, введенный в ObservableCollection.

Создание нашего приложения для Windows 8

Теперь, когда мы создали нашу Portable Class Library, пришло время создать наше приложение для Магазина Windows, которое будет его использовать. Начните с того, что щелкните правой кнопкой мыши на решении, затем нажмите «Добавить», затем «Новый проект». Мы собираемся выбрать Visual C # -> Магазин Windows -> Пустое приложение (XAML), дать ему имя DZoneWin8XAML и нажать «ОК».

Когда наше приложение загрузится, нам нужно добавить ссылку на нашу Portable Class Library. В обозревателе решений щелкните правой кнопкой мыши ссылку DZoneWin8XAML и выберите «Добавить ссылку». Затем выберите Solution -> Projects и проверьте запись «DZonePCL», как показано на рисунке 3.

Рисунок 3: Добавление переносимой библиотеки классов в наше приложение Windows 8 XAML / C #. 

Чтобы разрешить доступ к недавно указанному проекту DZonePCL, откройте файл MainZage.xaml в DZoneWin8XAML и добавьте следующее пространство имен в атрибуты элемента Page:

xmlns:portable="using:DZonePCL"

Теперь нам нужно настроить Page.Resources нашей ViewModel, предоставляя ключ, который мы можем использовать в XAML. Добавьте следующее в содержимое элемента Page непосредственно перед сеткой:

    <Page.Resources>
        <portable:CustomerViewModel x:Key="vm" />
    </Page.Resources>

Наконец, мы можем настроить наш пользовательский интерфейс, заменив Grid следующим кодом:

    <Grid Background="{StaticResource ApplicationPageBackgroundThemeBrush}">
    	<Grid.ColumnDefinitions>
    		<ColumnDefinition Width="681*"/>
    		<ColumnDefinition Width="685*"/>
    	</Grid.ColumnDefinitions>
            <StackPanel HorizontalAlignment="Center" VerticalAlignment="Center">
      
    		<TextBox x:Name="txtCustomerName" Margin="0,0,0,43"/>
    		<Button Content="Save Customer" Command="{Binding SaveCustomerCommand, Source={StaticResource vm}}"
    			CommandParameter="{Binding Text, ElementName=txtCustomerName}" />
    	</StackPanel>
            <ListView ItemsSource="{Binding Messages, Source={StaticResource vm}}" Grid.Column="1"/>
      
    </Grid>

В этом примере мы позволим пользователю ввести имя клиента и нажать кнопку «Сохранить клиента». Используя Команды, мы можем привязаться к SaveCustomerCommand в нашей ViewModel (определенной в нашей Portable Class Library) и выполнить ее без какого-либо кода позади. Мы также настроили CommandParameter для передачи текста в элементе управления txtCustomerName. Наконец, мы используем новый элемент управления в Windows 8 под названием ListView и привязываем ItemSource к ObservableCollection, называемому «Messages» из нашей ViewModel. Наш пользовательский интерфейс теперь выглядит следующим образом, как показано на рисунке 4.

Рисунок 4: Наш пользовательский интерфейс для приложения Windows 8 XAML с использованием переносимых библиотек классов.  Элемент управления ListView не отображается, поскольку элементы еще не добавлены.

Давайте посмотрим на этот простой интерфейс в действии. Сначала установите DZoneWin8XAML в качестве запускаемого проекта, щелкнув правой кнопкой мыши проект и выбрав «Установить как стартовый проект». Запустите проект и добавьте несколько клиентов. Теперь приложение должно выглядеть примерно так, как показано на рисунке 5.

После нажатия кнопки «Сохранить клиента» вы заметите, что ваши элементы анимируются в элемент управления ListView. В этом прелесть использования Windows 8. Анимации встроены в элемент управления, и нам нужно заниматься только логикой. Вы должны были заметить, что у нас нет кода на нашей странице с выделенным кодом (MainPage.xaml.cs), и у нас есть истинное разделение проблем с помощью шаблона MVVM и Portable Class Libraries.

Красота портативных классов

Время для повторного использования кода! Если вы помните, в начале этой статьи мы выбрали приложения .NET Framework, Silverlight, Windows Phone и Windows Store. Модель представления, которую мы создали в нашей Portable Class Library, готова к повторному использованию любым из этих типов приложений, как если бы она была в нашем приложении для Магазина Windows. Если у вас установлена ​​версия 8.0 Windows Phone SDK, создайте новый проект Windows Phone 8, снова сделав его стартовым проектом, и добавьте ссылку на тот же проект DZonePCL. Затем нам нужно только внести аналогичные изменения в MainPage.xaml, которые мы сделали в проекте DZoneWin8XAML. Единственное предостережение для этого — разные форм-факторы, может потребоваться новый макет пользовательского интерфейса, а некоторые элементы управления могут не существовать на других платформах (таких как ListView, который мы использовали в нашем приложении Windows Store).Ниже представлен XAML, используемый в проекте Windows Phone 8, который использует нашу Portable Class Library с совершенно новым элементом управления в Windows Phone 8, который называется LongListSelector.

<phone:PhoneApplicationPage
    x:Class="DZoneWP8.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone"
    xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:portable="clr-namespace:DZonePCL;assembly=DZonePCL"
    mc:Ignorable="d"
    FontFamily="{StaticResource PhoneFontFamilyNormal}"
    FontSize="{StaticResource PhoneFontSizeNormal}"
    Foreground="{StaticResource PhoneForegroundBrush}"
    SupportedOrientations="Portrait" Orientation="Portrait"
    shell:SystemTray.IsVisible="True">

    <phone:PhoneApplicationPage.Resources>
        <portable:CustomerViewModel x:Name="vm"/>
    </phone:PhoneApplicationPage.Resources>

    <Grid x:Name="LayoutRoot" Background="Transparent">      
        
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="*"/>
        </Grid.RowDefinitions>

        <StackPanel x:Name="TitlePanel" Grid.Row="0" Margin="12,17,0,28">
            <TextBlock Text="DZONE" Style="{StaticResource PhoneTextNormalStyle}" Margin="12,0"/>
            <TextBlock Text="pcl demo" Margin="9,-7,0,0" Style="{StaticResource PhoneTextTitle1Style}"/>
        </StackPanel>
        <Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
        	<Grid.RowDefinitions>
        		<RowDefinition Height="200*"/>
        		<RowDefinition Height="407*"/>
        	</Grid.RowDefinitions>
            <StackPanel Orientation="Vertical" VerticalAlignment="Center">
        		<TextBox x:Name="txtCustomerName" RenderTransformOrigin="0.5,0.5" UseLayoutRounding="False" d:LayoutRounding="Auto"/>
        		<Button Content="Save Customer" Command="{Binding SaveCustomerCommand, Source={StaticResource vm}}"
        			CommandParameter="{Binding Text, ElementName=txtCustomerName}" />
        	</StackPanel>
            <phone:LongListSelector ItemsSource="{Binding Messages, Source={StaticResource vm}}" Grid.Row="1"/>
        </Grid>
     </Grid>

</phone:PhoneApplicationPage>

После установки этого проекта в наш стартовый проект и ввода тех же данных наше приложение выглядит как на рисунке 6.

Рисунок 6: Наш проект Windows Phone 8 с использованием Portable Class Libraries.

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

Вывод

Надеемся, что к настоящему времени вы увидели мощь переносимых библиотек классов с MVVM в своих приложениях. Мы прошли через этапы создания Portable Class Library, нацеленной на несколько фреймворков и создание ViewModel, которой можно делиться повсюду. Мы использовали Portable Class Library в приложениях Windows 8 и Windows Phone 8, используя мощные механизмы связывания XAML. Если у вас есть какие-либо вопросы, не стесняйтесь оставлять их в комментариях ниже. Вы также можете подписаться на меня в Твиттере на  mbcrump  или не отставать от моего блога, посетив  michaelcrump.net .

СКАЧАТЬ КОД для этого урока