2011-12-18 91 views
8

我剛剛開始使用MVVM,並且遇到了一個障礙,希望有人能幫助我。我正在嘗試用2個列表框創建一個簡單的視圖。第一個列表框中的選擇將填充第二個列表框。我創建了一個類來存儲我想要綁定的信息。ObservableCollection不更新查看

爲MyObject類(可觀察對象只是一個基類實現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>(); 
    } 
} 

在我的ViewModel我有兩個ObservableCollections創建

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

在我的視圖模型的構造,我有:

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

對於Level1項目可以正常工作並在視圖中正確顯示。但是我有一個被調用,當用戶點擊一個項目在列表框中,它具有以下命令:

Level2MenuItems = ClickedItem.SubCategories; 

出於某種原因,這並不更新第二列表框的UI。如果我在這個位置放置一個斷點,我可以看到Level2MenuItems中存儲了正確的信息。如果我編寫一個foreach循環並將它們單獨添加到Level2MenuItems集合中,那麼它將正確顯示。

另外,作爲一個測試,我添加了下面的構造器:

Level2MenuItems = Level1MenuItems[0].SubCategories; 

這正確更新。

那麼,爲什麼代碼在構造函數中按預期方式工作,或者在循環時運行,而不是當用戶單擊列表框中的某個項時?

回答

6

您需要提出Level2MenuItems屬性的更改通知。

而不必

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

的需要

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

原因在構造函數中以前的作品是綁定並沒有發生呢。但是,由於您通過命令執行更改引用,在綁定後發生,您需要告訴視圖已更改

+0

感謝。正是我需要的。 – 2011-12-18 23:53:37

0

您的Subcategories屬性should be read-only

+0

這是如何解決問題的? – ChrisF 2011-12-18 23:47:50

+0

@ChrisF:我懷疑他正在設置這個屬性。 – SLaks 2011-12-18 23:51:59

1

您需要讓ObservableCollection中的poco類實現INotifyPropertyChanged。

實施例:

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