我需要完成的是一个显示People的ComboBox。当您展开下拉列表时,它会显示FirstName和LastName,但是当您选择一个人时,组合框中显示的值应该只是该人的名字。
我有以下ItemTemplate:
<ComboBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding FirstName}" />
<TextBlock Text=" " />
<TextBlock Text="{Binding LastName}" />
</StackPanel>
</DataTemplate>
</ComboBox.ItemTemplate>
当选择一个项目时,我还应该做什么才能显示第一个名字?
谢谢!
稍微改变了一个问题:如果我有人的照片而不是在选择一个人时只显示第一个名字怎么办,我只想显示照片。换句话说,我怎样才能有两个单独的模板 - 一个用于下拉列表,另一个用于所选项目?
答案 0 :(得分:18)
以下是解决方案:
<ComboBox>
<ComboBox.ItemTemplate>
<DataTemplate>
<StackPanel>
<ContentControl x:Name="content" Content="{Binding}" ContentTemplate="{StaticResource ComplexTemplate}"/>
</StackPanel>
<DataTemplate.Triggers>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType=ComboBoxItem}}" Value="{x:Null}">
<Setter TargetName="content" Property="ContentTemplate" Value="{StaticResource SimpleTemplate}"/>
</DataTrigger>
</DataTemplate.Triggers>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
基本上,您在此处再创建一层DataTemplate。 ComboBox'es ItemTemplate始终保持不变。但该模板中的内容会根据您感兴趣的条件进行调整。
将下拉组合框项目与选定区域组合框项目区分开来的技巧是,选择区域实际上并未包含在ComboBoxItem对象中,它是ComboBox控件本身的一部分。因此,ComboBoxItem的FindAncestor返回null,我们在上面的触发器中使用它。
答案 1 :(得分:6)
我明白了。我只需要将以下内容添加到我的ComboBox中:
IsEditable="True" IsReadOnly="True" TextSearch.TextPath="FirstName"
答案 2 :(得分:5)
在DataTemplate上放置一个触发器。触发器应检查IsSelected属性(DataTemplate将需要为此设置TargetType)。如果选中它,则可以将TextBlocks的可见性设置为折叠,并将图像的可见性设置为可见。然后针对没有选择它的情况做相反的事情。
答案 3 :(得分:1)
另一种选择是使用ItemTemplateSelector
代替ItemTemplate
。我一直在使用它以下方式。
ComboBoxItemTemplateSelector
派生自DataTemplateSelector
,并且有两个附加属性,SelectedTemplate
和DropDownTemplate
。然后我们像这样设置来自Xaml的DataTemplates
<ComboBox ItemsSource="{Binding Persons}"
ItemTemplateSelector="{StaticResource ComboBoxItemTemplateSelector}">
<ts:ComboBoxItemTemplateSelector.SelectedTemplate>
<DataTemplate>
<TextBlock Text="{Binding FirstName}" />
</DataTemplate>
</ts:ComboBoxItemTemplateSelector.SelectedTemplate>
<ts:ComboBoxItemTemplateSelector.DropDownTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding FirstName}" />
<TextBlock Text=" " />
<TextBlock Text="{Binding LastName}" />
</StackPanel>
</DataTemplate>
</ts:ComboBoxItemTemplateSelector.DropDownTemplate>
</ComboBox>
在SelectTemplate中,我们检查当前容器是否包含在ComboBoxItem
中,如果是,则返回DropDownTemplate
。否则我们返回SelectedTemplate
。
public class ComboBoxItemTemplateChooser : DataTemplateSelector
{
#region SelectedTemplate..
#region DropDownTemplate..
public override DataTemplate SelectTemplate(object item,
DependencyObject container)
{
ComboBox parentComboBox = null;
ComboBoxItem comboBoxItem = container.GetVisualParent<ComboBoxItem>();
if (comboBoxItem == null)
{
parentComboBox = container.GetVisualParent<ComboBox>();
return ComboBoxItemTemplateChooser.GetSelectedTemplate(parentComboBox);
}
parentComboBox = ComboBox.ItemsControlFromItemContainer(comboBoxItem) as ComboBox;
return ComboBoxItemTemplateChooser.GetDropDownTemplate(parentComboBox);
}
}
可以在此处下载使用此项目的小型演示项目:ComboBoxItemTemplateDemo.zip
我还在这里写了一篇关于此的简短博文:Different ComboBox ItemTemplate for dropdown。 它还显示了另一种显而易见的方法,即在ComboBoxItemTemplateSelector
中使用属性而不是附加属性。
哦,和GetVisualParent。每个人似乎都有自己的实现,但无论如何,这是我正在使用的那个
public static class DependencyObjectExtensions
{
public static T GetVisualParent<T>(this DependencyObject child) where T : Visual
{
while ((child != null) && !(child is T))
{
child = VisualTreeHelper.GetParent(child);
}
return child as T;
}
}
答案 4 :(得分:0)
我使用了下一个方法
<UserControl.Resources>
<DataTemplate x:Key="SelectedItemTemplate" DataType="{x:Type statusBar:OffsetItem}">
<TextBlock Text="{Binding Path=ShortName}" />
</DataTemplate>
</UserControl.Resources>
<StackPanel Orientation="Horizontal">
<ComboBox DisplayMemberPath="FullName"
ItemsSource="{Binding Path=Offsets}"
behaviors:SelectedItemTemplateBehavior.SelectedItemDataTemplate="{StaticResource SelectedItemTemplate}"
SelectedItem="{Binding Path=Selected}" />
<TextBlock Text="User Time" />
<TextBlock Text="" />
</StackPanel>
行为
public static class SelectedItemTemplateBehavior
{
public static readonly DependencyProperty SelectedItemDataTemplateProperty =
DependencyProperty.RegisterAttached("SelectedItemDataTemplate", typeof(DataTemplate), typeof(SelectedItemTemplateBehavior), new PropertyMetadata(default(DataTemplate), PropertyChangedCallback));
public static void SetSelectedItemDataTemplate(this UIElement element, DataTemplate value)
{
element.SetValue(SelectedItemDataTemplateProperty, value);
}
public static DataTemplate GetSelectedItemDataTemplate(this ComboBox element)
{
return (DataTemplate)element.GetValue(SelectedItemDataTemplateProperty);
}
private static void PropertyChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var uiElement = d as ComboBox;
if (e.Property == SelectedItemDataTemplateProperty && uiElement != null)
{
uiElement.Loaded -= UiElementLoaded;
UpdateSelectionTemplate(uiElement);
uiElement.Loaded += UiElementLoaded;
}
}
static void UiElementLoaded(object sender, RoutedEventArgs e)
{
UpdateSelectionTemplate((ComboBox)sender);
}
private static void UpdateSelectionTemplate(ComboBox uiElement)
{
var contentPresenter = GetChildOfType<ContentPresenter>(uiElement);
if (contentPresenter == null)
return;
var template = uiElement.GetSelectedItemDataTemplate();
contentPresenter.ContentTemplate = template;
}
public static T GetChildOfType<T>(DependencyObject depObj)
where T : DependencyObject
{
if (depObj == null) return null;
for (int i = 0; i < VisualTreeHelper.GetChildrenCount(depObj); i++)
{
var child = VisualTreeHelper.GetChild(depObj, i);
var result = (child as T) ?? GetChildOfType<T>(child);
if (result != null) return result;
}
return null;
}
}
像魅力一样工作。不喜欢这里的Loaded活动,但如果你想要
,你可以修复它