9

Ho scritto un'app per Windows Phone 7, di recente l'ho aggiornata a Windows Phone 8 e ho intenzione di aggiungere alcune funzionalità. Sfortunatamente, ho avuto un problema subito dopo l'aggiornamento. La parte principale dell'app è un controllo Panorama che è databound. Su SelectionChanged sto recuperando i dati per il nuovo PanoramaItem + 1 (preselezione dei dati in modo che siano lì quando la persona va alla voce). Ciò ha funzionato bene in WP7 ma l'evento SelectionChanged non viene attivato con WP8.Windows Phone 8 Panorama SelectionChanged & Databinding

Ho riprodotto il problema con una nuova app WP8 ​​che non è stata aggiornata ed è anche isolata per i controlli del database. Se aggiungo staticamente PanoramaItems, l'evento SelectionChanged si attiva correttamente.

Mi manca qualcosa o si tratta solo di un bug in verticale in WP8? Qualche soluzione consigliata?

Ho un repository GitHub con un campione statico e un campione di databound per mostrare cosa funziona e cosa non funziona. https://github.com/bthubbard/DatabindingIssues

risposta

18

Il controllo Panorama in WP8 presenta un bug di associazione dati noto. I sintomi del bug sono che SelectionChanged non si attiva, SelectedIndex & SelectedItem non sono affidabili e che la navigazione di ritorno in una pagina con Panorama reimposta l'elemento selezionato panorama.

Ad esempio, il seguente esempio di codice non attiverà mai MessageBox e SelectedIndex & SelectedItem non indicherà i valori attesi corretti.

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

Una soluzione ovvia sarà di inizializzare manualmente PanoramaItems in code-behind.

Un'altra soluzione sarebbe quella di modificare la nostra raccolta da digitare a non tipizzato e aggiungere il seguente frammento di codice alla nostra classe di dati limitata. Quindi cerchiamo di cambiare il nostro codice da ObservableCollection<Cow> a ObservableCollection<object> e aggiungere un po 'di codice alla classe 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(); 
    } 
} 

Ora, quando si corre questo frammento di codice possiamo vedere SelectionChanged incendi come previsto con i valori SelectedIndex corretti:

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

+3

Grazie per la risposta. Il work-around funziona alla grande su una piccola app ma potrebbe essere un po 'un problema con qualcosa di più coinvolto. Qualche idea su quando sarà risolto? – Brandon

+0

Ho appena testato e ora l'evento SelectionChanged sembra funzionare ora in WP8. – Sopuli

2

Solo un consiglio minore per chi ha il ViewModel in una libreria di classi Portable - ho messo questo codice nella classe base per i miei ViewModels:

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

Questo ha risolto il problema per me. Per quanto riguarda il commento di @Sopuli, ho ancora questo problema sui dispositivi WP8 che ho provato. (Nokia Lumia 920, WP8.0.10517.150)


Una versione 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 
+0

Scusa, dove l'hai messo esattamente nella tua PCL VM? Nel costruttore di una sorta di classe 'BindableBase' che implementa' INotifyChanged'? –

+0

I miei viewmodes sono in PCL. Tutti ereditano da una classe ViewModelBase (alsin in PCL). Il codice sopra fa parte dell'operatore Equals: – espenalb

+0

Perfect. Ho aggiunto una versione VB.NET del tuo codice C# in quanto leggermente diversa. –