2
votes

Im all new in the world of C# and .net platform,so please be easy on me. This forum helped me in a few problems that i came into while doing my project,but im now stuck on this for a few days. What i'm trying to achieve is to set the selecteditem of a combobox by passing a string to it. The scenario is : I have a datatable and im setting the combo's itemssource to that datatable.DefaultView. Also i set the DisplayMemberPath of the combo,and so far everything is ok,the items show up in the combobox. Beside this i have a string with some value that i have inside the combobox too. So i'm trying to set the selecteditem of the combo like this :

combo.SelectedItem = mystring;

As you can guess,it's not working. Strangely,when i do this:

combo.Items.Add(mystring);
combo.SelectedItem = mystring;

It's working. So this is why I'm confused!

EDIT:

I just found the solution :

combo.ItemsSource = datatable.DefaultView;
combo.DisplayMemberPath = "yourpath";
combo.SelectedValuePath = "yourpath";
combo.SelectedValue = mystring;

So the trick was to set the SelectedValuePath and the SelectedValue properties. I don't know is this a good programming practice,but this does exactly what i needed.

2

2 Answers

3
votes

You're doing something wrong.

Here's a demo app that shows this (the project should be named "StringCombo").

<Window
x:Class="StringCombo.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow"
ResizeMode="CanResize">
<Window.DataContext>
    <ViewModel
        xmlns="clr-namespace:StringCombo" />
</Window.DataContext>
<Grid>
    <Grid.RowDefinitions>
        <RowDefinition />
        <RowDefinition />
    </Grid.RowDefinitions>
    <Grid.ColumnDefinitions>
        <ColumnDefinition />
        <ColumnDefinition />
    </Grid.ColumnDefinitions>
    <ComboBox
        Name="OldeFashonedCombo" />
    <Button
        Grid.Column="1"
        Content="Select Olde Waye"
        Click="Button_Click" />
    <ComboBox
        Grid.Row="1"
        ItemsSource="{Binding Strings}"
        SelectedItem="{Binding SelectedString}" />
    <Button
        Grid.Row="1"
        Grid.Column="1"
        Content="Select New Way"
        Command="{Binding SelectString}" />
</Grid>
</Window>

We've got two combos and two buttons. One uses the old winforms method of codebehind to manipulate the combo, and the other uses the new MVVM pattern.

In both scenarios, the user clicks the button, it sets the combo's SelectedValue, and the combo updates on the ui.

Here's the codebehind version:

public MainWindow()
{
    InitializeComponent();
    OldeFashonedCombo.Items.Add("One");
    OldeFashonedCombo.Items.Add("Two");
    OldeFashonedCombo.Items.Add("Three");
}

private void Button_Click(object sender, RoutedEventArgs e)
{
    OldeFashonedCombo.SelectedItem = "Two";
}

Notice I'm not using the same "instance" of "Two"; there is no need as strings are "interned," or the same instance is automatically reused, in the .NET platform. object.ReferenceEquals("Two","Two") is always true.

So, I add strings to the Items collection, and when the button is clicked I set the SelectedItem to "Two". SelectedItem is the actual instance within the Items collection that should be selected. SelectedValue is the display value; you can select by this IIRC, but I wouldn't do that as a best practice.

Here's the MVVM version:

public sealed class ViewModel : INotifyPropertyChanged
{
    public ObservableCollection<string> Strings { get; private set; }

    public ICommand SelectString { get; private set; }

    public string SelectedString { get; set; }

    public ViewModel()
    {
        Strings = new ObservableCollection<string>();
        Strings.Add("Foo");
        Strings.Add("Bar");
        Strings.Add("Baz");
        SelectString = new SelectStringCommand
        {
            ExecuteCalled = SelectBar
        };
    }

    private void SelectBar()
    {
        SelectedString = "Bar";
        // bad practice in general, but this is just an example
        PropertyChanged(this, new PropertyChangedEventArgs("SelectedString"));
    }

    public event PropertyChangedEventHandler PropertyChanged;
}

/// <summary>
/// ICommands connect the UI to the view model via the commanding pattern
/// </summary>
public sealed class SelectStringCommand : ICommand
{
    public Action ExecuteCalled { get; set; }

    public bool CanExecute(object parameter)
    {
        return true;
    }

    public event EventHandler CanExecuteChanged;

    public void Execute(object parameter)
    {
        ExecuteCalled();
    }
}

Again, because of interning, I do not have to use the same "instance" of the string. To see how the ViewModel connects to the UI, check the bindings on the ComboBox and the Button (If you haven't looked into it yet, I'd strongly suggest ditching codebehind for MVVM. It may take a little more effort to figure it out, but its MUCH better in the long run).

ANYHOW, if you run this app you'd see that BOTH versions work as expected. When you click the button, the combo box is updated properly. This suggests that your code is wrong in some other way. Not sure what, as you haven't given us enough detail to determine this. But if you run the sample and compare it closely with your code, you might be able to figure this out.

-1
votes

I think using the findby will work so something like

combo.ClearSelection();
combo.Items.FindByValue(mystring).Selected = true;