This is related to the grid's virtualization. The following code demonstrates the problem
View Models and models:
public
class
MainViewModel : ViewModelBase
{
private
ObservableCollection<Person> _persons =
new
ObservableCollection<Person>();
private
DelegateCommand<Person> _deletePersonCommand;
public
MainViewModel()
{
for
(
int
i = 0; i < 30; i++)
{
_persons.Add(
new
Person()
{
FirstName =
"Hello"
+ i,
LastName =
"World"
+ i,
});
}
}
public
ObservableCollection<Person> Persons
{
get
{
return
_persons;
}
}
public
DelegateCommand<Person> DeletePersonCommand
{
get
{
if
(_deletePersonCommand ==
null
)
{
_deletePersonCommand =
new
DelegateCommand<Person>(deletePerson);
}
return
_deletePersonCommand;
}
}
private
void
deletePerson(Person person)
{
_persons.Remove(person);
}
}
public
class
Person
{
public
string
FirstName {
get
;
set
; }
public
string
LastName {
get
;
set
; }
}
I have excluded the definition of the Delegate Command. It doesn't matter to this problem, since it will also happen with CallMethodAction, for example...
Here is the XAML:
<
Window
x:Class
=
"GridViewRowRelativeSourceBug.MainWindow"
xmlns:telerik
=
"http://schemas.telerik.com/2008/xaml/presentation"
Title
=
"MainWindow"
Height
=
"250"
Width
=
"525"
>
<
Grid
>
<
telerik:RadGridView
Name
=
"radGridView1"
ShowGroupPanel
=
"False"
ShowGroupFooters
=
"False"
AutoGenerateColumns
=
"False"
ItemsSource
=
"{Binding Persons}"
>
<
telerik:RadGridView.Columns
>
<
telerik:GridViewDataColumn
IsReadOnly
=
"True"
Header
=
"First Name"
>
<
telerik:GridViewDataColumn.CellTemplate
>
<
DataTemplate
>
<
TextBlock
Text
=
"{Binding FirstName}"
/>
</
DataTemplate
>
</
telerik:GridViewDataColumn.CellTemplate
>
</
telerik:GridViewDataColumn
>
<
telerik:GridViewDataColumn
IsReadOnly
=
"True"
Header
=
"Last Name"
>
<
telerik:GridViewDataColumn.CellTemplate
>
<
DataTemplate
>
<
TextBlock
Text
=
"{Binding LastName}"
/>
</
DataTemplate
>
</
telerik:GridViewDataColumn.CellTemplate
>
</
telerik:GridViewDataColumn
>
<
telerik:GridViewDataColumn
IsReadOnly
=
"True"
Header
=
"Delete"
Width
=
"80"
>
<
telerik:GridViewDataColumn.CellTemplate
>
<
DataTemplate
>
<
Button
Content
=
"Delete Me"
Command
=
"{Binding RelativeSource={RelativeSource AncestorType=telerik:RadGridView}, Path=DataContext.DeletePersonCommand}"
CommandParameter
=
"{Binding}"
/>
</
DataTemplate
>
</
telerik:GridViewDataColumn.CellTemplate
>
</
telerik:GridViewDataColumn
>
</
telerik:RadGridView.Columns
>
</
telerik:RadGridView
>
</
Grid
>
</
Window
>
Please note that instead of having a command for each item, the mainViewModel that contains the items, gets the command and the item to remove as a command parameter.
If you run this example, then there are 2 ways to delete the rows, one will work and the other will fail after deleting about 10 rows
Way #1, deleting from the start
first delete the items from the start, meaning, click on the "Delete Me" button of the first row, now after the first row was deleted, then click the "Delete Me" of the new first row.
You should be able to delete all the rows in that grid.
Way #2, deleting from the end:
Scroll to the end of the grid, and click on the "Delete Me" of the last row. Once it was removed, repeat this procedure for about 10 more times (the number of times is related to the number if rows that fits into the view, and I assume that container recycling is one of the causes to this problem).
You should see that at some point, the "Delete Me" will not do anything, and that the deletePerson function is never called.
In the Output window of Visual Studio you will see:
System.Windows.Data Error: 4 : Cannot find source for binding with reference 'RelativeSource FindAncestor, AncestorType='Telerik.Windows.Controls.RadGridView', AncestorLevel='1''. BindingExpression:Path=DataContext.DeletePersonCommand; DataItem=null; target element is 'Button' (Name=''); target property is 'Command' (type 'ICommand')
I must say that this bug is pretty old, and its weird that no one has reported it yet.