Как сделать ListBox.ItemTemplate многоразовым/общим
Я новичок в WPF и пытаюсь понять, как лучше расширить элемент управления ListBox
. В качестве учебного опыта я хотел создать ListBox
, чей ListBoxItem
отображать a CheckBox
вместо простого текста. Я получил это, работая в основном, используя ListBox.ItemTemplate
, явно устанавливая имена свойств, к которым я хотел привязать данные. Пример стоит тысячи слов, поэтому...
У меня есть настраиваемый объект для привязки данных:
public class MyDataItem {
public bool Checked { get; set; }
public string DisplayName { get; set; }
public MyDataItem(bool isChecked, string displayName) {
Checked = isChecked;
DisplayName = displayName;
}
}
(Я создаю список этих и устанавливаю ListBox.ItemsSource
в этот список.) И мой XAML выглядит так:
<ListBox Name="listBox1">
<ListBox.ItemTemplate>
<DataTemplate>
<CheckBox IsChecked="{Binding Path=Checked}" Content="{Binding Path=DisplayName}" />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
Это работает. Но я хочу сделать этот шаблон многоразовым, т.е. Мне захочется привязать к другим объектам свойства, отличные от "Проверено" и "DisplayName". Как изменить шаблон, чтобы я мог сделать его ресурсом, повторно использовать его в нескольких экземплярах ListBox
и для каждого экземпляра привязать IsChecked
и Content
к произвольным именам свойств?
Ответы
Ответ 1
Самый простой способ - разместить DataTemplate
как ресурс где-нибудь в вашем приложении с TargetType
of MyDataItem
, как этот
<DataTemplate DataType="{x:Type MyDataItem}">
<CheckBox IsChecked="{Binding Path=Checked}" Content="{Binding Path=DisplayName}" />
</DataTemplate>
Вероятно, вам также придется включить xmlns
в свою локальную сборку и ссылаться на нее через это. Затем всякий раз, когда вы используете ListBox
(или что-нибудь еще, использующее MyDataItem
в ContentPresenter
или ItemsPresenter
), он будет использовать этот DataTemplate
для его отображения.
Ответ 2
Создайте свой DataTemplate в качестве ресурса, а затем ссылайтесь на него с помощью свойства ItemTemplate в ListBox. MSDN имеет хороший пример
<Windows.Resources>
<DataTemplate x:Key="yourTemplate">
<CheckBox IsChecked="{Binding Path=Checked}" Content="{Binding Path=DisplayName}" />
</DataTemplate>
...
</Windows.Resources>
...
<ListBox Name="listBox1"
ItemTemplate="{StaticResource yourTemplate}"/>
Ответ 3
Если вам нужен один способ отображения, вы можете использовать конвертер:
class ListConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
return ((IList<MyDataItem>)value).Select(i => new { Checked = i.Checked2, DisplayName = i.DisplayName2 });
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}
Тогда xaml будет выглядеть примерно так:
<Window.Resources>
<this:ListConverter x:Key="ListConverter" />
</Window.Resources>
<ListBox ItemsSource="{Binding Path=Items, Converter={StaticResource ListConverter}}">
<ListBox.ItemTemplate>
<DataTemplate>
<CheckBox IsChecked="{Binding Path=Checked, Mode=OneWay}" Content="{Binding Path=DisplayName, Mode=OneWay}" />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
Этот шаблон данных вы можете сделать общим, как указано выше. Двусторонняя привязка будет более сложной.
Я думаю, вам лучше сделать, чтобы ваши базовые классы реализовали интерфейс ICheckedItem, который предоставляет общие свойства, которые вы хотите привязать к datatemplates?