четверг, 20 сентября 2012 г.

Контракты в Windows 8 приложениях (Target)

Итак, давненько я не рассказывал про разработку Windows 8 приложений, но вот, муза вернулась из летнего отпуска, и я постараюсь продолжить эту весьма интересную тему.
Сегодня, я хотел бы рассказать, про одну из самых классных штук, которые появились в Windows 8 приложениях, а именно, о контрактах.
Если на пальцах, то идея проста. Приложение должно делать только то, для чего предназначено, а входные данные оно может получать из других приложений (про которые на момент написания, может быть даже и не известно) и в свою очередь, можно предоставлять данные из своего приложения в другие.

Рассмотрим ситуацию, в которой нам необходимо привязывать некие элементы в нашей программе к людям. Допустим, у нас есть список задач и мы хотим, чтобы можно было на них назначить ответственного.
Создаем новый проект пустого Windows 8 приложения, дважды кликаем на манифесте и переходим в закладку Declarations:
Как видим, пока у нас здесь все пусто. Ну ничего, делаем правый клик на проекте, выбираем "Add New Item" и в открывшемся окне выбираем Share Target Contract:
Нажимаем добавить. У меня Visual Studio спросила, не добавить ли мне связанных файлов, и после моего согласия, в проекте появилась еще одна страница, также притерпела изменения закладка Declarations в манифесте:
Как видим, появилась целых два формата данных которые может принимать наше приложение. Т.к. URI мы принимать не планируем, то удаляем его.
Все, уже на этом этапе, можно запускать наше приложение и тестировать. Для демонстрации, я завел в списке контактов нового человека: Иванова Ивана Ивановича с телефоном +7(111)111-11-11 и почтой ivanov@aaa.ru.
 Собственно, запускаем приложение (чтобы оно установилось в операционной системе), закрываем его и переходим в контакты. Уже здесь, выбираем нашего Иванов, делаем жест вдоль правой границы экрана (мышкой от правого верхнего угла, вдоль правой границы вниз) и выбираем Shared:
В появившемся списке, находим наше приложение и кликнув на него увидим, что оно уже в таком виде готово принимать данные:
Нас такой вид, не очень устраивает, да и не понятно, что кроме Иванов Иван у нас есть. Предлагаю посмотреть на соответствующую страницу и ее ShareTargetPage1 и ее код.
Страница оказывается достаточно скучной, в ней есть грид, в котором собраны компоненты показанные на предыдущей картинке. Удаляем все, оставив только корневой Grid. Переходим к коду. Первый метод, который нам интересен, это метод Activate. Т.к. он был предназначен, под удаленную нами на предыдущем шаге разметку, то и его необходимо почистить. Я оставлю только первую строчку, которая записывает в локальное поле переданную через контракт информацию.
Хорошо, начинаем решение задачи, по привязке переданного нам контакта к некой задаче внутри нашей программы. Для этого, на странице разместим:
1. Заголовок переданный в рамках контракта.
2. Список задач, из которого необходимо выбрать задачу к которой будем привязывать.
3. Сделаем просмотр элементов контракта, чтобы пользователь мог указать, какую информацию необходимо привязать к задаче.
Для начала, добавим в приложение класс описывающий задачу:
 
class AssignedTask
{
    public string Description { get; set; } 

    public string AssignTo { get; set; }
}
Правим разметку на странице, чтобы она решала поставленную задачу:

<Grid Style="{StaticResource LayoutRootStyle}">
    <Grid.RowDefinitions>
        <RowDefinition Height="auto" />
        <RowDefinition Height="auto" />
        <RowDefinition MaxHeight="200" />
        <RowDefinition Height="auto" />
        <RowDefinition Height="auto" />
        <RowDefinition Height="auto" />
        <RowDefinition Height="auto" />
        <RowDefinition Height="1*" />
    </Grid.RowDefinitions>
    <TextBlock Text="{Binding Title}" Margin="5" />
    <TextBlock Text="Задача" Grid.Row="1" Margin="5" />
    <ListBox Grid.Row="2" Margin="5"
                DisplayMemberPath="Description"
                ItemsSource="{Binding TaskList}"
                SelectedItem="{Binding SelectedTask,Mode=TwoWay}" />
    <TextBlock Text="Какие данные данные привязать к задаче" Grid.Row="3" Margin="5" />
    <ListBox Grid.Row="4" Margin="5"
                ItemsSource="{Binding ContactParts}"
                SelectedItem="{Binding SelectedContactPart,Mode=TwoWay}" />  
    <TextBlock Text="{Binding ResultText}" Grid.Row="5" Margin="5" />
    <Button Margin="5" Click="ShareButton_Click" Content="Share" HorizontalAlignment="Right" Grid.Row="6" />
</Grid>
Хорошо, теперь это все надо заполнить данными. Задачи, в рамках тестового примера, я сгенерирую циклом, а вот части контактной информации, получать будем из переданной нам через контракт информации:

public async void Activate(ShareTargetActivatedEventArgs args)
{
    this._shareOperation = args.ShareOperation;
    var shareProperties = this._shareOperation.Data.Properties;
    this.DefaultViewModel["Title"] = shareProperties.Title;
    List<AssignedTask> tasks = new List<AssignedTask>();
    for (int i = 0; i < 10; i++)
    {
        tasks.Add(new AssignedTask() { Description = "Задача " + (i + 1) });
    }
    this.DefaultViewModel["TaskList"] = tasks;
    this.DefaultViewModel["SelectedTask"] = tasks.First();
    this.DefaultViewModel["ContactParts"] = (await _shareOperation.Data.GetTextAsync()).Split('\n');
    this.DefaultViewModel["SelectedContactPart"] = null;
    Window.Current.Content = this;
    Window.Current.Activate();
}
Как видим все просто. Осталось только дописать обработчик клика по кнопке. Но и там ничего сложного нет. Проверяем все ли заполнено правильно, если нет, радуем пользователя. Если все хорошо, то сообщаем что начинаем обработку, обрабатываем и закрываем шаринг:

private void ShareButton_Click(object sender, RoutedEventArgs e)
{
    if (this.DefaultViewModel["SelectedContactPart"] != null)
    {
        this.DefaultViewModel["ResultText"] =
            string.Format(
            "К задаче \"{0}\" добаляем контакт \"{1}\"",
            this.DefaultViewModel["SelectedTask"],
            this.DefaultViewModel["SelectedContactPart"]);
    }
    else
    {
        this.DefaultViewModel["ResultText"] = "Ошибка! Необходимо выбрать контактные данные";
        return;
    }

    this._shareOperation.ReportStarted();
    // Обработка данных
    ((AssignedTask)this.DefaultViewModel["SelectedTask"]).AssignTo = this.DefaultViewModel["SelectedContactPart"].ToString();
    this._shareOperation.ReportCompleted();
}

По получению нашим приложением данных из других приложений пока все. Осталось только показать картинку с работающим контрактом:
 

Комментариев нет:

Отправить комментарий