WPF 根据绑定值创建不同的 ListBox 行模板
WPF Creating different ListBox row templates based on a bound value
我目前没有任何代码可以分享。只是一个设计问题。
我有一个 class,它定义了一个标签和一个关联的条目类型,我想将其绑定到 ListBox。例如,如果类型是 "Postal Code",我需要 ListBox 将行创建为 TextBlock 和 TextBox。对于 "Yes/no",我需要它知道创建旁边带有复选框的 TextBlock。可能会有 7 或 8 种不同的行类型。
解决这个问题的最佳方法是什么?
您可以使用 DataTrigger class.
A DataTrigger allows you to set property values when the property value of the data object matches a specified Value.
或者,您可以使用 DataTemplateSelector class。
Typically, you create a DataTemplateSelector when you have more than one DataTemplate for the same type of objects and you want to supply your own logic to choose a DataTemplate to apply based on the properties of each data object.
看看 ItemTemplateSelector
属性。 属性 允许您提供自定义逻辑,以选择用于集合中每个项目的模板。
首先在资源字典中定义各种模板...
<Application>
<Application.Resources>
<DataTemplate x:Key="TextBoxTemplate">
<!-- template here -->
</DataTemplate>
<DataTemplate x:Key="CheckBoxTemplate">
<!-- template here -->
</DataTemplate>
</Application.Resources>
</Application>
然后,创建自定义 DataTemplateSelector...
public class MyTemplateSelector : DataTemplateSelector
{
public override DataTemplate SelectTemplate(object item, DependencyObject container)
{
var myObj= item as MyObject;
if (myObj != null)
{
if (myObj.MyType is PostalCode)
{
return Application.Resources["TextBoxTemplate"] as DataTemplate;
}
if (myObj.MyType is YesNo)
{
return Application.Resources["CheckBoxTemplate"] as DataTemplate;
}
}
return null;
}
}
那么,只需要使用 ItemTemplateSelector
属性...
<Window>
<Window.Resources>
<local:MyTemplateSelector x:Key="tempSelector" />
</Window.Resources>
<ListBox ItemSource="{Binding items}" ItemTemplateSelector="{StaticResource tempSelector}" />
</Window>
解决此问题的最佳方法是创建一个集合 属性,其中包含您希望在 ListBox
中看到的所有项目,将该集合绑定到显示列表的控件项目,并使用不同的数据模板来更改用于每种项目的视觉效果。
例如,您的邮政编码类型可能是:
public class PostalCodeEntry
{
public string Value { get; set; } // Implement using standard INotifyPropertyChanged pattern
}
还有一个 "Boolean" 类型:
public class BooleanEntry
{
public bool Value { get; set; } // Implement using standard INotifyPropertyChanged pattern
}
你说你想要每个条目类型的标签,所以基础 class 是个好主意:
public abstract class EntryBase
{
public string Label { get; set; } // Implement using standard INotifyPropertyChanged pattern
}
然后 BooleanEntry
和 PostalCodeEntry
将派生自 EntryBase
。
这是 型号 排序的。您只需要这些的集合,以便您可以从 UI 绑定到它们。将适当的集合 属性 添加到您的 Window
或 ViewModel:
public ObservableCollection<EntryBase> Entries { get; private set; }
在您的 UI(View,在 XAML 中实现)中,使用知道如何绑定到列表的控件实例项目并将其可视化。在 WPF 中,这将是一个 ItemsControl
或从它派生的控件,例如 ListBox
或 ListView
:
<ItemsControl ItemsSource="{Binding Entries}" />
您可以看到我们如何将 ItemsSource
属性 绑定到名为 Entries
的代码隐藏 属性。 ItemsControl
(及其后代)知道如何将这些项目转换为视觉表示。默认情况下,您的自定义对象(在我们的示例中为 EntryBase
)将被转换为字符串并显示为文本块。但是,通过使用 data templates,您可以控制从对象到视觉对象的转换方式。
如果像这样向资源部分添加几个数据模板:
<Window ... xmlns:my="clr-namespace:---your namespace here---">
<Window.Resources>
<DataTemplate DataType="{x:Type my:PostalCodeEntry}">
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Label}" />
<TextBox Text="{Binding Value}" />
</StackPanel>
</DataTemplate>
<DataTemplate DataType="{x:Type my:BooleanEntry}">
<CheckBox Content="{Binding Label}" IsChecked="{Binding Value}" />
</DataTemplate>
</Window.Resources>
然后在其后添加 <ItemsControl ...
元素,然后您应该看到 TextBlock
/TextBox
组合用于 PostalCodeEntry
类型和 CheckBox
用于 BooleanEntry
类型。
希望如果您能使它正常工作,它会让您了解如何扩展它以处理其他模型类型及其匹配的数据模板。
我目前没有任何代码可以分享。只是一个设计问题。
我有一个 class,它定义了一个标签和一个关联的条目类型,我想将其绑定到 ListBox。例如,如果类型是 "Postal Code",我需要 ListBox 将行创建为 TextBlock 和 TextBox。对于 "Yes/no",我需要它知道创建旁边带有复选框的 TextBlock。可能会有 7 或 8 种不同的行类型。
解决这个问题的最佳方法是什么?
您可以使用 DataTrigger class.
A DataTrigger allows you to set property values when the property value of the data object matches a specified Value.
或者,您可以使用 DataTemplateSelector class。
Typically, you create a DataTemplateSelector when you have more than one DataTemplate for the same type of objects and you want to supply your own logic to choose a DataTemplate to apply based on the properties of each data object.
看看 ItemTemplateSelector
属性。 属性 允许您提供自定义逻辑,以选择用于集合中每个项目的模板。
首先在资源字典中定义各种模板...
<Application>
<Application.Resources>
<DataTemplate x:Key="TextBoxTemplate">
<!-- template here -->
</DataTemplate>
<DataTemplate x:Key="CheckBoxTemplate">
<!-- template here -->
</DataTemplate>
</Application.Resources>
</Application>
然后,创建自定义 DataTemplateSelector...
public class MyTemplateSelector : DataTemplateSelector
{
public override DataTemplate SelectTemplate(object item, DependencyObject container)
{
var myObj= item as MyObject;
if (myObj != null)
{
if (myObj.MyType is PostalCode)
{
return Application.Resources["TextBoxTemplate"] as DataTemplate;
}
if (myObj.MyType is YesNo)
{
return Application.Resources["CheckBoxTemplate"] as DataTemplate;
}
}
return null;
}
}
那么,只需要使用 ItemTemplateSelector
属性...
<Window>
<Window.Resources>
<local:MyTemplateSelector x:Key="tempSelector" />
</Window.Resources>
<ListBox ItemSource="{Binding items}" ItemTemplateSelector="{StaticResource tempSelector}" />
</Window>
解决此问题的最佳方法是创建一个集合 属性,其中包含您希望在 ListBox
中看到的所有项目,将该集合绑定到显示列表的控件项目,并使用不同的数据模板来更改用于每种项目的视觉效果。
例如,您的邮政编码类型可能是:
public class PostalCodeEntry
{
public string Value { get; set; } // Implement using standard INotifyPropertyChanged pattern
}
还有一个 "Boolean" 类型:
public class BooleanEntry
{
public bool Value { get; set; } // Implement using standard INotifyPropertyChanged pattern
}
你说你想要每个条目类型的标签,所以基础 class 是个好主意:
public abstract class EntryBase
{
public string Label { get; set; } // Implement using standard INotifyPropertyChanged pattern
}
然后 BooleanEntry
和 PostalCodeEntry
将派生自 EntryBase
。
这是 型号 排序的。您只需要这些的集合,以便您可以从 UI 绑定到它们。将适当的集合 属性 添加到您的 Window
或 ViewModel:
public ObservableCollection<EntryBase> Entries { get; private set; }
在您的 UI(View,在 XAML 中实现)中,使用知道如何绑定到列表的控件实例项目并将其可视化。在 WPF 中,这将是一个 ItemsControl
或从它派生的控件,例如 ListBox
或 ListView
:
<ItemsControl ItemsSource="{Binding Entries}" />
您可以看到我们如何将 ItemsSource
属性 绑定到名为 Entries
的代码隐藏 属性。 ItemsControl
(及其后代)知道如何将这些项目转换为视觉表示。默认情况下,您的自定义对象(在我们的示例中为 EntryBase
)将被转换为字符串并显示为文本块。但是,通过使用 data templates,您可以控制从对象到视觉对象的转换方式。
如果像这样向资源部分添加几个数据模板:
<Window ... xmlns:my="clr-namespace:---your namespace here---">
<Window.Resources>
<DataTemplate DataType="{x:Type my:PostalCodeEntry}">
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Label}" />
<TextBox Text="{Binding Value}" />
</StackPanel>
</DataTemplate>
<DataTemplate DataType="{x:Type my:BooleanEntry}">
<CheckBox Content="{Binding Label}" IsChecked="{Binding Value}" />
</DataTemplate>
</Window.Resources>
然后在其后添加 <ItemsControl ...
元素,然后您应该看到 TextBlock
/TextBox
组合用于 PostalCodeEntry
类型和 CheckBox
用于 BooleanEntry
类型。
希望如果您能使它正常工作,它会让您了解如何扩展它以处理其他模型类型及其匹配的数据模板。