views:

39

answers:

3

Hi,

I want to bind a combo box to a list of Device, List. I use,

m_ctrlCB.DataContext = m_List;
m_ctrlCB.DisplayMemberPath = "ToString()";
m_ctrlCB.SelectedValuePath = "ToString()";  // do I even need this?

I don't have any properties in Device to bind to and it's not my class. However, they do override ToString to something that is suitable for displaying in the combobox (something like: "Class Device. Number 1".

However, what I wrote doesn't work. What I see in the combobox is blank items. My selectionChanged event does work AND e.AddedItems[0] really is a Device, so I'm close. How can I get something meaningful to display in the combox box.

I suppose I'd also be happy creating ComboBoxItems and adding them to the ComboBox if necessary. But if I go this route, how do I set the Display stuff and the actual object itself so I can get it when the user selects it from the combobox?

Bonus question. If instead of using ToString, I want to use GetDeviceNumber() and combine it with my own test so the user sees, Device #1 Device #2 how would I do this?

thanks, Dave

+3  A: 

You don't have to set the DisplayMemberPath and the SelectedValuePath. Since your Device object overrides ToString(), it should display the correct string on its own.

EDIT:

To answer your "bonus question", one way to do this is to use an IValueConverter that calls the method you're interested in. The sample code below demonstrates this. I have here a combobox whose items are represented by a TextBlock (which shows the value for the ToString() method), as well as a Button (which shows the value for the GetDeviceNumber() method).

XAML:

<Window x:Class="StackOverflow.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:StackOverflow"
        Title="MainWindow" Height="350" Width="525"
        x:Name="window">
    <ComboBox x:Name="cb">
        <ComboBox.ItemTemplate>
            <DataTemplate>
                <StackPanel Orientation="Horizontal">
                    <TextBlock Text="{Binding}"/>
                    <Button>
                        <Button.Content>
                            <Binding>
                                <Binding.Converter>
                                    <local:DeviceValueConverter/>
                                </Binding.Converter>
                            </Binding>
                        </Button.Content>
                    </Button>
                </StackPanel>
            </DataTemplate>
        </ComboBox.ItemTemplate>
    </ComboBox>
</Window>

Code-Behind:

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();

        this.cb.ItemsSource = new List<Device>()
        { 
            new Device("Device1"),
            new Device("Device2"),
            new Device("Device3"),
        };
    }
}

public class Device
{
    private string text;

    public Device(string text)
    {
        this.text = text;
    }

    public string GetDeviceNumber() { return this.GetHashCode().ToString(); }
    public override string ToString() { return this.text; }
}

public class DeviceValueConverter : IValueConverter
{
    #region IValueConverter Members

    public object Convert(object value, System.Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        if (value is Device)
        {
            return (value as Device).GetDeviceNumber();
        }
        return string.Empty;
    }

    public object ConvertBack(object value, System.Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        throw new System.NotImplementedException();
    }

    #endregion
}
karmicpuppet
karmicpuppet, Thank you for the response. All seems to work well EXCEPT I get in the combobox items, what I configured in DeviceValueConvert AND the actual ToString value. It appended it without my asking. So I get something like: Class Device. Number 1 Device 1, whereas I should just get Device 1. Ideas?
Dave
I'm not sure I understand. What exactly do you want to display in the combobox items? Do you want to display ToString()? Or the DeviceValue? If you want to just display ToString(), you should be doing something like <TextBlock Text="{Binding}"/> in your ItemTemplate. On the other hand, if you want to show the DeviceValue, your XAML should be <TextBlock Text="{Binding Converter={StaticResource myConverter}}"/>
karmicpuppet
I think your use of Button confused me. I was able to get away with just TextBlock and setting <TextBlock.Text> <Binding> <Binding.Converter> <local:DeviceValueConverter /> Not sure why you had the Button in your markup. But thanks, you solved my problem. Marked as answer!
Dave
Oh. I just placed the button there because I thought it will make it clear that there are two different controls bound to two different things. Sorry if that confused you. Anyway, glad you had it sorted out. Cheers! =)
karmicpuppet
+1  A: 

One way you could do it would be to create a wrapper class and provide the appropriate properties on it. For example:

class DeviceWrapper
{
    private Device device;

    public DeviceWrapper(Device device)
    {
        this.device = device;
    }

    public int DeviceNumber
    {
        return this.device.GetDeviceNumber();
    }

    // etc...
}
Zach Johnson
+1  A: 

You should try to use ObjectDataProvider.

It will be something like this

...
  <UserControl.Resources>
    <ObjectDataProvider MethodName="GetValues"
                        ObjectType="{x:Type sys:Enum}"
                        x:Key="AlignmentValues">
      <ObjectDataProvider.MethodParameters>
        <x:Type TypeName="HorizontalAlignment" />
      </ObjectDataProvider.MethodParameters>
    </ObjectDataProvider>
  </UserControl.Resources>

  <Border Margin="10" BorderBrush="Aqua"
          BorderThickness="3" Padding="8">
    <StackPanel Width="300">
      <TextBlock>bla-bla</TextBlock>
      <ListBox Name="myComboBox" SelectedIndex="0" Margin="8"
               ItemsSource="{Binding Source={StaticResource AlignmentValues}}"/>
      <Button Content="Click Me!"
              HorizontalAlignment="{Binding ElementName=myComboBox,
                                            Path=SelectedItem}"/>
    </StackPanel>
  </Border>
...
madcyree