Bug: ItemsControl SelectedValue Binding Fails
First, full disclosure: this is a follow-up thread to http://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=2176434&SiteID=1
Okay, given the following .cs classes and .xaml window, why does having a RichTextBox before the ItemsControl break the SelectedValue Binding? If the RichTextBox is removed, the ItemsControl (specifically its child ListBoxes) get the current value of the State.FavoriteCity property and when a new value is selected the new value is reflected on the State.FavorityCity property.
When the RichTextBox is added, however, the value binding no longer works. Bug?
I've included all of the source necessary to repro. Just create a new WPF Windows Application and past the XAML below into Window1.xaml and the code into a new file (Classes.cs works fine). To verify that the property was not getting set, I placed a watchpoint on the set { favoriteCity = value; } line and had it output the value being set to the debug window.
Code Snippet: Window1.xaml<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:FunkyListBoxSelectedValue="clr-namespace:FunkyListBoxSelectedValue"
x:Class="FunkyListBoxSelectedValue.Window1"
Title="FunkyListBoxSelectedValue" Height="455" Width="694"
><Window.Resources>
<DataTemplate x:Key="StateListItemTemplate">
<StackPanel Width="Auto" Height="Auto">
<TextBlock Text="{Binding Path=Name, Mode=Default}" TextWrapping="Wrap"/>
<ListBox Width="Auto" Height="Auto" DisplayMemberPath="Name" ItemsSource="{Binding Path=Cities, Mode=Default}" IsSynchronizedWithCurrentItem="True" SelectedValue="{Binding Path=FavoriteCity, Mode=Default}" SelectedValuePath="Name"/>
</< SPAN>StackPanel></< SPAN>DataTemplate><FunkyListBoxSelectedValue:Country x:Key="countryData" Name="USA">
<FunkyListBoxSelectedValue:Country.States>
<FunkyListBoxSelectedValue:State Name="Kentucky" FavoriteCity="Louisville">
<FunkyListBoxSelectedValue:State.Cities>
<FunkyListBoxSelectedValue:City Name="Lexington"/>
<FunkyListBoxSelectedValue:City Name="Louisville"/>
</< SPAN>FunkyListBoxSelectedValue:State.Cities></< SPAN>FunkyListBoxSelectedValue:State><FunkyListBoxSelectedValue:State Name="Washington">
<FunkyListBoxSelectedValue:State.Cities>
<FunkyListBoxSelectedValue:City Name="Seattle"/>
<FunkyListBoxSelectedValue:City Name="Spokane"/>
</< SPAN>FunkyListBoxSelectedValue:State.Cities></< SPAN>FunkyListBoxSelectedValue:State><FunkyListBoxSelectedValue:State Name="Minnesota" FavoriteCity="Duluth">
<FunkyListBoxSelectedValue:State.Cities>
<FunkyListBoxSelectedValue:City Name="Minneapolis"/>
<FunkyListBoxSelectedValue:City Name="Duluth"/>
</< SPAN>FunkyListBoxSelectedValue:State.Cities></< SPAN>FunkyListBoxSelectedValue:State></< SPAN>FunkyListBoxSelectedValue:Country.States></< SPAN>FunkyListBoxSelectedValue:Country></< SPAN>Window.Resources><Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="0.5*"/>
<ColumnDefinition Width="0.5*"/>
</< SPAN>Grid.ColumnDefinitions><RichTextBox Width="Auto" Height="Auto"/>
<ListBox Visibility="Collapsed" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Width="Auto" Height="Auto" />
<ItemsControl DataContext="{StaticResource countryData}" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Width="Auto" Height="Auto" Grid.Column="1" ItemTemplate="{DynamicResource StateListItemTemplate}" ItemsSource="{Binding Path=States, Mode=Default}" />
</< SPAN>Grid></< SPAN>Window>Code Snippet: Classes.csusing System;using System.Collections.Generic;using System.Text;namespace FunkyListBoxSelectedValue{public class Country
{public Country() { }public Country(string name) { this.name = name; }
private string name;
public string Name
{get { return name; }
set { name = value; }
}
private List<State> states = new List<State>();
public List<State> States
{get { return states; }
set { states = value; }
}
}
public class State
{public State() { }public State(string name) { this.name = name; }
public State(string name, string favoriteCity) { this.name = name; this.favoriteCity = favoriteCity; }
private string name;
public string Name
{get { return name; }
set { name = value; }
}
private string favoriteCity;
public string FavoriteCity
{get { return favoriteCity; }
set { favoriteCity = value; }
}
private List<City> cities = new List<City>();
public List<City> Cities
{get { return cities; }
set { cities = value; }
}
}
public class City
{public City() { }public City(string name) {this.name = name; }
private string name;
public string Name
{get { return name; }
set { name = value; }
}
}
}
Answers
There are two bugs here. We're aware of both already.
1. You're setting up your ListBox from a template. Some controls don't work well with this because they set local values on their own properties, hiding the values you wanted to set from the template. That's happening here - ListBox is setting a local value for SelectedValue before your template can set the binding to FavoriteCity, and this prevents the binding from every doing anything. This is happening because you set the IsSynchronizedWithCurrentItem property to True; if you remove that, you'll get the binding back again, at least in this example.
This is a pretty fragile workaround. You may require the IsSynchronizedWithCurrentItem property for other reasons, and there are other ways to cause ListBox to set a local value for SelectedValue. Ultimately, we need to provide some way for a control to set values that doesn't hide template-defined values. Similar problems arise with other controls (e.g. RadioButton sets IsSelected=False on every button in a group other than the one you clicked on).
2. When you don't declare a FavoriteCity (e.g. Washington in your example), the FavoriteCity property has value = null. The null value is picked up by the binding on SelectedValue, but this causes confusion. The SelectedValue logic is treating null as "not set" instead of as a legitimate value. This ends up with the ListBox getting stuck (mistakenly) in the "waiting for items to show up" state.
The workaround here is to avoid using null as a value for SelectedValue. Either change your data objects to use a different default value (in your case String.Empty would probably work for FavoriteCity), or add a converter to the SelectedValue binding that converts null to some other non-null value (e,g, String.Empty). This bug seems easier to fix than the first - it's on my list for the next release.
All Replies
- Your code works fine for me with or without the RichTextBox...
Sorry, didn't notice you're having trouble on SelectedValue binding... Yes, I can repro this issue. Sorry no time to figure out the reason. But a simple workaround is to place the RichTextBox below the ListBox:
<ListBox HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Width="Auto" Height="Auto" Visibility="Collapsed"/>
<RichTextBox Width="Auto" Height="Auto"/>Thank you for responding. I am aware that I can move the controls around to avoid the issue. This solution is not adequate for two reasons:
1- If I move the items around, my UI will not look as it is supposed to.
2- I have been able to repro with other scenarios, like applying a style to the container of the controls. If I apply a style that sets properties (I've tried foreground and background) of say, LayoutRoot, then the binding breaks again.
It definitely looks like something is flaky with the binding logic for SelectedValue. It seems that whenever I get it working, a (seemingly) very unrelated change breaks it--styling the LayoutRoot??
Thanks again,
-jason
I still haven't worked around this and have not seen a satisfactory response from Microsoft. Can anyone (WPF Team) chime in and let me know if this is a bug or incorrect usage. Also, is there a workaround that won't be so fragile?
Thanks,
-jason
There are two bugs here. We're aware of both already.
1. You're setting up your ListBox from a template. Some controls don't work well with this because they set local values on their own properties, hiding the values you wanted to set from the template. That's happening here - ListBox is setting a local value for SelectedValue before your template can set the binding to FavoriteCity, and this prevents the binding from every doing anything. This is happening because you set the IsSynchronizedWithCurrentItem property to True; if you remove that, you'll get the binding back again, at least in this example.
This is a pretty fragile workaround. You may require the IsSynchronizedWithCurrentItem property for other reasons, and there are other ways to cause ListBox to set a local value for SelectedValue. Ultimately, we need to provide some way for a control to set values that doesn't hide template-defined values. Similar problems arise with other controls (e.g. RadioButton sets IsSelected=False on every button in a group other than the one you clicked on).
2. When you don't declare a FavoriteCity (e.g. Washington in your example), the FavoriteCity property has value = null. The null value is picked up by the binding on SelectedValue, but this causes confusion. The SelectedValue logic is treating null as "not set" instead of as a legitimate value. This ends up with the ListBox getting stuck (mistakenly) in the "waiting for items to show up" state.
The workaround here is to avoid using null as a value for SelectedValue. Either change your data objects to use a different default value (in your case String.Empty would probably work for FavoriteCity), or add a converter to the SelectedValue binding that converts null to some other non-null value (e,g, String.Empty). This bug seems easier to fix than the first - it's on my list for the next release.
- wow. over a year later and this bug appears to still be wreaking havoc on my massively binding-dependent wpf app, and with little-to-no way to efficiently debug bindings, i'm left to waste hours writing awkward work-arounds while introducing new bugs in my app! awesome!! that fails almost as hard as trying to login to this forum
- Does anyone know if this bug has been solved? Thanks.

