29

Here's my binding source object:

Public Class MyListObject

    Private _mylist As New ObservableCollection(Of String)
    Private _selectedName As String

    Public Sub New(ByVal nameList As List(Of String), ByVal defaultName As String)

        For Each name In nameList
            _mylist.Add(name)
        Next

        _selectedName = defaultName

    End Sub

    Public ReadOnly Property MyList() As ObservableCollection(Of String)
        Get
            Return _mylist
        End Get
    End Property

    Public ReadOnly Property SelectedName() As String
        Get
            Return _selectedName
        End Get
    End Property

End Class

Here is my XAML:

<Window x:Class="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:WpfApplication1"
        >

    <Window.Resources>
        <ObjectDataProvider x:Key="MyListObject" ObjectInstance="" />
    </Window.Resources>

        <Grid>

        <ComboBox Height="23"
                  Margin="24,91,53,0"
                  Name="ComboBox1"
                  VerticalAlignment="Top"
                  SelectedValue="{Binding Path=SelectedName, Source={StaticResource MyListObject}, Mode=OneWay}"
                  ItemsSource="{Binding Path=MyList, Source={StaticResource MyListObject}, Mode=OneWay}"
                  />

        <Button Height="23"
                HorizontalAlignment="Left"
                Margin="47,0,0,87"
                Name="btn_List1"
                VerticalAlignment="Bottom"
                Width="75">List 1</Button>

        <Button Height="23"
                Margin="0,0,75,87"
                Name="btn_List2"
                VerticalAlignment="Bottom"
                HorizontalAlignment="Right"
                Width="75">List 2</Button>
    </Grid>
</Window>

Here's the code-behind:

Class Window1

    Private obj1 As MyListObject
    Private obj2 As MyListObject
    Private odp As ObjectDataProvider

    Public Sub New()

        InitializeComponent()

        Dim namelist1 As New List(Of String)
        namelist1.Add("Joe")
        namelist1.Add("Steve")
        obj1 = New MyListObject(namelist1, "Steve")
.
        Dim namelist2 As New List(Of String)
        namelist2.Add("Bob")
        namelist2.Add("Tim")
        obj2 = New MyListObject(namelist2, "Tim")

        odp = DirectCast(Me.FindResource("MyListObject"), ObjectDataProvider)
        odp.ObjectInstance = obj1

    End Sub

    Private Sub btn_List1_Click(ByVal sender As System.Object, ByVal e As System.Windows.RoutedEventArgs) Handles btn_List1.Click

        odp.ObjectInstance = obj1

    End Sub

    Private Sub btn_List2_Click(ByVal sender As System.Object, ByVal e As System.Windows.RoutedEventArgs) Handles btn_List2.Click

        odp.ObjectInstance = obj2

    End Sub
End Class

When the Window first loads, the bindings hook up fine. The ComboBox contains the names "Joe" and "Steve" and "Steve" is selected by default. However, when I click a button to switch the ObjectInstance to obj2, the ComboBox ItemsSource gets populated correctly in the dropdown, but the SelectedValue is set to Nothing instead of being equal to obj2.SelectedName.

Litisqe Kumar
  • 2,512
  • 4
  • 26
  • 40
Rob Sobers
  • 20,737
  • 24
  • 82
  • 111

12 Answers12

38

We had a similar issue last week. It has to do with how SelectedValue updates its internals. What we found was if you set SelectedValue it would not see the change we had to instead set SelectedItem which would properly update every thing. My conclusion is that SelectedValue is designed for get operations and not set. But this may just be a bug in the current version of 3.5sp1 .net

SliverNinja - MSFT
  • 31,051
  • 11
  • 110
  • 173
Aaron Fischer
  • 20,853
  • 18
  • 75
  • 116
  • 4
    Confirming this issue is still present in .NET 4...best to just rely on `SelectedItem` instead of `SelectedValue` – SliverNinja - MSFT Feb 08 '12 at 17:16
  • 1
    I am currently having issues with `SelectedValue` in .NET 4.5... For me `SelectedItem` too solves the issue. – Rudey Jan 21 '13 at 23:27
  • 2
    I have a similar issue which seems to be acting oppositely from what your describing , where i am using only SelectedItem http://stackoverflow.com/questions/22300281/combobox-selectedvalue-not-changing-from-binding-to-dependency-property#22300281 – eran otzap Mar 10 '14 at 12:52
  • 3
    This answer solves the issue (`SelectedItem` actually does what both of these guys seem to have thought `SelectedValue` was supposed to do), but it's mistaken about the cause of the problem. The problem was that [`SelectedValue` needs `SelectedValuePath`. This is documented](https://msdn.microsoft.com/en-us/library/system.windows.controls.primitives.selector.selectedvaluepath(v=vs.110).aspx). `SelectedValue` and `SelectedItem` do different things. – 15ee8f99-57ff-4f92-890c-b56153 Jun 16 '16 at 12:56
  • I managed to solve this in my case by adding `UpdateSourceTrigger=PropertyChanged` to the `SelectedValue` binding. To me it feels like a special kind of ridiculous that I had to set that value at all. – Dan Nov 13 '17 at 17:00
16

To stir up a 2 year old conversation:

Another possibility, if you're wanting to use strings, is to bind it to the Text property of the combobox.

