2011-12-18 18 views
8

Sto appena iniziando con MVVM e ho raggiunto un ostacolo che spero che qualcuno mi possa aiutare. Sto cercando di creare una semplice vista con 2 listbox. Una selezione dalla prima casella di riepilogo popolerà la seconda casella di riepilogo. Ho creato una classe che memorizza le informazioni che voglio associare.ObservableCollection non si aggiorna Visualizza

MyObject Class (Object osservabile è solo una classe base che implementa 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>(); 
    } 
} 

Nel mio ViewModel ho due ObservableCollections creati

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

Nel mio costruttore della ViewModel ho:

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

Che funziona bene per le voci di Livello1 e vengono visualizzati correttamente nella vista. Tuttavia ho un comando che viene chiamato quando l'utente seleziona un elemento nella casella di riepilogo, che ha la seguente:

Level2MenuItems = ClickedItem.SubCategories; 

Per qualche ragione ciò non aggiornare l'interfaccia utente del secondo listbox. Se metto un breakpoint in questa posizione, posso vedere che Level2MenuItems ha le informazioni corrette memorizzate al suo interno. Se scrivo un ciclo foreach e li aggiungo singolarmente alla raccolta Level2MenuItems, viene visualizzato correttamente.

anche come un test ho aggiunto il seguente al costruttore:

Level2MenuItems = Level1MenuItems[0].SubCategories; 

E questo aggiornato correttamente.

Quindi, perché il codice funziona come previsto nel costruttore o durante il ciclo, ma non quando un utente fa clic su un elemento nella casella di riepilogo?

risposta

6

È necessario aumentare la notifica di modifica sulla proprietà Level2MenuItems.

Invece di avere

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

è necessario

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

La ragione l'ex opere nel costruttore è che il legame non ha ancora avuto luogo. Tuttavia dal momento che stai cambiando il riferimento tramite un comando eseguito che avviene dopo l'associazione devi dire che è cambiato

+0

Grazie. Esattamente quello di cui avevo bisogno. –

0

Il tuo Subcategories proprietà should be read-only.

+0

Come si risolve questo problema? – ChrisF

+0

@ChrisF: Sospetto che stia impostando la proprietà. – SLaks

1

È necessario rendere la classe ridotta all'interno dello strumento ObservableCollection INotifyPropertyChanged.

Esempio:

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