Статьи

Различные шаблоны в одном списке

В этом посте я объясню, как я выбирал разные шаблоны в зависимости от типа данных, которые я хотел показать в одном и том же списке.

Теперь, почему вы хотите, чтобы 2 разных шаблона в одном списке? Что ж, если вы хотите отображать различные задачи и встречи в течение одного дня. Но вы хотите быстро увидеть, что такое задание и что такое назначение. Допустим, у вас есть квадрат для всех задач и круг для всех встреч.

Для этого вы будете использовать ContentControl,  который при привязке данных к списку будет переопределять метод, чтобы проверить, является ли привязываемый элемент задачей или назначением. А затем установить шаблон в зависимости от того, что это такое.

В моем примере кода задачи и назначения наследуются от класса CalendarItem. Это принцип объектно-ориентированного программирования, и если вы его не понимаете, дайте мне знать, и я создам блог об его основах.

Сначала я подумал о том, чтобы создать шаблоны, которые я буду использовать для задач и встреч. Я создал отдельный файл с именем «DataTemplates.xaml» и поместил его в папку «Ресурсы».

<ResourceDictionary
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    <DataTemplate x:Key="TaskTemplate">
      <StackPanel Orientation="Horizontal" Margin="0, 6">
        <Grid Margin="12, 0, 12, 0">
          <Rectangle Fill="{Binding categoryColor}" Width="20" Height="20"/>
        </Grid>
        <StackPanel Orientation="Horizontal">
          <TextBlock Text="{Binding title}" HorizontalAlignment="Left" TextWrapping="Wrap" FontSize="24" Width="300"/>
          <TextBlock Text="{Binding time}" HorizontalAlignment="Right" FontSize="24" Width="112"/>
        </StackPanel>
      </StackPanel>
    </DataTemplate>
 
    <DataTemplate x:Key="ApptTemplate">
        <StackPanel Orientation="Horizontal" Margin="0, 6">
            <Grid Margin="12, 0, 12, 0">
                <Ellipse Fill="{Binding categoryColor}" Width="20" Height="20"/>
            </Grid>
            <StackPanel Orientation="Horizontal">
                <TextBlock Text="{Binding title}" HorizontalAlignment="Left" TextWrapping="Wrap" FontSize="24" Width="300"/>
                <TextBlock Text="{Binding time}" HorizontalAlignment="Right" FontSize="24" Width="300"/>
            </StackPanel>
        </StackPanel>
    </DataTemplate>
 
</ResourceDictionary>

Когда вы посмотрите на этот код, вы увидите, что структуры шаблонов выглядят одинаково, но одна использует прямоугольник, а другая использует эллипс. Теперь в классе CalendarItem все имеет категорию и категорию, цвет, заголовок и время. Таким образом, мы использовали все эти данные для отображения.

Следующим шагом будет создание переопределения с помощью ContentControl. Создайте файл класса в своем решении, я назвал мой «TemplateSelector.cs».

using System.Windows.Controls;
using System.Windows;
using System.Windows.Markup;
using System.Xml.Linq;
 
namespace DuelTemplateSample.Helpers
{
    public class DataTemplateHelper
    {
        public static DataTemplate LoadFromDictionary(string dictionary, string template)
        {
            var doc = XDocument.Load(dictionary);
            var dict = (ResourceDictionary)XamlReader.Load(doc.ToString(SaveOptions.None));
            return dict[template] as DataTemplate;
        }
    }
 
    public class templateSelector : ContentControl
    {
        protected override void OnContentChanged(object oldContent, object newContent)
        {
            base.OnContentChanged(oldContent, newContent);
 
            var calItem = (CalendarItem)newContent;
 
            if (calItem.type == "APPT")
            {
                ContentTemplate = DataTemplateHelper.LoadFromDictionary(
                                "DuelTemplateSample;component/Resources/DataTemplates.xaml",
                                "ApptTemplate");
            }
            else
            {
                ContentTemplate = DataTemplateHelper.LoadFromDictionary(
                                "DuelTemplateSample;component/Resources/DataTemplates.xaml",
                                "TaskTemplate");
            }
        }
    }
}

Как видно из кода ContentControl, мы переопределяем метод OnContentChanged, который принимает 2 объекта. oldContent и newContent. Если вы не понимаете, что такое переопределение, это еще один принцип объектно-ориентированного программирования. Затем мы вводим тип (то есть устанавливаем объект как другой тип), в этом случае мы говорим, что newContent является CalendarItem. Затем мы проверяем тип: это свойство элемента календаря, это будет либо «APPT» для встречи, либо «TASK» для задачи. Затем, в зависимости от типа, мы загружаем ContentTemplate из файла DateTemplate и имя шаблона. В коде я вызываю метод с именем LoadFromDictionary, который определен в коде выше OnContentChanged. Все, что он делает — загружает файл xaml, который вы создали ранее, и получает шаблон, соответствующий имени шаблона.Как вы можете видеть, я отправляю строку, в которой указано местоположение файла xaml, этот формат используется для указания местоположения файла в приложении «DuelTemplateSample;» сообщает, в каком пространстве имен находится файл, а «component / Resources / DataTemplates.xaml» сообщает, что файл находится в папке Resources. Компонент означает, что он находится в «корне» проекта.

Сейчас самое время настроить работу в ListBox. На вашей странице xaml, которая будет содержать ListBox, добавьте

xmlns:templateSelector="clr-namespace:DuelTemplateSample.Helpers"

в PhoneApplicationPage со всеми другими пространствами имен. Как видите, «DuelTemplateSample.Helpers» — это пространство имен, в котором находится templateSelector / OnContentChanged. Теперь для ListBox мой выглядит так

<ListBox x:Name="DuelListBox" SelectionChanged="DuelListBox_SelectionChanged" Height="133" Margin="0,475,0,0" VerticalAlignment="Top" >
    <ListBox.ItemTemplate>
        <DataTemplate>
            <templateSelector:templateSelector Content="{Binding}"/>
        </DataTemplate>
    </ListBox.ItemTemplate>
</ListBox>

Как видите, я установил DataTemplate на

<templateSelector:templateSelector Content="{Binding}"/>

Это то, что вызывает метод переопределения OnContentChange и устанавливает шаблон в соответствии с типом, который мы кодировали ранее.

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

Я надеюсь, что это поможет, и если вы не уверены, есть какие-либо вопросы или комментарии, пожалуйста, напишите или напишите мне на andy (at) underbridgecity.net.