Pull to refresh

Как использовать PivotViewer для Silverlight в реальном проекте (часть II)

Lumber room
Этот пост — окончание статьи Как использовать PivotViewer для Silverlight в реальном проекте.

Теперь в нашем приложении уже есть страница, которая может отобразить тестовую коллекцию данных (наш прототип). Переходим к следующему шагу…

Шаг 4-й, программное формирование xml с данными и изображений в Deep Zoom формате


Нам нужно сформировать .cxml файл с данными в xml и преобразовать изображения элементов в Deep Zoom формат. В принципе, xml легко можно создать при помощи стандартных .NET классов, а для работы с Deep Zoom воспользоваться библиотекой Deep ZoomTools.dll (входит в состав Deep Zoom Composer). Но есть еще более удобный способ — Pauthor. Этот проект включает в себя как .dll, которую можно вызывать из вашего кода, так и утилиты командной строки и позволяет создавать коллекции для Pivot, а так же совершать преобразования между этими коллекциями в другие форматы (CSV, Excel, CXML with raw images, and CXML with DeepZoom images) и обратно.

Pauthor удобен тем, что позволяет формировать коллекцию, используя высокоуровневые объекты, такие как PivotCollection, PivotFacetCategory, PivotItem и пр. Пример использования Pauthor приведен в хабротопике Создаем за 10 минут PivotViewer контента сайта на примере Хабрахабр, так что останавливаться на нем мы не будем.

Есть один полезный момент, который может сильно улучшить usability нашего Viewer-а. Мы же не хотим заставлять пользователя тыкать во все картинки подряд, чтобы понять, что именно (какая модель товара, отель или человек) на них нарисованы? Было бы неплохо размещать эти названия прямо на картинках. Но обычно у нас есть просто изображения товаров или чего-то другого без всяких подписей. Так вот, при создании Deep Zoom коллекции Pauthor позволяет нам указать html шаблон, на основании которого и будут формироваться изображения. Кроме чистого html в этих шаблонах можно использовать placeholders, которые будут заменены на соответствующие им характеристики из описания объекта. Вот пример простого шаблона:
<html>
  <head>
    <style>
      body {
        margin: 0px;
      }
      img {
        position: absolute;
        top: 0; left: 0;
        width: 100%; height: 100%;
      }
      p {
        font-size: 100px;
        color: white;
        background: grey;
        position: absolute;
        bottom: 0;
        left: 0;
        width: 100%;
        filter: alpha(opacity=50);
        padding: 20px;
      }
    </style>
  </head>
  <body>
    <img src="{image}" />
    <p>{name}</p>
  </body>
</html>


* This source code was highlighted with Source Code Highlighter.

В папке с Pauthor вы сможете найти несколько других примеров. А вот пример того, что может получится, взятый с сайта, который позволит вам подобрать место для проведения свадьбы:



Итак, на первый взгляд все в порядке — мы можем программно сформировать коллекцию с нужными нам данными, a Pivot Viewer сделает все остальное. Но для большего удобства не помешает добавить пару деталей. Итак…

Шаг 5-й, необязательное, но мелкое и полезное допиливание элемента напильником :)


Когда пользователь выбирает одну из картинок, ее детальное описание появляется в property панели (в правой части Viewer). Заголовок описания выделен как ссылка, а вот что произойдет при клике по этой ссылке Viewer полностью оставляет на наше усмотрение.

Точно так же пользователи привыкли, что при двойном клике по объекту происходит действие, принятое по умолчанию. Viewer обрабатывает double click по картинке так же, как и клик по заголовоку описания — формирует событие и оставляет решение за нами.

Для их обработки добавим пару строчек кода на .xaml страницу в Silverlight проекте:

<pivot:PivotViewer
  x:Name="MainPivotViewer"
  LinkClicked="OnPivotViewerLinkClicked"
  ItemDoubleClicked="OnPivotViewerItemDoubleClicked"
/>

/// <summary>
/// Handle links clicked in the metadata pane.
/// </summary>
private void OnPivotViewerLinkClicked(Object sender, LinkEventArgs args)
{
  OpenLink(args.Link.ToString());
}

