I came across an annoying bug in the RadTreeListView this morning!
If I have a class hierarchy similiar to:
With Xaml similiar to:
Using this code, I get an exception when I try to edit Joe, Sam, George, or Frank:
However if I use the following code:
I don't get the exception.
Notice the only difference is I included both derived classes in the root collection in the working case, where as there was only a single derived class in the failing case.
The exception I am receiving is "Unable to cast object of type 'SilverlightApplication5.Client' to type 'SilverlightApplication5.Employee'."
The stack trace is:
One workaround I thought of was to included the second derived class for binding, then remove the second item right away, similar to:
However that doesn't appear to work...
A second more viable option might be a strategy pattern where there is only a single class in the grid, but this class delegates to the various derived classes. A "hack" but it should work.
Any thoughts?
In my actual use case there will only be one derived class in the grid's root, then a plethora of derived classes down the hierarchy of the grid...
Thanks
Jay
If I have a class hierarchy similiar to:
public
abstract
class
Person
{
public
string
Name {
get
;
set
; }
public
decimal
Sales {
get
;
set
; }
public
bool
IsReadOnly {
get
;
set
; }
public
abstract
string
Type {
get
; }
private
readonly
ObservableCollection<Person> _people =
new
ObservableCollection<Person>();
public
ObservableCollection<Person> People {
get
{
return
_people; } }
}
public
class
Employee : Person
{
public
Employee() { IsReadOnly =
true
; }
public
override
string
Type {
get
{
return
"Employee"
; } }
}
public
class
Client : Person
{
public
override
string
Type {
get
{
return
"Client"
; } }
}
With Xaml similiar to:
<
telerik:RadTreeListView
Name
=
"radTreeListView1"
AutoGenerateColumns
=
"false"
>
<
telerik:RadTreeListView.ChildTableDefinitions
>
<
telerik:TreeListViewTableDefinition
ItemsSource
=
"{Binding People}"
/>
</
telerik:RadTreeListView.ChildTableDefinitions
>
<
telerik:RadTreeListView.Columns
>
<
telerik:GridViewDataColumn
DataMemberBinding
=
"{Binding Name}"
Header
=
"Name"
IsReadOnlyBinding
=
"{Binding IsReadOnly}"
/>
<
telerik:GridViewDataColumn
DataMemberBinding
=
"{Binding Type}"
Header
=
"Type"
IsReadOnlyBinding
=
"{Binding IsReadOnly}"
/>
<
telerik:GridViewDataColumn
DataMemberBinding
=
"{Binding Sales}"
Header
=
"Sales"
IsReadOnlyBinding
=
"{Binding IsReadOnly}"
/>
<
telerik:GridViewDataColumn
DataMemberBinding
=
"{Binding IsReadOnly}"
Header
=
"IsReadOnly"
IsReadOnlyBinding
=
"{Binding IsReadOnly}"
/>
</
telerik:RadTreeListView.Columns
>
</
telerik:RadTreeListView
>
Using this code, I get an exception when I try to edit Joe, Sam, George, or Frank:
public
partial
class
MainPage : UserControl
{
public
MainPage()
{
InitializeComponent();
var list =
new
ObservableCollection<Person>();
Employee sam =
new
Employee() { Name =
"Alice"
};
list.Add(sam);
sam.People.Add(
new
Client() { Name =
"Joe"
});
sam.People.Add(
new
Client() { Name =
"Sam"
});
Employee john =
new
Employee() { Name =
"John"
};
john.People.Add(
new
Client() { Name =
"George"
});
john.People.Add(
new
Client() { Name =
"Frank"
});
list.Add(john);
//list.Add(new Client() { Name = "Jay" });
radTreeListView1.ItemsSource = list;
}
}
However if I use the following code:
public
partial
class
MainPage : UserControl
{
public
MainPage()
{
InitializeComponent();
var list =
new
ObservableCollection<Person>();
Employee sam =
new
Employee() { Name =
"Alice"
};
list.Add(sam);
sam.People.Add(
new
Client() { Name =
"Joe"
});
sam.People.Add(
new
Client() { Name =
"Sam"
});
Employee john =
new
Employee() { Name =
"John"
};
john.People.Add(
new
Client() { Name =
"George"
});
john.People.Add(
new
Client() { Name =
"Frank"
});
list.Add(john);
list.Add(
new
Client() { Name =
"Jay"
});
radTreeListView1.ItemsSource = list;
}
}
I don't get the exception.
Notice the only difference is I included both derived classes in the root collection in the working case, where as there was only a single derived class in the failing case.
The exception I am receiving is "Unable to cast object of type 'SilverlightApplication5.Client' to type 'SilverlightApplication5.Employee'."
The stack trace is:
at Telerik.Windows.Data.FuncExtensions.<>c__DisplayClass1`2.<ToUntypedFunc>b__0(Object item)
at Telerik.Windows.Controls.GridViewBoundColumnBase.EvaluateIsReadOnlyState(Object item)
at Telerik.Windows.Controls.GridViewBoundColumnBase.CanEdit(Object item)
at Telerik.Windows.Controls.GridView.GridViewDataControl.BeginEdit(GridViewCell gridViewCell, RoutedEventArgs editingEventArgs)
at Telerik.Windows.Controls.GridView.GridViewDataControl.OnCellMouseDown(GridViewCell cell, MouseButtonEventArgs args)
at Telerik.Windows.Controls.GridView.GridViewCell.OnMouseLeftButtonDown(MouseButtonEventArgs e)
at System.Windows.Controls.Control.OnMouseLeftButtonDown(Control ctrl, EventArgs e)
at MS.Internal.JoltHelper.FireEvent(IntPtr unmanagedObj, IntPtr unmanagedObjArgs, Int32 argsTypeIndex, Int32 actualArgsTypeIndex, String eventName)
One workaround I thought of was to included the second derived class for binding, then remove the second item right away, similar to:
Client jay =
new
Client() { Name =
"Jay"
};
list.Add(jay);
radTreeListView1.ItemsSource = list;
list.Remove(jay);
However that doesn't appear to work...
A second more viable option might be a strategy pattern where there is only a single class in the grid, but this class delegates to the various derived classes. A "hack" but it should work.
Any thoughts?
In my actual use case there will only be one derived class in the grid's root, then a plethora of derived classes down the hierarchy of the grid...
Thanks
Jay