Reputation: 43
I have a listview's itemsource binded to a Observable collection of Animal class.
When the window loads up, listview displays all the items correctly.
But I have a button which deletes an item from the observablecollection which did not update the listview.
Expected Behaviour: Button click should delete first item in observable collection and update the UI
Observed Behaviour: Button click should deletes first item in observable collection but did not update the UI
public class Animal
{
public int Num { get; set; }
public string Name { get; set; }
}
public class ViewModel:INotifyPropertyChanged
{
private ObservableCollection<Animal> animals;
public ObservableCollection<Animal> Animals
{
get { return animals; }
set { animals = value; OnPropertyChanged("Animals"); }
}
public ViewModel()
{
Animals = new ObservableCollection<Animal>()
{
new Animal(){ Name="ASD", Num = 1},
new Animal(){ Name="XYZ", Num = 2},
};
}
public void Run()
{
Animals.RemoveAt(0);
}
public event PropertyChangedEventHandler PropertyChanged;
// Create the OnPropertyChanged method to raise the event
private void OnPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}
<Grid DataContext="{Binding Source={StaticResource ViewModelDataSource}}">
<Button Content="Button" HorizontalAlignment="Left" Height="20" Margin="70,285,0,0" VerticalAlignment="Top" Width="100" Click="Button_Click"/>
<ListView x:Name="mylistview" HorizontalAlignment="Left" Height="212" Margin="42,47,0,0" VerticalAlignment="Top" Width="446" ItemsSource="{Binding Animals}">
<ListView.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<Label Content="{Binding Num}"/>
<Label Content="{Binding Name}"/>
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</Grid>
public partial class MainWindow : Window
{
private ViewModel vm;
public MainWindow()
{
InitializeComponent();
vm = new ViewModel();
}
private void Button_Click(object sender, System.Windows.RoutedEventArgs e)
{
vm.Run();
}
}
Upvotes: 1
Views: 738
Reputation: 35681
ListView uses DataContext="{Binding Source={StaticResource ViewModelDataSource}}
.
In a Window you create another instance of a view model (vm = new ViewModel();
). After that you have 2 different instances and collections. vm.Run();
removes item from collection which is not connected to view.
You need to work with one instance, so try to find the same resource, which is used in the view:
public MainWindow()
{
InitializeComponent();
vm = (ViewModel)this.FindResource("ViewModelDataSource");
}
Also DataContext setter can be simplified:
`DataContext="{StaticResource ViewModelDataSource}"`
1] declare command property in a viewmodel
public ICommand RunCmd { get; private set; }
2] use some ready-made ICommand implementation, e.g. RelayCommand or DelegateCommand and initialize RunCmd
property from viewmodel constructor:
RunCmd = new RelayCommand(Run);
3] bind Button to that command:
<Button Content="Button"
HorizontalAlignment="Left"
Height="20" Width="100" Margin="70,285,0,0"
VerticalAlignment="Top"
Command="{Binding RunCmd}"/>
note, that Click
handler is removed
Upvotes: 1