I have a RadGrid and a RadDataForm on the same page. Within the RadDataForm I have a three-tiered product selector that is comprised of three DataFormComboBoxField (they are stored in the underlying object in three fields):
Product
- Component
- Version
The ProductTree source table that populates the selector values is coming from the database is a single flat table (example):
| Product | Component | Version |
|---|---|---|
| Product A | Component A-1 | Version A-1-1 |
| Product A | Component A-1 | Version A-1-2 |
| Product A | Component A-2 | Version A-2-1 |
| Product A | Component A-2 | Version A-2-2 |
| Product B | Component B-1 | Version B-1-1 |
| Product B | Component B-1 | Version B-1-2 |
| Product B | Component B-2 | Version B-2-1 |
| Product B | Component B-2 | Version B-2-2 |
| ... | ... | ... |
To start, the Product DataFormComboBoxField should only display DISTINCT products. Then, when the Product DataFormComboBoxField is changed, the ItemSource for the Component DataFormComboBoxField should update accordingly and display just the DISTINCT Components for the selected Product; likewise when Component changes, Version should update accordingly. I won't go though all the various iterations I have tried to make this happen (custom methods and query parameters of the RadDomainDataSource, GroupDescriptors and FilterDescriptors, etc.); suffice to say I'm stumped and it ain't happening.
So without the noise of my failed attempts coloring your perceptions, how would YOU make this happen?
8 Answers, 1 is accepted
XAML
<telerik:DataFormComboBoxField Label="Product (Required):"> <telerik:DataFormComboBoxField.ContentTemplate> <DataTemplate> <telerik:RadComboBox x:Name="combo_Product" SelectedValue="{Binding Product, Mode=TwoWay}" DisplayMemberPath="Product" SelectedValuePath="Product" SelectionChanged="combo_Product_SelectionChanged"/> </DataTemplate> </telerik:DataFormComboBoxField.ContentTemplate></telerik:DataFormComboBoxField><telerik:DataFormComboBoxField Label="Component:"> <telerik:DataFormComboBoxField.ContentTemplate> <DataTemplate> <telerik:RadComboBox x:Name="combo_Component" SelectedValue="{Binding Component, Mode=TwoWay}" DisplayMemberPath="Component" SelectedValuePath="Component" SelectionChanged="combo_Component_SelectionChanged"/> </DataTemplate> </telerik:DataFormComboBoxField.ContentTemplate></telerik:DataFormComboBoxField><telerik:DataFormComboBoxField Label="Version:"> <telerik:DataFormComboBoxField.ContentTemplate> <DataTemplate> <telerik:RadComboBox x:Name="combo_Version" SelectedValue="{Binding Version, Mode=TwoWay}" DisplayMemberPath="FP" SelectedValuePath="FP"/> </DataTemplate> </telerik:DataFormComboBoxField.ContentTemplate>Code-Behind
#region Product Selectorsprivate void resourceDetail_CurrentItemChanged(object sender, EventArgs e){ loadProductSelector(); loadComponentSelector(); loadVersionSelector();}private void loadProductSelector(){ LoadOperation<GlobalLabManager.Web.ProductTree> loadProductTree = dc.Load(dc.GetProductTreesQuery()); loadProductTree.Completed += (s, a) => { var query = from p in loadProductTree.Entities orderby p.Product ascending group p by p.Product into pProd select pProd.FirstOrDefault(); var x = resourceDetail.ChildrenOfType<RadComboBox>().Where(rcb => rcb.Name == "combo_Product").First(); x.ItemsSource = query; };}private void loadComponentSelector(){ var item = rdds_Resources.DataView.CurrentItem as Web.Resource; if (item.Product != null) { LoadOperation<GlobalLabManager.Web.ProductTree> loadProductTree = dc.Load(dc.GetProductTreesQuery()); loadProductTree.Completed += (s, a) => { var _Prod = resourceDetail.ChildrenOfType<RadComboBox>().Where(rcb => rcb.Name == "combo_Product").First(); var query = from c in loadProductTree.Entities where c.Product == _Prod.SelectedValue.ToString() orderby c.Component ascending group c by c.Component into cComp select cComp.FirstOrDefault(); var x = resourceDetail.ChildrenOfType<RadComboBox>().Where(rcb => rcb.Name == "combo_Component").First(); x.ItemsSource = query; }; } else { var x = resourceDetail.ChildrenOfType<RadComboBox>().Where(rcb => rcb.Name == "combo_Component").First(); x.ItemsSource = null; }}private void loadVersionSelector(){ var item = rdds_Resources.DataView.CurrentItem as Web.Resource; if (item.Component != null) { LoadOperation<GlobalLabManager.Web.ProductTree> loadProductTree = dc.Load(dc.GetProductTreesQuery()); loadProductTree.Completed += (s, a) => { var _Prod = resourceDetail.ChildrenOfType<RadComboBox>().Where(rcb => rcb.Name == "combo_Product").First(); var _Comp = resourceDetail.ChildrenOfType<RadComboBox>().Where(rcb => rcb.Name == "combo_Component").First(); var query = from f in loadProductTree.Entities where f.Product == _Prod.SelectedValue.ToString() && f.Component == _Comp.SelectedValue.ToString() orderby f.FP ascending group f by f.FP into fFP select fFP.FirstOrDefault(); var x = resourceDetail.ChildrenOfType<RadComboBox>().Where(rcb => rcb.Name == "combo_Version").First(); x.ItemsSource = query; }; } else { var x = resourceDetail.ChildrenOfType<RadComboBox>().Where(rcb => rcb.Name == "combo_Version").First(); x.ItemsSource = null; }}private void combo_Product_SelectionChanged(object sender, Telerik.Windows.Controls.SelectionChangedEventArgs e){ loadComponentSelector();}private void combo_Component_SelectionChanged(object sender, Telerik.Windows.Controls.SelectionChangedEventArgs e){ loadVersionSelector();}#endregionIt works, but only when the page initially loads the first item of the underlying RadDomainDataSource. When I move to a different row of the grid, it throws an error as teh DataForm loads. I suspect that the SelectionChanged events are firing before the DataForm has finished loaded, but I'm not sure how to handle the order of events.
The struggle continues...
May I ask you to send us a sample project that illustrates your scenario? We will do our best to modify your it, in order to meet your requirements and send it back to you.
Regards,Ivan Ivanov
Telerik
Explore the entire Telerik portfolio by downloading Telerik DevCraft Ultimate.
I have downloaded GlobalLabManager, but as far as I can see the project does not use RadDataForm. Nevertheless, I will prepare a sample project from scratch and will send it to you tomorrow.
Regards,Ivan Ivanov
Telerik
Explore the entire Telerik portfolio by downloading Telerik DevCraft Ultimate.
Manage_Resource.xaml
<sdk:Page x:Class="GlobalLabManager.Views.Manage_Resource" xmlns:navigation="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Navigation" xmlns:telerik="http://schemas.telerik.com/2008/xaml/presentation" xmlns:Web="clr-namespace:GlobalLabManager.Web" mc:Ignorable="d" d:DesignWidth="1280" d:DesignHeight="960" Title="Manage Page"> <Grid x:Name="LayoutRoot" Margin="10"> <Grid.Resources> <DataTemplate x:Key="ResourceEditTempate"> <StackPanel> <telerik:DataFormComboBoxField Label="Location (Required):" DataMemberBinding="{Binding LocationFK, Mode=TwoWay}" ItemsSource="{Binding DataView, ElementName=rdds_Locations}" SelectedValuePath="ID" DisplayMemberPath="Location1" IsEnabled="True"/> <telerik:DataFormDataField Label="Resource (Required):" DataMemberBinding="{Binding Resource1, Mode=TwoWay}"/> <telerik:DataFormDataField Label="Description:" DataMemberBinding="{Binding Description, Mode=TwoWay}"/> <telerik:DataFormComboBoxField Label="Product (Required):"> <telerik:DataFormComboBoxField.ContentTemplate> <DataTemplate> <telerik:RadComboBox x:Name="combo_Product" SelectedValue="{Binding Product, Mode=TwoWay}" DisplayMemberPath="Product" SelectedValuePath="Product" SelectionChanged="combo_Product_SelectionChanged"/> </DataTemplate> </telerik:DataFormComboBoxField.ContentTemplate> </telerik:DataFormComboBoxField> <telerik:DataFormComboBoxField Label="Component:"> <telerik:DataFormComboBoxField.ContentTemplate> <DataTemplate> <telerik:RadComboBox x:Name="combo_Component" SelectedValue="{Binding Component, Mode=TwoWay}" DisplayMemberPath="Component" SelectedValuePath="Component" SelectionChanged="combo_Component_SelectionChanged"/> </DataTemplate> </telerik:DataFormComboBoxField.ContentTemplate> </telerik:DataFormComboBoxField> <telerik:DataFormComboBoxField Label="Version:"> <telerik:DataFormComboBoxField.ContentTemplate> <DataTemplate> <telerik:RadComboBox x:Name="combo_Version" SelectedValue="{Binding Version, Mode=TwoWay}" DisplayMemberPath="FP" SelectedValuePath="FP"/> </DataTemplate> </telerik:DataFormComboBoxField.ContentTemplate> </telerik:DataFormComboBoxField> <telerik:DataFormDataField Label="IP Address:" DataMemberBinding="{Binding IPAddress, Mode=TwoWay}"/> <telerik:DataFormDataField Label="Rack Location:" DataMemberBinding="{Binding RackLocation, Mode=TwoWay}"/> <telerik:DataFormCheckBoxField Label="Include in Reports:" DataMemberBinding="{Binding IncludeInReports, Mode=TwoWay}"/> <telerik:DataFormCheckBoxField Label="Is Manager:" DataMemberBinding="{Binding IsManager, Mode=TwoWay}"/> <telerik:DataFormComboBoxField Label="Manager:" DataMemberBinding="{Binding ManagerFK, Mode=TwoWay}" ItemsSource="{Binding DataView, ElementName=rdds_Managers}" SelectedValuePath="ID" DisplayMemberPath="Resource1"/> <telerik:DataFormDataField Label="OS:" DataMemberBinding="{Binding OS, Mode=TwoWay}"/> <telerik:DataFormDataField Label="OS Version:" DataMemberBinding="{Binding OSversion, Mode=TwoWay}"/> <telerik:DataFormDataField Label="DB:" DataMemberBinding="{Binding DB, Mode=TwoWay}"/> <telerik:DataFormDataField Label="DB Version:" DataMemberBinding="{Binding DBversion, Mode=TwoWay}"/> <telerik:DataFormDataField Label="Password Aging:" DataMemberBinding="{Binding PasswordAging, Mode=TwoWay}"/> </StackPanel> </DataTemplate> </Grid.Resources> <Grid.ColumnDefinitions> <ColumnDefinition Width="*"/> <ColumnDefinition Width="600"/> </Grid.ColumnDefinitions> <Grid.RowDefinitions> <RowDefinition Height="Auto"/> <RowDefinition/> </Grid.RowDefinitions> <!-- Page data sources --> <telerik:RadDomainDataSource x:Name="rdds_Resources" AutoLoad="True" QueryName="GetResourcesQuery"> <telerik:RadDomainDataSource.DomainContext> <Web:GlobalLabManagerDomainContext/> </telerik:RadDomainDataSource.DomainContext> <telerik:RadDomainDataSource.SortDescriptors> <telerik:SortDescriptor Member="Resource1" SortDirection="Ascending"/> </telerik:RadDomainDataSource.SortDescriptors> </telerik:RadDomainDataSource> <telerik:RadDomainDataSource x:Name="rdds_Locations" AutoLoad="True" QueryName="GetLocationsQuery"> <telerik:RadDomainDataSource.DomainContext> <Web:GlobalLabManagerDomainContext/> </telerik:RadDomainDataSource.DomainContext> <telerik:RadDomainDataSource.SortDescriptors> <telerik:SortDescriptor Member="Location1" SortDirection="Ascending"/> </telerik:RadDomainDataSource.SortDescriptors> </telerik:RadDomainDataSource> <telerik:RadDomainDataSource x:Name="rdds_Managers" AutoLoad="True" QueryName="GetManagersByLocQuery"> <telerik:RadDomainDataSource.DomainContext> <Web:GlobalLabManagerDomainContext/> </telerik:RadDomainDataSource.DomainContext> <telerik:RadDomainDataSource.QueryParameters> <telerik:QueryParameter ParameterName="locId" Value="{Binding ElementName=rdds_Resources, Path=DataView.CurrentItem.LocationFK}"/> </telerik:RadDomainDataSource.QueryParameters> <telerik:RadDomainDataSource.SortDescriptors> <telerik:SortDescriptor Member="Resource1" SortDirection="Ascending"/> </telerik:RadDomainDataSource.SortDescriptors> </telerik:RadDomainDataSource> <!-- Page Subheading --> <Border Background="#FF747678" Grid.ColumnSpan="2" Padding="10,5,0,5"> <TextBlock Text="Manage Resources" Style="{StaticResource PageSubheading}"/> </Border> <!-- Page controls --> <telerik:RadGridView x:Name="resourceGrid" ItemsSource="{Binding DataView, ElementName=rdds_Resources}" IsBusy="{Binding IsBusy, ElementName=rdds_Resources}" IsReadOnly="True" Grid.Column="0" Grid.Row="1" SelectionMode="Extended" AutoGenerateColumns="False" AlternationCount="2" AlternateRowBackground="#FFBEE2F4"> <telerik:RadGridView.Columns> <telerik:GridViewDataColumn DataMemberBinding="{Binding Resource1}" UniqueName="Resource" Header="Resource" MinWidth="200"/> <telerik:GridViewDataColumn DataMemberBinding="{Binding Location.Location1}" UniqueName="Location" Header="Location" MinWidth="200"/> <telerik:GridViewDataColumn DataMemberBinding="{Binding Product}" UniqueName="Product" Header="Product" MinWidth="250"/> </telerik:RadGridView.Columns> </telerik:RadGridView> <telerik:RadDataForm x:Name="resourceDetail" ItemsSource="{Binding DataView, ElementName=rdds_Resources}" Grid.Column="1" Grid.Row="1" AutoGenerateFields="False" AutoEdit="True" AutoCommit="True" CommandButtonsVisibility="Delete,Add,Cancel,Commit" ReadOnlyTemplate="{StaticResource ResourceEditTempate}" EditTemplate="{StaticResource ResourceEditTempate}" NewItemTemplate="{StaticResource ResourceEditTempate}" EditEnded="resourceDetail_EditEnded" DeletedItem="resourceDetail_DeletedItem" AddedNewItem="resourceDetail_AddedNewItem" CurrentItemChanged="resourceDetail_CurrentItemChanged"/> </Grid></sdk:Page>Manage_Resource.cs
using System;using System.Linq;using System.ServiceModel.DomainServices.Client;using System.Windows;using System.Windows.Controls;using Telerik.Windows.Controls;using GlobalLabManager.Web;namespace GlobalLabManager.Views{ public partial class Manage_Resource : Page { GlobalLabManagerDomainContext dc = new GlobalLabManagerDomainContext(); public Manage_Resource() { InitializeComponent(); } #region Product Selectors private void resourceDetail_CurrentItemChanged(object sender, EventArgs e) { loadProductSelector(); loadComponentSelector(); loadVersionSelector(); } private void loadProductSelector() { LoadOperation<GlobalLabManager.Web.ProductTree> loadProductTree = dc.Load(dc.GetProductTreesQuery()); loadProductTree.Completed += (s, a) => { var query = from p in loadProductTree.Entities orderby p.Product ascending group p by p.Product into pProd select pProd.FirstOrDefault(); var x = resourceDetail.ChildrenOfType<RadComboBox>().Where(rcb => rcb.Name == "combo_Product").First(); x.ItemsSource = query; }; } private void loadComponentSelector() { var item = rdds_Resources.DataView.CurrentItem as Web.Resource; if (item.Product != null) { LoadOperation<GlobalLabManager.Web.ProductTree> loadProductTree = dc.Load(dc.GetProductTreesQuery()); loadProductTree.Completed += (s, a) => { var _Prod = resourceDetail.ChildrenOfType<RadComboBox>().Where(rcb => rcb.Name == "combo_Product").First(); var query = from c in loadProductTree.Entities where c.Product == _Prod.SelectedValue.ToString() orderby c.Component ascending group c by c.Component into cComp select cComp.FirstOrDefault(); var x = resourceDetail.ChildrenOfType<RadComboBox>().Where(rcb => rcb.Name == "combo_Component").First(); x.ItemsSource = query; }; } else { var x = resourceDetail.ChildrenOfType<RadComboBox>().Where(rcb => rcb.Name == "combo_Component").First(); x.ItemsSource = null; } } private void loadVersionSelector() { var item = rdds_Resources.DataView.CurrentItem as Web.Resource; if (item.Component != null) { LoadOperation<GlobalLabManager.Web.ProductTree> loadProductTree = dc.Load(dc.GetProductTreesQuery()); loadProductTree.Completed += (s, a) => { var _Prod = resourceDetail.ChildrenOfType<RadComboBox>().Where(rcb => rcb.Name == "combo_Product").First(); var _Comp = resourceDetail.ChildrenOfType<RadComboBox>().Where(rcb => rcb.Name == "combo_Component").First(); var query = from f in loadProductTree.Entities where f.Product == _Prod.SelectedValue.ToString() && f.Component == _Comp.SelectedValue.ToString() orderby f.FP ascending group f by f.FP into fFP select fFP.FirstOrDefault(); var x = resourceDetail.ChildrenOfType<RadComboBox>().Where(rcb => rcb.Name == "combo_Version").First(); x.ItemsSource = query; }; } else { var x = resourceDetail.ChildrenOfType<RadComboBox>().Where(rcb => rcb.Name == "combo_Version").First(); x.ItemsSource = null; } } private void combo_Product_SelectionChanged(object sender, Telerik.Windows.Controls.SelectionChangedEventArgs e) { loadComponentSelector(); } private void combo_Component_SelectionChanged(object sender, Telerik.Windows.Controls.SelectionChangedEventArgs e) { loadVersionSelector(); } #endregion #region DataForm operations private void resourceDetail_EditEnded(object sender, Telerik.Windows.Controls.Data.DataForm.EditEndedEventArgs e) { this.rdds_Resources.SubmitChanges(); } private void resourceDetail_DeletedItem(object sender, Telerik.Windows.Controls.Data.DataForm.ItemDeletedEventArgs e) { this.rdds_Resources.SubmitChanges(); } private void resourceDetail_AddedNewItem(object sender, Telerik.Windows.Controls.Data.DataForm.AddedNewItemEventArgs e) { this.rdds_Resources.SubmitChanges(); } #endregion }}There are a lot of different way to go in order to create cascading combo box fields. One way to go is to handle the whole logic in your ViewModel. You can bind SelectedItem/ SelectedValue property of RadComboBox-es you used above to properties in your ViewModel, expose the source collections there as well and once a SelectedItem is changed - update the collection used for source of the combo boxes. You can check out this article for more information.
Another way to go is to handle SelectionChanged event of the each combo box and as soon as it is raised, update the source used as ItemsSource for the second combo box.
Yet another way to go is to add handler for SelectionChanged event of RadComboBox and handle all the logic inside (I am attaching a sample project illustrating this approach). The exact implementation depends on your exact scenario and custom logic. In the event handler you can specify which items to be loaded in the source depending on a particular parameter (that can be found by the arguments of the event).
Let me know in case you need further assistance.
Maya
Telerik
Explore the entire Telerik portfolio by downloading Telerik DevCraft Ultimate.
I use MVVM pattern, I try to load items inside combobox like this
<telerik:RadDataForm.NewItemTemplate> <DataTemplate> <StackPanel> <telerik:DataFormDataField DataMemberBinding="{Binding PositionCode, Mode=TwoWay}" Label="PositionCode"/> <telerik:DataFormDateField DataMemberBinding="{Binding EstimatedFromDate, Mode=TwoWay}" Label="Starting Date"/> <telerik:DataFormDateField DataMemberBinding="{Binding EstimatedThruDate, Mode=TwoWay}" Label="Ending Date"/> <telerik:DataFormCheckBoxField DataMemberBinding="{Binding SalaryFlag, Mode=TwoWay}" Label="Salary"/> <telerik:DataFormCheckBoxField DataMemberBinding="{Binding FullTimeFlag, Mode=TwoWay}" Label="Is Full-Time"/> <telerik:DataFormCheckBoxField DataMemberBinding="{Binding TemporaryFlag, Mode=TwoWay}" Label="Is Temporary"/> <telerik:DataFormComboBoxField ItemsSource="{Binding PositionTypeCollectionView}" DisplayMemberPath="Title" Label="Job Title" SelectedValuePath="PositionTypeId" DataMemberBinding="{Binding PositionTypeId, Mode=TwoWay}"/> </StackPanel> </DataTemplate> </telerik:RadDataForm.NewItemTemplate>I want to bind
<telerik:DataFormComboBoxField ItemsSource="{Binding PositionTypeCollectionView}"
to the PosititionTypeCollectionView .. a view of domainservice
and it is found on the viewmodel that is datacontext of user control which hold the DataForm!
plz help
DataContext of the fields is the corresponding data item. If you want to bind the ItemsSource to a property from your ViewModel, not from your business object, you need to specify the Source of the binding explicitly. For example:
<telerik:DataFormComboBoxField ItemsSource="{Binding PositionTypeCollectionView, Source={StaticResource MyViewModel}}" .... />Regards,
Maya
Telerik
Check out the Telerik Platform - the only platform that combines a rich set of UI tools with powerful cloud services to develop web, hybrid and native mobile apps.