Статьи

Windows Phone DataTemplateSelectors с помощью Caliburn.Micro

В этом руководстве по Windows Phone 7 вы узнаете, как использовать Caliburn.Micro при отображении списка неидентичных объектов для пользователя.

Фон

Отображение ListBox для списка, который содержит различные виды элементов, является распространенным сценарием при разработке приложений для Windows Phone. Например, ваш список может представлять папку, которая содержит файлы и подпапки. Представляя этот список пользователю, вы обычно хотите, чтобы файлы и папки выглядели по-разному. Есть много способов сделать это, например ValueConverters и следующая реализация, использующая абстрактный DataTemplateSelector .

Но если вы используете фреймворк Caliburn.Micro , все готово. Функциональные возможности внутри фреймворка позаботятся об этом автоматически за вас.

образсценарий

Вы хотите представить структуру папок конечному пользователю. У вас есть один связываемый список, который содержит как вложенные папки, так и файлы, и у вас есть один ListBox внутри XAML, который показывает оба типа элементов. Файлы File.cs и Folder.cs содержат наши модели :

В ListBox вы хотите отобразить имя элемента и маленький значок рядом с ним, чтобы указать тип элемента.

Реализация — ViewModel

Нам понадобится всего лишь одна ViewModel . Мы не собираемся создавать ViewModels для наших моделей:

  • MainPageViewModel — Основная виртуальная машина, которая содержит список, который отображается пользователю.

MainPageViewModel наследует класс проводника Caliburn.Micro . Проводник предоставляет нашей ВМ наблюдаемый список, в который мы можем добавлять элементы. Когда список изменяется, наше представление автоматически получает уведомление и знает, что нужно обновить.

Вы можете вручную создать новую коллекцию ObservableCollection, но в нашем случае мы стараемся использовать все преимущества нашей структуры выбора.

Доступ к списку можно получить через свойство Items . Итак, чтобы добавить новый элемент в наш наблюдаемый список, мы можем просто вызвать Items.Add (OurObject). Как вы заметите, мы определили проводник как тип объекта . Это означает, что свойство Items внутри проводника имеет тип BindableCollection <object>. Это означает, что вы можете добавить любой элемент в коллекцию. Вы можете использовать более точный тип, если знаете, какие элементы содержит ваш список.

Фактическая работа, которую должен выполнить MainPageViewModel, — это создать некоторые фиксированные данные для нашего приложения:

public class MainPageViewModel : Conductor<object>.Collection.AllActive
{
    protected override void OnInitialize()
    {
        Items.AddRange(new List<object>()
                           {
                               new Folder(1, "Folder 1", null),
                               new Folder(2, "Folder 2", null),
                               new File(1, "File 1", 30.0),
                               new File(2, "File 2", 30.0),
                               new File(3, "File 3", 30.0),
                               new Folder(4, "Folder 3", null),
                           });
    }
}

Теперь у нас настроена вся ViewModel, поэтому давайте сосредоточимся на представлениях.

Реализация — взгляды

Нам нужны три разных вида:

  • MainPage.xaml — страница, которая содержит наш ListBox
  • FolderView — UserControl, который отображает элемент папки
  • FileViewModel — UserControl, который отображает элемент File

Наш MainPage.xaml прост, содержит только ListBox. Мы назовем его «Items», чтобы Caliburn.Micro автоматически связывал его со свойством Items MainPageViewModel. Что отличается от обычного, так это наш DataTemplate . Мы делаем Caliburn.Micro, чтобы найти правильный UserControl для представления нашего элемента.

<ListBox x:Name="Items">
    <ListBox.ItemTemplate>
        <DataTemplate>
            <ContentControl cal:View.Model="{Binding .}" HorizontalAlignment="Left" />
        </DataTemplate>
    </ListBox.ItemTemplate>
</ListBox>

Теперь, когда наша MainPage полностью настроена, мы можем создать элементы управления UserControls, которые представляют элементы внутри папки. Вот реализация FileView:

<Grid x:Name="LayoutRoot" Background="Transparent" Margin="12 0 0 0">
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="auto"></ColumnDefinition>
        <ColumnDefinition></ColumnDefinition>
    </Grid.ColumnDefinitions>
    <Image Grid.Column="0" Source="/Icons/appbar.save.rest.png"/>
    <TextBlock Grid.Column="1" Text="{Binding Name}" VerticalAlignment="Center" Style="{StaticResource PhoneTextNormalStyle}"/>
</Grid>

И FolderView выглядит аналогично, мы просто изменим изображение. Но обратите внимание, вы можете настроить эти представления так, как хотите, например, для отображения вложенных папок в папке.

<Grid x:Name="LayoutRoot" Background="Transparent">
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="auto"></ColumnDefinition>
        <ColumnDefinition></ColumnDefinition>
    </Grid.ColumnDefinitions>
    <Image Grid.Column="0" Source="/Icons/appbar.folder.rest.png"/>
    <TextBlock Grid.Column="1" Text="{Binding Name}" VerticalAlignment="Center" Style="{StaticResource PhoneTextTitle3Style}"/>
</Grid>

 

образЕсли мы теперь запустим приложение, то увидим, что все почти установлено, за исключением того, что Caliburn.Micro не может найти правильные представления для классов File и Folder. Давайте позаботимся об этом дальше.

Сопоставление ViewModel и моделей с представлениями

Как вы помните, мы не создавали ViewModel-классы для моделей. Вместо этого мы расскажем Caliburn.Micro, как сопоставить модели файлов и папок с их представлениями.

Caliburn.Micro использует условные обозначения для сопоставления Views и ViewModels. Наиболее распространенное соглашение для нахождения View для ViewModel — просто удалить Model из имени типа, например CustomerViewModel -> CustomerView. Структура легко настраивается, и вы можете добавлять свои собственные соглашения. 

Чтобы фреймворк нашел наши представления, мы добавим пару правил в его ViewLocator . Мы настраиваем ViewLocator внутри загрузчика приложения. Мы могли бы назвать наши модели FileViewModel и FolderViewModel, и если бы мы сделали это, нам бы не понадобилось следующее, потому что Caliburn.Micro мог бы автоматически находить представления:

ViewLocator.NameTransformer.AddRule("caliburn_micro_datatemplate_selector.File", "caliburn_micro_datatemplate_selector.FileView");
ViewLocator.NameTransformer.AddRule("caliburn_micro_datatemplate_selector.Folder", "caliburn_micro_datatemplate_selector.FolderView");

Код объясняет себя довольно хорошо. Мы просто передаем полное имя типа ViewModel и соответствующее полное имя представления. Чтобы упростить рефакторинг кода, мы могли бы использовать типы вместо магических строк:

ViewLocator.NameTransformer.AddRule(typeof(File).FullName, typeof(FileView).FullName);
ViewLocator.NameTransformer.AddRule(typeof (Folder).FullName, typeof (FolderView).FullName);

Вот и все. Теперь у нас есть приложение, которое может обрабатывать ситуацию, когда один список содержит несколько типов объектов.

образ

Вывод

Caliburn.Micro предлагает мощное решение для тех ситуаций, когда ваш список содержит несколько типов объектов, и вы хотите отобразить их в одном ListBox.

Полный исходный код для примера приложения доступен на GitHub.

связи

 

Источник:  http://mikaelkoskinen.net/post/windows-phone-datatemplateselector-with-caliburn-micro-change-listbox-datatemplate-based-on-item-type-in-list.aspx