2011-12-18 16 views
8

Estoy empezando con MVVM y he tropezado con un obstáculo que espero que alguien pueda ayudarme. Estoy tratando de crear una vista simple con 2 listboxes. Una selección del primer cuadro de lista completará el segundo cuadro de lista. Tengo una clase creada que almacena la información que quiero vincular.ObservableCollection no se actualiza View

MiObjeto clase (objeto observable es sólo una clase base que 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>(); 
    } 
} 

En mi modelo de vista tengo dos ObservableCollections crearon

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

En mi constructor del modelo de vista que tengo:

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

Eso funciona bien para los artículos de nivel 1 y se muestran correctamente en la Vista. Sin embargo tengo un comando que se llama cuando el usuario hace clic en un elemento del cuadro de lista, que tiene la siguiente:

Level2MenuItems = ClickedItem.SubCategories; 

Por alguna razón esto no actualizar la interfaz de usuario del segundo cuadro de lista. Si pongo un punto de interrupción en esta ubicación, puedo ver que Level2MenuItems tiene la información correcta almacenada en él. Si escribo un ciclo foreach y los agrego individualmente a la colección Level2MenuItems, se muestra correctamente.

también como una prueba de que añade el siguiente al constructor:

Level2MenuItems = Level1MenuItems[0].SubCategories; 

Y eso actualizado correctamente.

Entonces, ¿por qué el código funcionaría como se esperaba en el constructor, o cuando se realiza un bucle, pero no cuando un usuario hace clic en un elemento en el cuadro de lista?

Respuesta

6

Debe enviar la notificación de cambio a la propiedad Level2MenuItems.

En lugar de tener

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

necesita

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

La razón los trabajos anteriores en el constructor es que la unión no ha tenido lugar todavía. Sin embargo, como está cambiando la referencia a través de un comando ejecutar lo que sucede después del enlace, debe indicar que cambió

+0

Gracias. Exactamente lo que necesitaba. –

0

Su Subcategories propiedad should be read-only.

+0

¿Cómo soluciona esto el problema? – ChrisF

+0

@ChrisF: sospecho que él está estableciendo la propiedad. – SLaks

1

Necesita hacer que su clase poco dentro de la herramienta ObservableCollection INotifyPropertyChanged.

Ejemplo:

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