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 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
It 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.