11

I want to get my ComboBox in XAML to bind to my List collection of custom objects in code behind.

Currently the ComboBox lists for each entry dpwpf.Contact which is my {namespace}.{classname}.

What do I need to put in the XAML to tell it to list out, e.g. LastName + FirstName?

I know it's something like {Binding Path=... Value=...} but I can't get it.

XAML:

<Window x:Class="dpwpf.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="Window1" Height="300" Width="300">
    <StackPanel>
        <StackPanel>
            <TextBlock Text="Select the contact:"/>
            <ComboBox Name="theContactList"/>
        </StackPanel>
    </StackPanel>
</Window>

Code Behind:

namespace dpwpf
{
    public partial class Window1 : Window
    {
        public Window1()
        {
            InitializeComponent();

            StoreDB db = new StoreDB();
            List<Contact> contacts = db.GetContacts()
            theContactList.ItemsSource = contacts.ToList();
        }
    }
}

Answer:

<Window x:Class="dpwpf.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="Window1" Height="300" Width="300"
    xmlns:local="clr-namespace:dpwpf">

    <Window.Resources>
        <DataTemplate DataType="{x:Type local:Contact}">
            <StackPanel Orientation="Horizontal">
                <TextBlock Text="{Binding LastName}"/>
                <TextBlock Text=" "/>
                <TextBlock Text="{Binding FirstName}"/>
            </StackPanel>
        </DataTemplate>
    </Window.Resources>

    <StackPanel>
        <StackPanel Margin="10">
            <TextBlock Text="Contact Name:" Foreground="#555"/>
            <TextBox Name="theName"/>
        </StackPanel>
        <StackPanel>
            <TextBlock Text="Select the contact:"/>
            <ComboBox Name="theContactList"/>
        </StackPanel>
    </StackPanel>
</Window>
Dave Clemmer
  • 3,741
  • 12
  • 49
  • 72
Edward Tanguay
  • 189,012
  • 314
  • 712
  • 1,047
  • 1
    Possible duplicate of [WPF IsEditable=true ComboBox filled with objects displays the ToString() as the selected item](https://stackoverflow.com/questions/1844156/wpf-iseditable-true-combobox-filled-with-objects-displays-the-tostring-as-the) – Huseyin Yagli Oct 26 '17 at 09:48

4 Answers4

10

You can override the ToString method of Contact, or you can define a DataTemplate in WPF.

xmlns:dpwpf="... namespace of dpwpf"

<Window.Resources>
    <DataTemplate DataType="{x:Type dpwpf:Contact}">
        <StackPanel Orientation="Horizontal">
            <TextBlock Text="{Binding LastName}">
            <TextBlock Text=" ">
            <TextBlock Text="{Binding FirstName}">
        </StackPanel>
    </DataTemplate>
</Window.Resources>

This allows you to define how a Contact object will appear anywhere in the window. If you want to limit this to the ComboBox you can add the DataTemplate just to the ComboBox resources.

Bhargav Rao
  • 50,140
  • 28
  • 121
  • 140
Cameron MacFarland
  • 70,676
  • 20
  • 104
  • 133
  • wow, I'm going to have to let that sink in, you have a StackPanel going on inside a ComboBoxItem. So the posted answer code works above but I don't see the connection between the my ComboBox and the DataTemplate, I'm expecting the DataTemplate to have a name and the ComboBox refer to it. – Edward Tanguay Feb 02 '09 at 15:32
  • The combobox shows Contact objects. So WPF searches the visual tree for a DataTemplate that displays Contacts, and uses that template. If there's no template then it defaults to using ToString. There is no direct connection except through the Contact object. – Cameron MacFarland Feb 02 '09 at 15:34
  • This is the beauty of WPF. You define a way of showing a data object, and then wherever that object turns up the template is used to display it. – Cameron MacFarland Feb 02 '09 at 15:35
  • Also, the stackpanel was just there to get the "firstname" + "lastname" look. You could do the same thing with a Binding converter, but doing it this way is easier. – Cameron MacFarland Feb 02 '09 at 15:37
  • Autocompletion won't work when working around the issue like this. Take a look at Rafa's answer. – Alex Maker Apr 22 '13 at 09:30
7

Just add this in you ComboBox tag (xaml code)

TextSearch.TextPath ="Title"

ToString() modification affects all future cases you need it, I don't recommend you to do that.

See that example: http://simplesample.site90.com/wpf_combobox.php

Andreas Louv
  • 46,145
  • 13
  • 104
  • 123
Rafa
  • 71
  • 1
  • 1
  • I knew that it's some property like `TextSearch.TextPath`, but boy is it hard to find the right answer among those suggesting `ToString`s and `DisplayMemberPath`s... Thank you! – Gman Apr 09 '13 at 13:22
6

What the binding mechanism is doing is calling ToString() on the type that is being bound. Because I guess you're not overriding ToString() it'll just so the namespace.type instead of something useful.

As rebelious says, you can use DisplayMember to tell the binding to use a property of that name for the display value or you can override ToString() as below to get your custom property to show.

public void Contact
{
 public string FirstName { get; set; }
 public override string ToString()
 {
   return FirstName; 
 }
}
Ray Booysen
  • 28,894
  • 13
  • 84
  • 111
  • 1
    this is nice, but I might have other controls which want to override differently, and as far as I understand I only get one override. – Edward Tanguay Feb 02 '09 at 15:33
3

you need to use DisplayMember="TheValue"

you can add this in the XAML or in the CLR also note your binding in cose and not through the XAML. i think this relates to a prvious question of yours. which implements the binding through ObjectDataProvider use that example and add the DisplayMemeber="memeber" in the XAML

HTH, Eric,

user61477
  • 182
  • 9
  • yes, this will work, but I want to be able to format the text instead the combobox item, e.g. lastname + " " + firstname – Edward Tanguay Feb 02 '09 at 15:33
  • Hi Edward, sorry it took me so long. you have a couple of ways to tackle the problem. 1) add a property FullName which returns this.lastname + ", " + this.firstname. and use it as the deisplay member. HH, Eric – user61477 Feb 02 '09 at 17:42
  • 2) use a IValueConverter to convert the displaed vaule, you can use as a static resource in the XAML and add the Converter XML propert. – user61477 Feb 02 '09 at 17:43