WPF ComboBox - 在选择值时显示不同的内容

时间:2009-07-17 18:18:31

标签: wpf data-binding combobox

我需要完成的是一个显示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>

当选择一个项目时,我还应该做什么才能显示第一个名字?

谢谢!

修改

稍微改变了一个问题:如果我有人的照片而不是在选择一个人时只显示第一个名字怎么办,我只想显示照片。换句话说,我怎样才能有两个单独的模板 - 一个用于下拉列表,另一个用于所选项目?

5 个答案:

答案 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,并且有两个附加属性,SelectedTemplateDropDownTemplate。然后我们像这样设置来自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活动,但如果你想要

,你可以修复它