/// <summary>
/// Handle double-clicks on collection items
/// </summary>
private void OnPivotViewerItemDoubleClicked(Object sender, ItemEventArgs args)
{
  String linkUriString = MainPivotViewer.GetItem(args.ItemId).Href;
  if (!String.IsNullOrWhiteSpace(linkUriString))
  {
    MainPivotViewer.CurrentItemId = args.ItemId;
    OpenLink(linkUriString);
  }
  else
  {
    // Error: No Associated Web Page: the item that was double-clicked has no value for the 'Href' field
  }
}


* This source code was highlighted with Source Code Highlighter.

В нашем случае мы вызываем вспомогательный метод OpenLink, который открывает страницу с описанием объекта в другом окне браузера. Вполне возможно, вместо перехода по url вы захотите добавлять выбранные объекты в корзину или открывать какую-нибудь другую коллекцию объектов. Чтобы не увеличивать размер описания, код OpenLink здесь не приведен. Вы можете его посмотреть, а так же скопировать весь остальной код обработки событий в примере из папки с Pivot (в моем случае это «C:\Program Files (x86)\Microsoft SDKs\Silverlight\v4.0\PivotViewer\Jun10\Source»).

Этот пример содержит описание еще одной полезной возможности. Pivot Viewer позволяет добавить к каждой картинке несколько пользовательских actions. Action — это действие, которое можно произвести над выбранным объектом. Для каждого action вы должны указать иконку, название и callback метод. Тогда при наведении курсора на картинку Pivot выведет список доступных actions. Вот как это выглядит в примере из Pivot, в котором actions используются для добавления \ удаления товаров из корзины:



И еще один полезный момент. Когда вы просматриваете большие объемы данных — вам дорог каждый кусочек места. Но многие сайты имеют фиксированную верстку и занимают только часть экрана (часто встречающийся вариант в постановке — ориентироваться разрешение шириной 1024px). У Silverlight приложений есть очень удобная возможность переключаться в полноэкранный режим, для этого достаточно изменить значение свойства IsFullScreen.

Все что нам нужно — это каким-то образом прилепить к Pivot Viewer кнопку для изменения режима, например так:

<Grid x:Name="LayoutRoot" Background="White">
  <pivot:PivotViewer
    x:Name="MainPivotViewer"
    LinkClicked="OnPivotViewerLinkClicked"
    ItemDoubleClicked="OnPivotViewerItemDoubleClicked"
  />
  <Image
    x:Name="btFullScreen"
    Width="32" Height="32" MinWidth="32" MaxWidth="32" MinHeight="32" MaxHeight="32"
    Margin="0,0,12,12"
    HorizontalAlignment="Right" VerticalAlignment="Bottom"
    Source="{путь к изображению}"
  />
</Grid>


* This source code was highlighted with Source Code Highlighter.

и добавить к ней обработчик:

private static readonly BitmapImage imageOff = new BitmapImage({изображение для сворачивания обратно});
private static readonly BitmapImage imageOn = new BitmapImage({изображение для распахивания на весь экран});

btFullScreen.MouseLeftButtonDown +=
  delegate(Object s, MouseButtonEventArgs args)
  {
    if (Application.Current.Host.Content.IsFullScreen)
    {
      Application.Current.Host.Content.IsFullScreen = false;
      btFullScreen.Source = imageOn;
    }
    else
    {
      Application.Current.Host.Content.IsFullScreen = true;
      btFullScreen.Source = imageOff;
    }
  };


* This source code was highlighted with Source Code Highlighter.

Для наглядности я изменяю картинки на конопках в зависимости от режима. Вот как это выглядит в моем случае:



Пять шагов пройдены и мы можем полюбоваться на результат своей работы. Но это описание мало бы чем отличалось от обычных «how to», если бы я не поделился опытом решения проблем, которые возникали во время разработки. Помните, в самом начале статьи я писал, что мы можем немного поплутать по лесу? Это действительно так, а виной всему — обработка ошибок в элементе управления Pivot.

Скажу сразу, на мой взгляд работает он достаточно стабильно. Правда за пару недель работы я дважды натыкался на грустное сообщение а-ля «Silverlight плагин выполнил некорректную операцию и не может работать дальше», но простая перезагрузка страницы все исправляла. Вобщем с учетом всех его преимуществ на это пока можно не обращать внимание, тем более это только первая версия.

