Windows Phone 8 Panorama SelectionChanged&数据绑定

时间:2013-01-10 14:56:17

标签: silverlight windows-phone-7 windows-phone-8 panorama-control

我为Windows Phone 7编写了一个应用程序,最近我将其升级到Windows Phone 8,我计划添加一些功能。不幸的是,我在升级后立即遇到了问题。该应用程序的主要部分是数据绑定的全景控件。在SelectionChanged上,我正在获取新的PanoramaItem + 1的数据(预选数据,以便当人最终进入该项时它就在那里)。这在WP7中运行良好,但SelectionChanged事件不会触发WP8。

我已经使用未升级的新WP8应用程序重现了这个问题,并且它也与数据绑定控件隔离。如果我静态添加PanoramaItems,SelectionChanged事件会触发。

我错过了什么,或者这只是WP8中的一个直接错误?任何推荐的解决方法?

我有一个带静态样本的GitHub repo和一个数据绑定样本,以显示哪些有效,哪些无效。 https://github.com/bthubbard/DatabindingIssues

2 个答案:

答案 0 :(得分:18)

WP8中的Panorama控件有一个已知的数据绑定错误。该错误的症状是SelectionChanged不会触发,SelectedIndex& SelectedItem不可靠,并且使用Panorama返回导航到页面会重置全景选定项目。

例如,以下代码示例永远不会触发MessageBox和SelectedIndex& SelectedItem不会指示正确的期望值。

<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; }
}

一个明显的解决方法是在代码隐藏中手动初始化PanoramaItems。

另一个解决方案是将我们的集合从typed更改为untyped,并将以下代码片段添加到我们的有界数据类中。我们将代码从ObservableCollection<Cow>更改为ObservableCollection<object>并将一些代码添加到Cow类:

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();
    }
}

现在,当我们运行此代码段时,我们可以看到SelectionChanged按预期使用正确的SelectedIndex值触发:

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

答案 1 :(得分:2)

对于在可移植类库中具有ViewModel的任何人来说,这只是一个小小的提示 - 我将此代码放在我的viewmodels的基类中:

if (Equals(obj.GetType().Name, "PanoramaItem"))
{
    var datacontextProperty = obj.GetType().GetRuntimeProperty("DataContext");
    var datacontext = datacontextProperty.GetValue(obj);
    return Equals(datacontext, this);
}

这解决了我的问题。至于@Sopuli的评论 - 我在测试过的WP8设备上肯定还有这个问题。 (诺基亚Lumia 920,WP8.0.10517.150)


VB.NET版本:

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