Binding Master/Detail

17 posts, 1 answers
  1. Adam
    Adam avatar
    39 posts
    Member since:
    Jun 2009

    Posted 19 Jul 2009 Link to this post

    Please help...

    I am trying to figure out how to do a simple RadPanelBar with 2 related tables. We will use Northwind as an example, using Categories and Products and Linq.

    I want each Header to be the Category and within each area, the Products for that Category.It seems that this should be straight forward.

    I am able to do the Headers, but cannot figure out the items.

    Below is my code:
    ------------ Window1.xaml.cs -----------
    using System.Linq;
    using System.Windows;

    namespace RadPanelTest
    {
        public partial class Window1 : Window
        {
            private IQueryable<Category> listCategory;
            private IQueryable<Product> listProduct;

            public Window1()
            {
                InitializeComponent();
                Setup();
            }

            public void Setup()
            {
                this.DataContext = this;
                LinqTestDataContext ltdc = new LinqTestDataContext();
                ListCategory = from c in ltdc.Categories select c;
                ListProduct = from p in ltdc.Products select p;
            }

            public IQueryable<Category> ListCategory
            {
                get { return listCategory; }
                set { listCategory = value;}
            }

            public IQueryable<Product> ListProduct
            {
                get { return listProduct; }
                set { listProduct = value; }
            }
        }
    }
    ---------------------------------
    ----------- Window1.xaml --------------------
    <Window x:Class="RadPanelTest.Window1"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:telerik="http://schemas.telerik.com/2008/xaml/presentation"
        Title="Window1" Height="350" Width="500"
        >
        <Grid>
            <telerik:RadPanelBar Margin="0" ItemsSource="{Binding Path=ListCategory}" >
                <telerik:RadPanelBar.ItemTemplate>
                    <HierarchicalDataTemplate >
                        <HeaderedContentControl>
                            <StackPanel Orientation="Horizontal">
                                <TextBlock Text="{Binding CategoryName}" />
                            </StackPanel>
                        </HeaderedContentControl>
                    </HierarchicalDataTemplate>
                </telerik:RadPanelBar.ItemTemplate>
            </telerik:RadPanelBar>
        </Grid>
    </Window>

  2. Tihomir Petkov
    Admin
    Tihomir Petkov avatar
    576 posts

    Posted 20 Jul 2009 Link to this post

    Hello Adam,

    Please take a look at the sample project that I prepared for you and let me know if it demonstrates what you need.

    Kind regards,
    Tihomir Petkov
    the Telerik team

    Instantly find answers to your questions on the new Telerik Support Portal.
    Check out the tips for optimizing your support resource searches.
  3. UI for WPF is Visual Studio 2017 Ready
  4. Adam
    Adam avatar
    39 posts
    Member since:
    Jun 2009

    Posted 20 Jul 2009 Link to this post

    Appears to be exactly what I need, thanks!

    Was the problem that  I was using the wrong control? I have been pulling my hair out all night. 
    I had:
    xmlns:telerik="http://schemas.telerik.com/2008/xaml/presentation"
    and you have:
    xmlns:telerikNavigation="clr-namespace:Telerik.Windows.Controls;assembly=Telerik.Windows.Controls.Navigation"

    Can you explain what the difference is? Sorry, I am new to C#, WPF and all....




    A follow up question:
    - Can sorting, filtering, etc be done using the control or do I need to do a linq expression and bind to it?

  5. Tihomir Petkov
    Admin
    Tihomir Petkov avatar
    576 posts

    Posted 20 Jul 2009 Link to this post

    Hi Adam,

    The difference between the namespace you were using and the one I did is that yours is an umbrella namespace for all the telerik namespaces (Navigation, Input, etc.), which saves some writing in case you use most of them. So, the namespace I used is a subset of the one you used.

    As for data binding and templates, here is some background. What happens behind the scenes when you bind a RadPanelBar control is that, unless the source collection consists of RadPanelBarItems, it wraps the source objects in dynamically created RadPanelBarItems and assigns each source object to the Header property of the wrapping PanelBarItem. So, when you specify a DataTemplate or a HierarchicalDataTemplate, that template determines how data is rendered in a RadPanelBarItem's header. This is all done to fascilitate data binding to hierarchical data sources. In case you need to display an item with a header and content (no hierarchy within that item), then you need to set the ChildItemsTemplate property of your item to a ControlTemplate that will determine how your content will be rendered. This way, you will bind your element's Header property to what you want in the header, and the item's Items property to the content (remember it will be automatically wrapped in a RadPanelBarItem, which will take the ControlTemplate which you assigned to the ChildItemsTemplate property of the parent item).

    The RadPanelBar control does not support filtering and sorting other than the ones provided by the underlying ItemsControl class. So, if you need to filter/sort your data deeper than the root level of items you will need to provide your custom logic for that.

    I hope I was able to help at least a little. Let me know if you have other questions.

    Greetings,
    Tihomir Petkov
    the Telerik team

    Instantly find answers to your questions on the new Telerik Support Portal.
    Check out the tips for optimizing your support resource searches.
  6. Adam
    Adam avatar
    39 posts
    Member since:
    Jun 2009

    Posted 20 Jul 2009 Link to this post

    I will have to re-read the binding section several times before I get it... but I did get my connection working, thanks!

    I do see a small issue, which may be by design or it may be something I can work out. I am not sure if it is because I am binding to IQueryable instead of something else...

    Anyway, the issue appears to be retaining the item selected in the group. For example, using the code you sent me (for Northwind connection), if you open Beverages and click on "Chang", then open Condiments and select anything, then go back to Beverages, it is no longer selected/highlighted.

    Is there any way to retain the ItemSelected?

    Sorry if these are dumb questions, as I said I have been doing WPF and C# since July (though I do have previous programming experience).


  7. Adam
    Adam avatar
    39 posts
    Member since:
    Jun 2009

    Posted 20 Jul 2009 Link to this post

    I ran into another problem, and I am not sure how to get around it. I am sure there is a simple solution.

    With my data, I have a field called IsActive. So, assume that Northwind Categories/Products has IsActive.
    Using the IQueryable result from Linq:
     from c in dc.Categories where c.IsActive select c;
    The categories filter properly, but the Products get all of them.

    So, I thought the simple solution was to do the same thing on Products: create an IQueryable result and change the code you sent from Product to the IQueryable property.

    Now, my items are empty, so obviously there is a step I am missing, such as how to bind one IQueryable to another, since the foreign key relationship doesn't exist.


  8. Tihomir Petkov
    Admin
    Tihomir Petkov avatar
    576 posts

    Posted 20 Jul 2009 Link to this post

    Hi Adam,

    You're right that my "clarification" about binding and data templates isn't actually very clear. Please excuse me and let me know if you need more details.

    Regarding your second question, the selection mechanism of RadPanelBar allows for only one selected item, so the control does not support multiple selection - only multiple expanded items. This behavior is by design and actually you are the first person to ask for such functionality in RadPanelBar. If there is more demand for this feature we will certainly consider implementing it.

    As for your last question, judging from your description things should work fine. Can you please send me a snippet from your code or your entire project if possible, so that I can take a look? It is hard to tell what the problem might be just from your desciption.

    Kind regards,
    Tihomir Petkov
    the Telerik team

    Instantly find answers to your questions on the new Telerik Support Portal.
    Check out the tips for optimizing your support resource searches.
  9. Adam
    Adam avatar
    39 posts
    Member since:
    Jun 2009

    Posted 20 Jul 2009 Link to this post

    I don't see where to attach files... but if you use your code that you sent me, here are my changes:

    .cs file
    ---------
      private void Setup() 
            { 
                this.DataContext = this
                NorthwindDataContext dataContext = new NorthwindDataContext(); 
                ListCategory = from c in dataContext.Categories select c; 
                /* Added */ 
                ListProduct = from p in dataContext.Products 
                              where !p.ProductName.StartsWith("c")  // Eliminate Chai, Chang, etc. 
                              select p; 
            } 
     

         #region Added /* Added */ 
            private IQueryable<Product> listProduct; 
            public IQueryable<Product> ListProduct 
            { 
                get { return listProduct; } 
                set { listProduct = value; } 
            } 
            #endregion 

    and in the .XAML file:
    --------------------------
       <telerikNavigation:RadPanelBar.ItemTemplate> 
                    <!-- WAS: ItemsSource="{Binding Path=Products}" -->  
                    <HierarchicalDataTemplate ItemsSource="{Binding Path=ListProduct}" 
                                              ItemTemplate="{StaticResource productTemplate}"

    So, all I did was get another list, and try to make it the itemsource. Now, nothing opens.
    I am thinking it could be
    a) I need to format it, as it may be returning an object that it does not know how to display... so another DataTemplate?
    b)  Some relationship needs to be set
    c) I am stupid?

    The other thought I had was if there was a way (using the original Products, not the ListProduct) to create a conditional display.
     I tried something but it did not work. Tried to set the Visibility to Hidden based on the column IsActive = false. I don't remember how I tried it (datatrigger?). Been a long night.




  10. Adam
    Adam avatar
    39 posts
    Member since:
    Jun 2009

    Posted 20 Jul 2009 Link to this post

    I don't see where to attach files... but if you use your code that you sent me, here are my changes:

    .cs file
    ---------
      private void Setup() 
            { 
                this.DataContext = this
                NorthwindDataContext dataContext = new NorthwindDataContext(); 
                ListCategory = from c in dataContext.Categories select c; 
                /* Added */ 
                ListProduct = from p in dataContext.Products 
                              where !p.ProductName.StartsWith("c")  // Eliminate Chai, Chang, etc. 
                              select p; 
            } 
     

         #region Added /* Added */ 
            private IQueryable<Product> listProduct; 
            public IQueryable<Product> ListProduct 
            { 
                get { return listProduct; } 
                set { listProduct = value; } 
            } 
            #endregion 

    and in the .XAML file:
    --------------------------
       <telerikNavigation:RadPanelBar.ItemTemplate> 
                    <!-- WAS: ItemsSource="{Binding Path=Products}" -->  
                    <HierarchicalDataTemplate ItemsSource="{Binding Path=ListProduct}" 
                                              ItemTemplate="{StaticResource productTemplate}"

    So, all I did was get another list, and try to make it the itemsource. Now, nothing opens.
    I am thinking it could be
    a) I need to format it, as it may be returning an object that it does not know how to display... so another DataTemplate?
    b)  Some relationship needs to be set
    c) I am stupid?

    The other thought I had was if there was a way (using the original Products, not the ListProduct) to create a conditional display.
     I tried something but it did not work. Tried to set the Visibility to Hidden based on the column IsActive = false. I don't remember how I tried it (datatrigger?). Been a long night.

    Also, how do I determine what is the currently selected item and in what group? Is there a way in WPF to embed the Tag property with the primary key of the Product? I am thinking it should be simple , though I don't know the exact syntax
    Tag = "{BInding Source=ID}" or similar?
  11. Adam
    Adam avatar
    39 posts
    Member since:
    Jun 2009

    Posted 20 Jul 2009 Link to this post

    I don't see where to attach files... but if you use your code that you sent me, here are my changes:

    .cs file
    ---------
      private void Setup() 
            { 
                this.DataContext = this
                NorthwindDataContext dataContext = new NorthwindDataContext(); 
                ListCategory = from c in dataContext.Categories select c; 
                /* Added */ 
                ListProduct = from p in dataContext.Products 
                              where !p.ProductName.StartsWith("c")  // Eliminate Chai, Chang, etc. 
                              select p; 
            } 
     

         #region Added /* Added */ 
            private IQueryable<Product> listProduct; 
            public IQueryable<Product> ListProduct 
            { 
                get { return listProduct; } 
                set { listProduct = value; } 
            } 
            #endregion 

    and in the .XAML file:
    --------------------------
       <telerikNavigation:RadPanelBar.ItemTemplate> 
                    <!-- WAS: ItemsSource="{Binding Path=Products}" -->  
                    <HierarchicalDataTemplate ItemsSource="{Binding Path=ListProduct}" 
                                              ItemTemplate="{StaticResource productTemplate}"

    So, all I did was get another list, and try to make it the itemsource. Now, nothing opens.
    I am thinking it could be
    a) I need to format it, as it may be returning an object that it does not know how to display... so another DataTemplate?
    b)  Some relationship needs to be set
    c) I am stupid?

    The other thought I had was if there was a way (using the original Products, not the ListProduct) to create a conditional display.
     I tried something but it did not work. Tried to set the Visibility to Hidden based on the column IsActive = false. I don't remember how I tried it (datatrigger?). Been a long night.

    Also, how do I determine what is the currently selected item and in what group? Is there a way in WPF to embed the Tag property with the primary key of the Product? I am thinking it should be simple , though I don't know the exact syntax
    Tag = "{BInding Source=ID}" or similar?
  12. Answer
    Tihomir Petkov
    Admin
    Tihomir Petkov avatar
    576 posts

    Posted 21 Jul 2009 Link to this post

    Hello Adam,

    When using HierarchicalDataTemplates and DataTemplates you can bind to properties of the underlying data object only. In the code you sent, you were trying to bind to the ListProduct collection which is not a property of the Category class (what the top level of items is bound to). This is why you were not getting any child items.

    I updated the sample project to demonstrate how to filter the products in each category, without affecting the real data in the database. I assume you will only display the filtered categories and products since the RadPanelBar control does not support item editing.

    I implemented 2 possible approaches to your scenario. The first one is to create a partial Category class that augments the automatically generated one and add a helper FilteredProducts property that is taking care of filtering the products in each category according to their Discontinued property (you can easily swap that for your IsActive property). This is needed in order to avoid modifying the real data in the database, which is what happens if you filter the actual Products collection. With that partial class in place, you can bind to the FilteredProducts instead to the Products property in the HierarchicalDataTemplate.

    The second approach is to create a ValueConverter that will filter out the unnecessary products. My implementation returns an enumerator over the original products collection and, the same as the previous approach, leaves the original data intact.

    The sample project includes both approaches so you can take a look and decide which one suits you best. Let me know if this helps.

    Greetings,
    Tihomir Petkov
    the Telerik team

    Instantly find answers to your questions on the new Telerik Support Portal.
    Check out the tips for optimizing your support resource searches.
  13. Adam
    Adam avatar
    39 posts
    Member since:
    Jun 2009

    Posted 09 Aug 2009 Link to this post

    I am still having conceptual difficulty with master/detail binding.

    Suppose I am not pulling from a database, but instead create a couple of classes xCat and xProd.
    class xCat (int id, string name); 
    class xProd (int id, int parentID, string name); 

    new xCat(1, "Beverages");
    new xCat(2, "Shirts");
    new xProd(1, 1, "Coke");
    new xProd(2, 1, "Pepsi");
    new xProd(3, 2, "T-Shirt");



      public ObservableCollection<xCat> ListCat        { 
                get; 
                set; 
            } 
     
      public ObservableCollection<xProd> ListProd      { 
                get; 
                set; 
            } 

    Okay, I know that since these are 2 separate lists that have no master/detail binding that they cannot work together in the RadPanelBar.

    My question is, how can they?

    Do I create another class that does :
    newclass(xCat, xProd)

    Do I change the xProd class to take (int id, xCat cat, string name); ??

    Do I somehow combine these into a datatable / dataset / linq query ?

    Really, really confused...

    Ultimately, what I am trying to accomplish, is using the Design Guidance for Composite Applications for WPF, to setup a list of Modules  (such as Clients, Orders, Reports, Admin) and have the Tasks (such as Order - New, Order - Reservations) appear within the RadPanelBar AND be associated with a view that will be loaded into a region. Right now, this is all over my head.
  14. Tihomir Petkov
    Admin
    Tihomir Petkov avatar
    576 posts

    Posted 13 Aug 2009 Link to this post

    Hello Adam,

    In order to leave the structure of your underlying data intact, you can do two things:

    • In your viewmodel create a custom class which is basically a xCat plus a collection of xProd items. Then use the new class to create a collection that is suitable for binding to the panelbar control (with a HierarchicalDataTemplate).
    • Bind the panelbar control directly to the collection of xCat items, use a HierarchicalDataTemplate in combination with a custom ValueConverter for the ItemsSource property of the template. The converter should take the xCat object that is the item for the current root level panelbar item, search the collection of xProd objects and return a new collection of the relevant xProds only (which will become the child items of the current xCat).

    I believe both approaches will work for you, you just pick the one you like more. Let me know if you have further questions.

    Greetings,
    Tihomir Petkov
    the Telerik team

    Instantly find answers to your questions on the new Telerik Support Portal.
    Check out the tips for optimizing your support resource searches.
  15. ejb
    ejb avatar
    6 posts
    Member since:
    Dec 2006

    Posted 18 May 2011 Link to this post

    I was able to incorporate the posted example to my solution, the question that I have is:

    How do i handle a click event on one of the radpanel items? in posted example app, on click of one of the products, I would like to get the productID on click in code behind.  can you show me a code snippet that would do this?

    Thanks in advance,

    EJ
  16. Petar Mladenov
    Admin
    Petar Mladenov avatar
    2891 posts

    Posted 24 May 2011 Link to this post

    Hi ejb,

    I prepared a sample for you that uses the ItemClick event of the RadPanelBarItem. Please give it a try and let us know if it satisfies you.

    Best wishes,
    Petar Mladenov
    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
  17. ejb
    ejb avatar
    6 posts
    Member since:
    Dec 2006

    Posted 31 May 2011 Link to this post

    Your above answer does not work with the master detail example reference above ie: "wpf-panelbar-masterdetails-v2.zip",   Thats ok though i figured it out, I just used the tag property to hold the ID value....

    I do have a question that I need answered though and here it is:

    In the Binding MasterDetail example above "wpf-panelbar-masterdetails-v2.zip", how do i refresh the panelbar if changes are made to the backend data table(s) In this example, how would i show if additional products were added after the form was opened?, without closing and reopening Window1?

    Thanks in advance,

    E.J.
  18. Petar Mladenov
    Admin
    Petar Mladenov avatar
    2891 posts

    Posted 06 Jun 2011 Link to this post

    Hi ejb,

    The example mentioned uses old Telerik RadControl`s version (July 2009) in which the ItemClick event of the RadPanelBar and the Click of the RadPanelBarItem are not included. These events are officially introduced with the Q3 2010 SP1 (January 2011).
    Refreshing the RadPanelBar could be achieved from code behind. You could use a "Refresh" Button and rebind the ItemSource of the PanelBar(s)  in the Click event handler of the Button.
    Please let us know if you need further assistance or info.

    Best wishes,
    Petar Mladenov
    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
Back to Top
UI for WPF is Visual Studio 2017 Ready