2011-12-18 30 views
8

Tôi chỉ mới bắt đầu với MVVM và đã đánh một rào cản mà tôi hy vọng ai đó có thể giúp tôi. Tôi đang cố gắng để tạo ra một View đơn giản với 2 hộp danh sách. Lựa chọn từ hộp danh sách đầu tiên sẽ điền vào hộp danh sách thứ hai. Tôi có một lớp được tạo để lưu trữ thông tin mà tôi muốn liên kết.Quan sátCollection không cập nhật Xem

MyObject Class (Object Quan sát chỉ là một lớp cơ sở mà thực hiện INotifyPopertyChanged)

public class MyObject : ObservableObject 
{ 
    String _name = String.Empty; 
    ObservableCollection<MyObject> _subcategories; 

    public ObservableCollection<MyObject> SubCategories 
    { 
     get { return _subcategories; } 

     set 
     { 
      _subcategories = value; 
      RaisePropertyChanged("SubCategories"); 
     } 
    } 

    public String Name 
    { 
     get { return _name; } 
     set 
     { 
      _name = value; 
      RaisePropertyChanged("Name"); 
     } 
    } 


    public MyObject() 
    { 
     _subcategories = new ObservableCollection<EMSMenuItem>(); 
    } 
} 

Trong viewmodel của tôi, tôi có hai ObservableCollections tạo

public ObservableCollection<EMSMenuItem> Level1MenuItems { get; set; } 
public ObservableCollection<EMSMenuItem> Level2MenuItems { get; set; } 

Trong constructor của tôi về ViewModel tôi có:

this.Level1MenuItems = new ObservableCollection<EMSMenuItem>(); 
this.Level2MenuItems = new ObservableCollection<EMSMenuItem>(); 
this.Level1MenuItems = LoadEMSMenuItems("Sample.Xml"); 

Điều đó phù hợp với các mục Level1 và chúng hiển thị chính xác trong Chế độ xem. Tuy nhiên, tôi có lệnh được gọi khi người dùng nhấp vào một mục trong hộp danh sách, trong đó có các mục sau:

Level2MenuItems = ClickedItem.SubCategories; 

Vì một số lý do này không cập nhật giao diện người dùng của hộp danh sách thứ hai. Nếu tôi đặt một điểm ngắt tại vị trí này tôi có thể thấy rằng Level2MenuItems có thông tin chính xác được lưu trữ trong nó. Nếu tôi viết một vòng lặp foreach và thêm chúng riêng lẻ vào bộ sưu tập Level2MenuItems thì nó sẽ hiển thị chính xác.

Cũng như là một thử nghiệm tôi đã thêm phần sau đây để các nhà xây dựng:

Level2MenuItems = Level1MenuItems[0].SubCategories; 

Và đó cập nhật một cách chính xác.

Vậy tại sao mã sẽ hoạt động như mong đợi trong hàm dựng hoặc khi lặp qua, nhưng không phải khi người dùng nhấp vào một mục trong hộp danh sách?

Trả lời

6

Bạn cần phải thông báo thay đổi trên thuộc tính Level2MenuItems.

Thay vì phải

public ObservableCollection<EMSMenuItem> Level2MenuItems { get; set; } 

bạn cần

private ObservableCollection<EMSMenuItem> _level2MenuItems; 
public ObservableCollection<EMSMenuItem> Level2MenuItems 
{ 
    get { return _level2MenuItems; } 
    set 
    { 
     _level2MenuItems = value; 
     RaisePropertyChanged("Level2MenuItems"); 
    } 
} 

Lý do các công trình cũ trong các nhà xây dựng là Binding đã không xảy ra được nêu ra. Tuy nhiên vì bạn đang thay đổi tham chiếu thông qua một lệnh thực thi xảy ra sau khi ràng buộc bạn cần phải cho biết rằng nó đã thay đổi

+0

Cảm ơn. Chính xác những gì tôi cần. –

0

Subcategories thuộc tính should be read-only.

+0

Làm thế nào để giải quyết vấn đề này? – ChrisF

+0

@ChrisF: Tôi nghi ngờ anh ta đang thiết lập thuộc tính. – SLaks

1

Bạn cần tạo lớp poco trong ObservableCollection triển khai INotifyPropertyChanged.

Ví dụ:

<viewModels:LocationsViewModel x:Key="viewModel" /> 
. 
. 
.  
<ListView 
    DataContext="{StaticResource viewModel}" 
    ItemsSource="{Binding Locations}" 
    IsItemClickEnabled="True" 
    ItemClick="GroupSection_ItemClick" 
    ContinuumNavigationTransitionInfo.ExitElementContainer="True"> 

    <ListView.ItemTemplate> 
     <DataTemplate> 
      <StackPanel Orientation="Horizontal"> 
       <TextBlock Text="{Binding Name}" Margin="0,0,10,0" Style="{ThemeResource ListViewItemTextBlockStyle}" /> 
       <TextBlock Text="{Binding Latitude, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" Style="{ThemeResource ListViewItemTextBlockStyle}" Margin="0,0,5,0"/> 
       <TextBlock Text="{Binding Longitude, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" Style="{ThemeResource ListViewItemTextBlockStyle}" Margin="5,0,0,0" /> 
      </StackPanel> 
     </DataTemplate> 
    </ListView.ItemTemplate> 
</ListView> 

public class LocationViewModel : BaseViewModel 
{ 
    ObservableCollection<Location> _locations = new ObservableCollection<Location>(); 
    public ObservableCollection<Location> Locations 
    { 
     get 
     { 
      return _locations; 
     } 
     set 
     { 
      if (_locations != value) 
      { 
       _locations = value; 
       OnNotifyPropertyChanged(); 
      } 
     } 
    } 
} 

public class Location : BaseViewModel 
{ 
    int _locationId = 0; 
    public int LocationId 
    { 
     get 
     { 
      return _locationId; 
     } 
     set 
     { 
      if (_locationId != value) 
      { 
       _locationId = value; 
       OnNotifyPropertyChanged(); 
      } 
     } 
    } 

    string _name = null; 
    public string Name 
    { 
     get 
     { 
      return _name; 
     } 
     set 
     { 
      if (_name != value) 
      { 
       _name = value; 
       OnNotifyPropertyChanged(); 
      } 
     } 
    } 

    float _latitude = 0; 
    public float Latitude 
    { 
     get 
     { 
      return _latitude; 
     } 
     set 
     { 
      if (_latitude != value) 
      { 
       _latitude = value; 
       OnNotifyPropertyChanged(); 
      } 
     } 
    } 

    float _longitude = 0; 
    public float Longitude 
    { 
     get 
     { 
      return _longitude; 
     } 
     set 
     { 
      if (_longitude != value) 
      { 
       _longitude = value; 
       OnNotifyPropertyChanged(); 
      } 
     } 
    } 
} 

public class BaseViewModel : INotifyPropertyChanged 
{ 
    #region Events 
    public event PropertyChangedEventHandler PropertyChanged; 
    #endregion 

    protected void OnNotifyPropertyChanged([CallerMemberName] string memberName = "") 
    { 
     if (PropertyChanged != null) 
     { 
      PropertyChanged(this, new PropertyChangedEventArgs(memberName)); 
     } 
    } 
} 
Các vấn đề liên quan