9

Tôi đã viết một ứng dụng cho Windows Phone 7, gần đây tôi đã nâng cấp nó lên Windows Phone 8 và tôi có kế hoạch thêm một số tính năng. Thật không may, tôi đã gặp sự cố ngay sau khi nâng cấp. Phần chính của ứng dụng là một điều khiển Panorama là databound. Ngày SelectionChanged Tôi lấy dữ liệu cho mới PanoramaItem + 1 (chọn trước dữ liệu để nó có khi người cuối cùng đi đến mục). Điều đó làm việc tốt trong WP7 nhưng sự kiện SelectionChanged không cháy với WP8.Windows Phone 8 Panorama SelectionThay đổi & Databinding

Tôi đã sao chép sự cố với ứng dụng WP8 mới chưa được nâng cấp và nó cũng bị cô lập với các điều khiển dữ liệu. Nếu tôi tĩnh thêm PanoramaItems, sự kiện SelectionChanged sẽ hoạt động tốt.

Tôi có thiếu thứ gì đó hay đây chỉ là lỗi trực tiếp trong WP8? Bất kỳ đề nghị làm việc xung quanh?

Tôi có một repo GitHub với một mẫu tĩnh và một mẫu dữ liệu để hiển thị những gì hoạt động và những gì không hoạt động. https://github.com/bthubbard/DatabindingIssues

Trả lời

18

Điều khiển toàn cảnh trong WP8 có lỗi dữ liệu đã biết. Các triệu chứng của lỗi là SelectionChanged không cháy, SelectedIndex & SelectedItem không đáng tin cậy và điều hướng trở lại vào một trang với Panorama đặt lại ảnh toàn cảnh được chọn.

Ví dụ: mẫu mã sau sẽ không bao giờ kích hoạt MessageBox và SelectedIndex & SelectedItem sẽ không cho biết giá trị mong đợi chính xác.

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

Một sửa chữa rõ ràng sẽ tự khởi PanoramaItems trong code-behind.

Một giải pháp khác là thay đổi bộ sưu tập của chúng tôi từ được nhập thành chưa được nhập và thêm đoạn mã sau vào lớp dữ liệu bị chặn của chúng tôi. Vì vậy, hãy thay đổi mã của chúng tôi từ ObservableCollection<Cow> để ObservableCollection<object> và thêm một số mã để các lớp 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(); 
    } 
} 

Bây giờ, khi chúng tôi chạy đoạn mã này, chúng ta có thể nhìn thấy đám cháy SelectionChanged như mong đợi với các giá trị SelectedIndex đúng:

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

+3

Cảm ơn phản hồi của bạn. Bạn làm việc xung quanh hoạt động tốt trên một ứng dụng nhỏ nhưng có thể là một chút đau đớn với một cái gì đó liên quan nhiều hơn. Bất kỳ ý tưởng khi điều này sẽ được cố định? – Brandon

+0

Tôi vừa thử nghiệm và bây giờ sự kiện SelectionChanged dường như hoạt động ngay bây giờ trong WP8. – Sopuli

2

Chỉ cần một mẹo nhỏ cho những ai có ViewModel trong một class Library xách tay - tôi đặt mã này trong lớp cơ sở cho viewmodels tôi:

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

Điều này giải quyết được vấn đề cho tôi. Đối với các bình luận từ @Sopuli - Tôi chắc chắn vẫn còn có vấn đề này trên các thiết bị WP8 tôi đã thử nghiệm. (Nokia Lumia 920, WP8.0.10517.150)


Một phiên bản 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

Xin lỗi, bạn đã đặt chính xác cái này vào máy PCL VM ở đâu? Trong hàm tạo của một số loại 'BindableBase' lớp thực hiện' INotifyChanged'? –

+0

Chế độ xem của tôi nằm trong PCL. Tất cả đều thừa kế từ một lớp ViewModelBase (alsin trong PCL). Đoạn mã trên là một phần của toán tử Equals: – espenalb

+0

Hoàn hảo. Tôi đã thêm một phiên bản VB.NET của mã C# của bạn vì nó hơi khác một chút. –