<ComboBox Text="{Binding Test}">
     <ComboBoxItem Content="A" />
     <ComboBoxItem Content="B" />
     <ComboBoxItem Content="C" />
</ComboBox>

That's bound to something like:

public class TestCode
{
    private string _test;
    public string Test 
    { 
      get { return _test; }
      set
      {
         _test = value;
         NotifyPropertyChanged(() => Test); // NotifyPropertyChanged("Test"); if not using Caliburn
      }
    }
}

The above code is Two-Way so if you set Test="B"; in code then the combobox will show 'B', and then if you select 'A' from the drop down then the bound property will reflect the change.

ASeale
  • 351
  • 2
  • 7
10

Use

UpdateSourceTrigger=PropertyChanged 

in the binding

Josh Darnell
  • 11,304
  • 9
  • 38
  • 66
Junier
  • 101
  • 1
  • 2
  • Mode=TwoWay, and UpdateSourceTrigger=PropertyChanged must be set explicitly. Don't confuse them defaults. – AnjumSKhan Dec 12 '15 at 10:00
  • not always works , for example when binding a class 's property. When you change the property the value not updated – luka Oct 31 '17 at 08:50
6

The type of the SelectedValuePath and the SelectedValue must be EXACTLY the same.

If for example the type of SelectedValuePath is Int16 and the type of the property that binds to SelectedValue is int it will not work.

I spend hours to find that, and that's why I am answering here after so much time the question was asked. Maybe another poor guy like me with the same problem can see it.

Dummy01
  • 1,985
  • 1
  • 16
  • 21
6

Problem:

The ComboBox class searches for the specified object by using the IndexOf method. This method uses the Equals method to determine equality.

Solution:

So, try to set SelectedIndex using SelectedValue via Converter like this:

C# code

//Converter

public class SelectedToIndexConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            if (value != null && value is YourType)
            {
                YourType YourSelectedValue = (YourType) value;

                YourSelectedValue = (YourType) cmbDowntimeDictionary.Tag;
                YourType a = (from dd in Helper.YourType
                                        where dd.YourTypePrimaryKey == YourSelectedValue.YourTypePrimaryKey
                                        select dd).First();

                int index = YourTypeCollection.IndexOf(a); //YourTypeCollection - Same as ItemsSource of ComboBox
            }
            return null;
        }
         public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            if (value!=null && value is int)
            {
                return YourTypeCollection[(int) value];
            }

            return null;
        }
    }

Xaml

<ComboBox 
   ItemsSource="{Binding Source={StaticResource YourDataProvider}}"
   SelectedIndex="{Binding Path=YourValue, Mode=TwoWay, Converter={StaticResource SelectedToIndexConverter}, UpdateSourceTrigger=PropertyChanged}"/>

Good luck! :)

H.B.
  • 166,899
  • 29
  • 327
  • 400
Pavel Kovalev
  • 7,521
  • 5
  • 45
  • 67
3

Ran into something similar, finally I just subscribed to the SelectionChanged event for the drop down and set my data property with it. Silly and wish it was not needed, but it worked.

1

Is it reasonable to set the SelectedValuePath="Content" in the combobox's xaml, and then use SelectedValue as the binding?

It appears that you have a list of strings and want the binding to just do string matching against the actual item content in the combobox, so if you tell it which property to use for the SelectedValue it should work; at least, that worked for me when I ran across this problem.

It seems like Content would be a sensible default for SelectedValue but perhaps it isn't?

yannh
  • 392
  • 5
  • 14
Mikeb
  • 6,271
  • 3
  • 27
  • 41
  • Thank you this pointed me in the right direction. I wanted the Name property of the ComboBoxItem so I set the SelectedValuePath="Name" and it works like a champ – Brian Dishaw Jun 03 '15 at 00:22
1

In my case I was binding to a list while I should be binding to a string.

What I was doing:

private ObservableCollection<string> _SelectedPartyType;

public ObservableCollection<string> SelectedPartyType { get { return 
_SelectedPartyType; } set { 
             _SelectedPartyType = value; OnPropertyChanged("SelectedPartyType"); } }

What should be

 private string _SelectedPartyType;

 public string SelectedPartyType { get { return _SelectedPartyType; } set { 
             _SelectedPartyType = value; OnPropertyChanged("SelectedPartyType"); } }
Rajon Tanducar
  • 308
  • 4
  • 8
1

Have you tried raising an event that signals SelectName has been updated, e.g., OnPropertyChanged("SelectedName")? That worked for me.

davidinjc
  • 61
  • 3
0

The Binding Mode needs to be OneWayToSource or TwoWay since the source is what you want updated. Mode OneWay is Source to Target and therefore makes the Source ReadOnly which results in never updating the Source.

0

You know... I've been fighting with this issue for hours today, and you know what I found out? It was a DataType issue! The list that was populating the ComboBox was Int64, and I was trying to store the value in an Int32 field! No errors were being thrown, it just wasn't storing the values!

0

Just resolved this. Huh!!! Either use [one of...] .SelectedValue | .SelectedItem | .SelectedText Tip: Selected Value is preferred for ComboStyle.DropDownList while .SelectedText is for ComboStyle.DropDown.

-This should solve your problem. took me more than a week to resolve this small fyn. hah!!