If I understand correctly, you need to update your list when an item is addend or removed from the collection, right? This is simple to achieve with the use of an ObservableCollection
instead of a List
/Array
The trick is the use of the ObservableCollection
because it implements the INotifyCollectionChanged
interface, that is responsible for inform the Binding
that the content of the collection has changed.
As for the code for achieve it is:
XAML
<Window x:Class="CollectionChangeQuestion.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:CollectionChangeQuestion"
Title="MainWindow" Height="350" Width="525">
<Window.DataContext>
<local:ViewModel/>
</Window.DataContext>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<ListView ItemsSource="{Binding Players}">
<ListView.View>
<GridView AllowsColumnReorder="True">
<GridViewColumn DisplayMemberBinding="{Binding FirstName}" Header="First Name"/>
<GridViewColumn DisplayMemberBinding="{Binding LastName}" Header="Last Name"/>
<GridViewColumn DisplayMemberBinding="{Binding Position}" Header="Position"/>
</GridView>
</ListView.View>
</ListView>
<StackPanel Orientation="Horizontal" Grid.Row="1">
<Button Content="Add New" Click="AddNew_Click" Margin="5,2.5" Width="150"/>
</StackPanel>
</Grid>
</Window>
CS
The Player class:
public class Player : INotifyPropertyChanged
{
private string _FirstName;
private string _LastName;
private string _Position;
public string FirstName
{
get { return _FirstName; }
set
{
if (_FirstName != value)
{
_FirstName = value;
NotifyPropertyChanged("FirstName");
}
}
}
public string LastName
{
get { return _LastName; }
set
{
if (_LastName != value)
{
_LastName = value;
NotifyPropertyChanged("LastName");
}
}
}
public string Position
{
get { return _Position; }
set
{
if (_Position != value)
{
_Position = value;
NotifyPropertyChanged("Position");
}
}
}
#region INotifyPropertyChanged Members
private void NotifyPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
public event PropertyChangedEventHandler PropertyChanged;
#endregion
}
The ViewModel class:
public class ViewModel
{
public ObservableCollection<Player> Players
{
get;
private set;
}
public ViewModel()
{
Players = new ObservableCollection<Player>();
#if DEBUG
Players.Add(
new Player
{
FirstName = "Raul",
LastName = "Mainardi Neto",
Position = "Me"
});
Players.Add(
new Player
{
FirstName = "Maria Lúcia",
LastName = "Kardosh de Freitas Mainardi",
Position = "Wife"
});
Players.Add(
new Player
{
FirstName = "Catarina",
LastName = "de Freitas Mainardi",
Position = "Daughter"
});
#endif
}
}
The Window class:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void AddNew_Click(object sender, RoutedEventArgs e)
{
var currentContext = this.DataContext as ViewModel;
if (currentContext == null)
{
MessageBox.Show("The DataContext is not a ViewModel");
return;
}
currentContext.Players.Add(
new Player
{
FirstName = "Dummy",
LastName = "Person",
Position = "Not defined"
});
}
}
By using this approach you will not need to call neither the InvalidateVisual() (which is responsible for Invalidating the rendering of the element, and forces a complete new layout pass. OnRender is called after the layout cycle is completed.) or the BeginInit() (which is not performatic at all).
Hope this helps
All best
Raul Mainardi Neto