А вот что заставило меня потратить время на отладку — так это сообщения об ошибках. Сейчас я расскажу об этом подробнее, а вы запомните два полезных правила:
  1. Если Pivot просто перестал что-то отображать — возможно вы накосячили с данными. Подсуньте ему простенькую тестовую коллекцию. Заработало? Тогда методом половинного деления выбрасывайте из ваших оригинальных данных куски xml, пока не сузите область до того значения \ атрибута, который во всем и виноват.

  2. Если вам удалось получить какое-то сообщение об ошибке (это бывает далеко не всегда) — не воспринимайте его буквально. Иногда текст сообщения не имеет никакого отношения к реальной причине ошибки.

Теперь пройдемся по ошибкам подробнее. Кстати, не забывайте, что к моменту, когда вы будете читать эту статью, что-то могут уже исправить, а что-то новенькое — добавить :)
  • Вы получили сообщение «Элемент уже является дочерним для другого элемента» (или его эквивалент на английском).

    Проверили структуру вашего xml — все в порядке? Тогда посмотрите на версию вашей операционной системы. Неудачники с 32-битной версией Windows 7 покидают наши ряды.
    Эта ошибка проявляется при попытке загрузить коллекцию в PivotViewer. Вы можете походить по форумам и там будут предлагать разные причины этой ошибки. Но крайне вероятно, что причина — именно версия OS. На ней не работают даже родные примеры от Microsoft, причем как и они, так и ваш код прекрасно отработают на 64-битной версии Windows 7, да и на остальных операционных системах.

  • Вы до сих пор получаете сообщение «Элемент уже является дочерним для другого элемента», хотя пункт первый к вам явно не относится.

    Возможная причина — какие-то ошибки в значениях атрибутов xml тегов. В моем случае причиной было то, что я по ошибке указал в атрибуте p:Icon тега Collection не url к изображению, а физический путь к картинке на моем компьютере.

  • Вы получили забавное сообщение «Invalid type for String facet: String».

    Причина — нельзя указывать пустые строки в качестве значений для категорий (FacetCategory) типа String. В этом случае просто не добавляйте значение вообще.

  • В один прекрасный момент данные просто перестали отрисовываться без всяких сообщений об ошибках.

    Возможная причина — вы используете разделитель "," для категорий типа Number вместо ".". Вполне возможно, я просто не понял, как можно указать Pivot Viewer нужную culture info. По крайней мере изменение свойства Language и явное указание культуры в web.config не помогли, Viewer упорно считал, что только точка может быть корректным разделителем.
    В моем случае я просто ушел от проблемы. Number использовался у меня для категории «Размер игры (в Мб)» и я подумал, что округление его до целого значения только упростит фильтр. Если кто-то разберется, как можно решить эту проблему — пишите, я подправлю описание.

  • Вы получили интригующее сообщение «Unhandled Error in Silverlight Application Значение не может быть неопределенным. Имя параметра: displayText».

    Возможная причина — значение «0» для категории с типом Number. Да-да, для вас это может быть вполне значимая величина, но из-за ошибки во Viewer (или какой-то логике, о которой я не догадался) нулевые значения для чисел так же нельзя использовать, как и пустые строки для строковых категорий. Поэтому просто не указывайте значение этой категории у объекта.
И напоследок еще один совет. Браузеры агрессивно кешируют коллекции с данными. Ctrl+F5 вам не поможет (так как объем данных может быть в несколько мегабайт — в реальном приложении этому можно только радоваться ). Но если вы играетесь с xml, чтобы найти оптимальный набор фильтров — выведите кнопку «очистить историю» на toolbar браузеров IE или FF — это сэкономит вам немало времени. А вот Opera отлично чистит все данные по своему Ctrl+R.

Обычно, в конце статьи нужно подводить какой-то итог. Ну… Этот элемент слишком хорош, чтобы его портили мелкие недостатки — так что было здорово! Мне очень интересно, сможет ли он действительно упростить нам поиск, так что — ждем новых реализаций на наших сайтах :)

Удачи и приятного программирования!

Tags:
Hubs:
Total votes 13: ↑11 and ↓2 +9
Views 285
Comments Comments 5