9

Ich schrieb eine App für Windows Phone 7, vor kurzem habe ich es auf Windows Phone 8 aktualisiert und ich plane, einige Funktionen hinzuzufügen. Leider habe ich unmittelbar nach dem Upgrade auf ein Problem gestoßen. Der Hauptteil der App ist ein Panorama-Steuerelement, das datengebunden ist. Auf SelectionChanged hole ich die Daten für das neue PanoramaItem + 1 (vorausgewählte Daten, so dass es dort ist, wenn die Person schließlich zu dem Element geht). Das hat in WP7 funktioniert, aber das SelectionChanged-Ereignis wird nicht mit WP8 ausgelöst.Windows Phone 8 Panorama SelectionChanged & Databinding

Ich habe das Problem mit einer neuen WP8-App reproduziert, die nicht aktualisiert wurde, und es ist auch zu datengebundenen Steuerelementen isoliert. Wenn ich PanoramaItems statisch hinzufüge, wird das SelectionChanged-Ereignis ausgelöst.

Fehle ich etwas oder ist das nur ein Fehler in WP8? Irgendwelche empfohlenen Work-Arounds?

Ich habe ein GitHub Repo mit einem statischen Beispiel und einem datengebundenen Beispiel, um zu zeigen, was funktioniert und was nicht funktioniert. https://github.com/bthubbard/DatabindingIssues

Antwort

18

Das Panorama-Steuerelement in WP8 hat einen bekannten Datenbindungsfehler. Die Symptome des Fehlers sind, dass SelectionChanged nicht ausgelöst wird, SelectedIndex & SelectedItem sind nicht zuverlässig und die Rücknavigation in eine Seite mit Panorama setzt das ausgewählte Panoramaelement zurück.

Zum Beispiel wird das folgende Codebeispiel die MessageBox nie auslösen und SelectedIndex & SelectedItem wird nicht die richtigen erwarteten Werte angeben.

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

Eine offensichtliche Fix wird manuell PanoramaItems in Code-behind zu initialisieren.

Eine andere Lösung wäre, unsere Sammlung von typisiert in untypisiert zu ändern und das folgende Code-Snippet zu unserer begrenzten Datenklasse hinzuzufügen. Also lassen Sie uns unseren Code zu ObservableCollection<object> von ObservableCollection<Cow> ändern und einige Code der Cow Klasse hinzufügen:

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

Wenn wir jetzt führen Sie diesen Code-Schnipsel wir Feuer Selection sehen können, wie mit den richtigen SelectedIndex Werte zu erwarten:

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

+3

Vielen Dank für Ihre Antwort. Sie arbeiten auf einer kleinen App gut, aber vielleicht etwas mit etwas mehr beteiligt. Irgendeine Idee, wenn das behoben wird? – Brandon

+0

Ich habe gerade getestet und jetzt das SelectionChanged-Ereignis scheint jetzt in WP8 zu arbeiten. – Sopuli

2

Nur ein kleiner Tipp für alle, die das Ansichtsmodell in einer Portable Klassenbibliothek hat - habe ich diesen Code in der Basisklasse für meine Viewmodel:

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

Dies löste das Problem für mich. Wie für den Kommentar von @Sopuli - ich habe definitiv dieses Problem auf den WP8-Geräten, die ich getestet habe. (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 
+0

Entschuldigung, wo genau hast du das in deine PCL VM gesteckt? Im Konstruktor einer Art 'BindableBase' Klasse, die' INotifyChanged' implementiert? –

+0

Meine Ansichtsmodi befinden sich in der PCL. Sie alle erben von einer ViewModelBase-Klasse (auch in der PCL). Der obige Code ist Teil des Equals-Operators: – espenalb

+0

Perfekt. Ich habe eine VB.NET-Version Ihres C# -Codes hinzugefügt, da sie etwas anders ist. –