Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Windows Phone 8 Panorama SelectionChanged & Databinding

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 after the upgrade. The main part of the app is a Panorama control that is databound. On SelectionChanged I am fetching the data for the new PanoramaItem + 1 (preselecting data so it's there when the person eventually goes to the item). That worked fine in WP7 but the SelectionChanged event doesn't fire with WP8.

I've reproduced the issue with a new WP8 app that wasn't upgraded and it's also isolated to databound controls. If I statically add PanoramaItems the SelectionChanged event fires fine.

Am I missing something or is this just a straight up bug in WP8? Any recommended work-arounds?

I have a GitHub repo with a static sample and a databound sample to show what works and what doesn't work. https://github.com/bthubbard/DatabindingIssues

like image 723
Brandon Avatar asked Jan 10 '13 14:01

Brandon


1 Answers

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:

Panorama firing the SelecitonChanged event with the correct SelectedIndexPanorama firing the SelecitonChanged event with the correct SelectedIndex

like image 120
JustinAngel Avatar answered Sep 27 '22 20:09

JustinAngel