9

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

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

我错过了什么还是这只是 WP8 中的一个直接错误?有什么推荐的解决方法吗?

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

4

2 回答 2

18

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

例如,以下代码示例永远不会触发 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。

另一种解决方案是将我们的集合从有类型更改为无类型,并将以下代码片段添加到有界数据类中。因此,让我们将代码从ObservableCollection<Cow>to更改为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 值触发:

全景图使用正确的 SelectedIndex 触发 SelecitonChanged 事件 全景图使用正确的 SelectedIndex 触发 SelecitonChanged 事件

于 2013-01-11T00:18:46.993 回答
2

对于在可移植类库中拥有 ViewModel 的任何人来说,这只是一个小提示——我将此代码放在我的视图模型的基类中:

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
于 2014-03-29T13:55:48.073 回答