RadGridView: the master-detail case via datatables in WPF

3 posts, 1 answers
  1. Onotole
    Onotole avatar
    2 posts
    Member since:
    Aug 2013

    Posted 06 Aug 2013 Link to this post

    Hello

    We trying to implement the master-detail WPF app to learn the capabilities of Telerik RadGridView.

    It is a simple application which has RadGridView with the following markup:
    <telerik:RadGridView ItemsSource="{Binding Persons}" SelectedItem="{Binding Selectedperson, Mode=TwoWay}" VerticalAlignment="Stretch" HorizontalAlignment="Stretch" AutoGenerateColumns="True" telerik:StyleManager.Theme="Windows7">
                <telerik:RadGridView.ChildTableDefinitions>
                    <telerik:GridViewTableDefinition>
                    </telerik:GridViewTableDefinition>
                </telerik:RadGridView.ChildTableDefinitions>
                <telerik:RadGridView.HierarchyChildTemplate>
                    <DataTemplate>
                        <telerik:RadGridView
                                AutoGenerateColumns="True"
                                telerik:StyleManager.Theme="Windows7"
                                ItemsSource="{Binding Details}">
                        </telerik:RadGridView>
                    </DataTemplate>
                </telerik:RadGridView.HierarchyChildTemplate>
            </telerik:RadGridView>
    Under the hood is view model which is set to DataContext of the main windows where Telerik RadGridView is placed, as follows:
    namespace MasterDetailViaDataTables
    {
        public partial class MainWindow : Window
        {
     
            public MainWindow()
            {
                InitializeComponent();
                this.DataContext = new MainViewModel();
            }

    Persons and Details are fields of view model which are ObservableCollection of appropriate instances.
    PersonDetails.cs:
    namespace MasterDetailViaDataTables
    {
        public class PersonDetails : BindableBase
        {
            private int _PersonID;
            public int PersonID
            {
                get { return _PersonID; }
                set { this.SetProperty<int>(ref this._PersonID, value); }
            }
     
            private string address;
            public string Address
            {
                get { return address; }
                set { this.SetProperty<string>(ref this.address, value); }
            }
     
            private string _Description;
            public string Description
            {
                get { return _Description; }
                set { this.SetProperty<string>(ref this._Description, value); }
            }
     
            public static ObservableCollection<PersonDetails> GetDetails()
            {
                ObservableCollection<PersonDetails> details = new ObservableCollection<PersonDetails>();
                try
                {
                    DataTable table = new DataTable("persondetail");
                    DataColumn PersonID = new DataColumn("PersonID", typeof(System.Int64));
                    DataColumn Address = new DataColumn("Address", typeof(System.String));
                    DataColumn Description = new DataColumn("Description", typeof(System.String));
                    table.Columns.Add(PersonID);
                    table.Columns.Add(Address);
                    table.Columns.Add(Description);
     
                    for (int pID = 1; pID <= 5; pID++)
                    {
                        for (int i = 0; i < 2; i++)
                        {
                            DataRow row = table.NewRow();
                            row["PersonID"] = pID;
                            row["Address"] = "Address" + (pID-1).ToString() + " - " + i.ToString();
                            row["Description"] = "Description" + (pID-1).ToString() + " - " + i.ToString();
                            table.Rows.Add(row);
                        }
                    }
     
     
                    details.Clear();
     
                    for (int i = 0; i < table.Rows.Count; ++i)
                        details.Add(new PersonDetails
                        {
                            PersonID = Convert.ToInt32(table.Rows[i][0]),
                            Address = table.Rows[i][1].ToString(),
                            Description = table.Rows[i][2].ToString()
                        });
     
                }
                catch (Exception ex)
                {
                    Console.WriteLine(ex.Message);
                }
                return details;
            }
        }
    Person.cs:
    public class Person : BindableBase
    {
        private int _PersonID;
        private string _FirstName;
        private string _LastName;
     
        public int PersonID
        {
            get { return _PersonID; }
            set { this.SetProperty<int>(ref this._PersonID, value); }
        }
     
        public string FirstName
        {
            get { return _FirstName; }
            set { this.SetProperty<string>(ref this._FirstName, value); }
        }
     
        public string LastName
        {
            get { return _LastName; }
            set { this.SetProperty<string>(ref this._LastName, value); }
        }
     
        public static ObservableCollection<Person> GetPersons()
        {
            ObservableCollection<Person> persons = new ObservableCollection<Person>();
            try
            {
                DataTable table = new DataTable("person");
                DataColumn id = new DataColumn("PersonID", typeof(System.Int64));
                id.AutoIncrement = true;
                id.AutoIncrementSeed = 1;
                DataColumn FirstName = new DataColumn("FirstName", typeof(System.String));
                DataColumn LastName = new DataColumn("LastName", typeof(System.String));
                table.Columns.Add(id);
                table.Columns.Add(FirstName);
                table.Columns.Add(LastName);
     
                for (int i = 0; i < 5; i++)
                {
                    DataRow row = table.NewRow();
                    row["FirstName"] = "FirstName" + i.ToString();
                    row["LastName"] = "LastName" + i.ToString();
                    table.Rows.Add(row);
                }
     
                persons.Clear();
     
                for (int i = 0; i < table.Rows.Count; ++i)
                    persons.Add(new Person
                    {
                        PersonID = Convert.ToInt32(table.Rows[i][0]),
                        FirstName = table.Rows[i][1].ToString(),
                        LastName = table.Rows[i][2].ToString()
                    });
     
     
     
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
     
            }
            return persons;
        }
     
     
    }
    MainViewModel.cs:
    public class MainViewModel : BindableBase, INotifyPropertyChanged
    {
        public MainViewModel()
        {
            this.Persons = Person.GetPersons();
        }
     
        private ObservableCollection<Person> personValues;
        public ObservableCollection<Person> Persons
        {
            get { return personValues; }
            set { this.SetProperty<ObservableCollection<Person>>(ref this.personValues, value); }
        }
     
     
        private ObservableCollection<PersonDetails> detailsvalues;
        public ObservableCollection<PersonDetails> Details
        {
            get
            {
                if (this.Selectedperson == null)
                {
                    return null;
                }
                return this.LoadDetails(this.Selectedperson.PersonID);
            }
     
        }
     
        private ObservableCollection<PersonDetails> LoadDetails(int personID)
        {
            ObservableCollection<PersonDetails> details = new ObservableCollection<PersonDetails>();
            foreach (PersonDetails detail in PersonDetails.GetDetails().Where(item => item.PersonID == personID))
            {
                details.Add(detail);
            }
            return details;
        }
     
        private Person selectedPersonValue;
        public Person Selectedperson
        {
            get { return selectedPersonValue; }
            set
            {
                this.SetProperty<Person>(ref this.selectedPersonValue, value);
                this.RaiseNotification("Details");
            }
        }
     
    }

    We can't get working hierarchical RadGridView. When we trying to expand the parent row, we see the following in the Output window:
    System.Windows.Data Error: 40 : BindingExpression path error: 'Details' property not found on 'object' ''Person' (HashCode=43402647)'.
    BindingExpression:Path=Details; DataItem='Person' (HashCode=43402647); target element is 'RadGridView' (Name=''); target property is 'ItemsSource' (type 'Object')
    We can't figure out what is wrong here, can you help us?
  2. Answer
    Rossen Hristov
    Admin
    Rossen Hristov avatar
    2478 posts

    Posted 06 Aug 2013 Link to this post

    Hi,

    The DataContext of each child grid is the parent data item, i.e. Person. Since Person does not have a Details property your Binding fails. Each Person should have many PersonDetails, hence the Person class should have an IEnumerable<PersonDetail> property which the child grid can bind to.

    This is how one-to-many relationships are established.

    Regards,
    Rossen Hristov
    Telerik
    TRY TELERIK'S NEWEST PRODUCT - EQATEC APPLICATION ANALYTICS for WPF.
    Learn what features your users use (or don't use) in your application. Know your audience. Target it better. Develop wisely.
    Sign up for Free application insights >>
  3. Onotole
    Onotole avatar
    2 posts
    Member since:
    Aug 2013

    Posted 06 Aug 2013 Link to this post

    Thanks!
Back to Top