I wrote an app for Windows Phone 7, recently I\'ve upgraded it to Windows Phone 8 and I plan on adding some features. Unfortunately, I\'ve run into a problem immediately af
The Panorama control in WP8 has a known databinding bug. The symptoms of the bug are that SelectionChanged doesn't fire, SelectedIndex & SelectedItem aren't reliable and that back navigation into a page with Panorama resets the panorama selected item.
For example, the following code sample will never fire the MessageBox and SelectedIndex & SelectedItem won't indicate the correct expected values.
<phone:Panorama x:Name="panorama"
ItemsSource="{Binding}"
SelectionChanged="Panorama_SelectionChanged_1">
<phone:Panorama.HeaderTemplate>
<DataTemplate>
<ContentControl Content="{Binding Name}" />
</DataTemplate>
</phone:Panorama.HeaderTemplate>
<phone:Panorama.ItemTemplate>
<DataTemplate>
<ContentControl Content="{Binding Name}" />
</DataTemplate>
</phone:Panorama.ItemTemplate>
</phone:Panorama>
private void MainPage_Loaded(object sender, RoutedEventArgs e)
{
this.DataContext = new ObservableCollection<Cow>()
{
new Cow("Foo"),
new Cow("Bar"),
new Cow("Baz")
};
}
private void Panorama_SelectionChanged_1(object sender, SelectionChangedEventArgs e)
{
MessageBox.Show("Panorama_SelectionChanged_1: " + panorama.SelectedIndex);
}
public class Cow
{
public Cow(string name)
{
Name = name;
}
public string Name { get; set; }
}
One obvious fix will be to manually initialize PanoramaItems in code-behind.
Another solution would be to change our collection from typed to untyped, and add the following code snippet to our bounded data class. So let's change our code from ObservableCollection<Cow>
to ObservableCollection<object>
and add some code to the Cow
class:
private void MainPage_Loaded(object sender, RoutedEventArgs e)
{
this.DataContext = new ObservableCollection<object>()
{
new Cow("Foo"),
new Cow("Bar"),
new Cow("Baz")
};
}
public class Cow
{
public Cow(string name)
{
Name = name;
}
public string Name { get; set; }
public override bool Equals(object obj)
{
if ((obj != null) && (obj.GetType() == typeof(PanoramaItem)))
{
var thePanoItem = (PanoramaItem)obj;
return base.Equals(thePanoItem.Header);
}
else
{
return base.Equals(obj);
}
}
public override int GetHashCode()
{
return base.GetHashCode();
}
}
Now, when we run this code snippet we can see SelectionChanged fires as expected with the correct SelectedIndex values:
Just a minor tip for anyone who has the ViewModel in a Portable Class Library - I put this code in the base class for my viewmodels:
if (Equals(obj.GetType().Name, "PanoramaItem"))
{
var datacontextProperty = obj.GetType().GetRuntimeProperty("DataContext");
var datacontext = datacontextProperty.GetValue(obj);
return Equals(datacontext, this);
}
This solved the problem for me. As for the comment from @Sopuli - I definitely still have this problem on the WP8 devices I have tested. (Nokia Lumia 920, WP8.0.10517.150)
A VB.NET version:
Public Overrides Function Equals(obj As Object) As Boolean
If Equals(obj.GetType.Name, "PanoramaItem") Then
Dim datacontextProperty = System.Reflection.RuntimeReflectionExtensions.GetRuntimeProperty(obj.GetType, "DataContext")
Dim datacontext = datacontextProperty.GetValue(obj)
Return Equals(datacontext, Me)
Else
Return MyBase.Equals(obj)
End If
End Function