Как сделать элемент ListBox.ItemTemplate многоразовые / общие

Я пытаюсь понять, как лучше продлить ListBox управление. В качестве учебного опыта я хотел построить ListBox чей ListBoxItems дисплей a CheckBox вместо просто текста. Я получил, что работает в основном, используя ListBox.ItemTemplate, явно устанавливая имена свойств, которые я хотел привязать к databind. Пример стоит тысячи слов...

у меня есть пользовательский объект для привязки данных:

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>

это работает. Но я хочу сделать этот шаблон многоразовым, т. е. я хочу привязаться к другим объектам со свойствами, отличными от "Checked" и "DisplayName". Как я могу изменить свой шаблон так, чтобы я мог сделать его ресурсом, повторно использовать его на нескольких ListBox экземпляры, и для каждого экземпляра bind IsChecked и Content произвольные имена свойств?

3 ответов


самый простой способ, вероятно, чтобы поставить 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, чтобы отобразить его.


создайте 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}"/>

Если вы хотите один способ отображения, то вы можете использовать конвертер:

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?