IsReadOnlyBinding with derived classes in hierarchy

5 posts, 0 answers
  1. Jay
    Jay avatar
    2 posts
    Member since:
    Jul 2010

    Posted 22 Jun 2011 Link to this post

    I came across an annoying bug in the RadTreeListView this morning!

    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




     
  2. Jay
    Jay avatar
    2 posts
    Member since:
    Jul 2010

    Posted 22 Jun 2011 Link to this post

    I should add this is with version 2011.1.419.1040 of the controls.

    Thanks
    Jay
  3. DevCraft banner
  4. Yordanka
    Admin
    Yordanka avatar
    634 posts

    Posted 27 Jun 2011 Link to this post

    Hi Jay,

    We are currently investigating the problem and we will contact you as soon as we have more information.
     
    Best wishes,
    Yordanka
    the Telerik team
    Do you want to have your say when we set our development plans? Do you want to know when a feature you care about is added or when a bug fixed? Explore the Telerik Public Issue Tracking system and vote to affect the priority of the items
  5. Yordanka
    Admin
    Yordanka avatar
    634 posts

    Posted 14 Jul 2011 Link to this post

    Hi Jay,

    The problem is already resolved and the fix for it is included in our Q2 2011 official version.
     
    Kind regards,
    Yordanka
    the Telerik team

    Register for the Q2 2011 What's New Webinar Week. Mark your calendar for the week starting July 18th and book your seat for a walk through of all the exciting stuff we will ship with the new release!

  6. Carson
    Carson avatar
    5 posts
    Member since:
    Jul 2011

    Posted 16 Aug 2011 Link to this post

    public abstract class ViewModel
    {
        public string Name{get;set;}
        public ViewType Type {get;set;}
      
    }
    The Above Class is the my base view model that is being displayed in the grid.

    I derive several other VM from this one and Bind a grid to them

    public class PersonViewModel:ViewModel
    {
      public string State{get;set;}
    }
      
    public class AddressViewModel:ViewModel
    {
      public string Street1{get;set;}
    }

    ObservableCollection<ViewModel> _items;
      
    public ObservableCollection<ViewModel>
    {
      get
      {
        return _items;
      }
    }

    The Grid is then bound to the Items property

    <GridView:RadGridView 
                  ItemsSource="{Binding Items}" 
                  CanUserFreezeColumns="False" 
                  ScrollMode="RealTime" 
                  IsReadOnly="True" 
                  x:Name="AlertGrid" IsFilteringAllowed="False"
                  GridLinesVisibility="None" AutoGenerateColumns="False"
                  MinHeight="350" MaxHeight="525"
                  RowStyle="{StaticResource rowStyle}">
                  <GridView:RadGridView.Columns>
                      <GridView:GridViewDataColumn Header="Name" SortingState="Descending" DataMemberBinding="{Binding Name}" Width="150" IsFilterable="False"/>
                      <GridView:GridViewDataColumn Header="ViewType" DataMemberBinding="{Binding Type}" Width="150" IsFilterable="False"/>
                           </GridView:RadGridView.Columns>
              </GridView:RadGridView>

    When I first load the ites everything in the collection are just PersonViewModel and they display fine. If I group on a property of the base type i.e. ViewModel.Name It will group just fine. However if while grouped I add a new item to the collection that is an AddressViewModel then I get an exception that looks like

    The value "AddressViewModel" is not of type "PersonViewModel" and cannot be used in this generic collection.

    If I however ungroup the grid and then add the AddressViewModel to the collection and then regroup, it all works as expected and I don't recieve an error.

    Understand that my problem has been paraphrased and these are not the exact object names nor fields that I am using in the application, but hopefully describes my problem well enough.

    I am using 2011.2.712.1040 of the Grid Controls\


    Edit: Just Relized that I posted in the wrong forum, but the issues seem related. If not I will repost in the grid forum
Back to Top
DevCraft banner