Here are the changes I did to ForeignKey_Edit.aspx
// includes...
namespace KHS.Innopas.Web.DynamicData.FieldTemplates
{
public partial class ForeignKey_EditField : CascadingFieldTemplate
{
protected void Page_Init(object sender, EventArgs e)
{
// fixed: Assign ListControl information
ListControl = DropDownList1;
// add event handler if dependee exists
if (ParentControl != null)
{
// subscribe to event
ParentControl.SelectionChanged += SelectedIndexChanged;
// fixed: For performance reasons
// Make sure, that ParentControl.ListControl has AutoPostBack enabled.
// Default behaviour for this control was AutoPostBack = True.
// This caused a full postback for all controls that use this class, even
// if they don't need to do a postback (because they don't have a parent control).
if (ParentControl.ListControl != null)
ParentControl.ListControl.AutoPostBack = true;
}
}
}
}
Okay but back to my problem...
This is the new function I've placed in CascadingFieldTemplate.cs
// advanced populate list controlprotected void PopulateListControl(CheckBoxList listControl, String filterValue)
{
//get the parent columnif (ParentColumn == null)
{
// TODO: review this on monday...
// if no parent column then just call
// the base to populate the control
PopulateListControl(listControl);
// make sure control is enabled
listControl.Enabled = true;
}
else if (String.IsNullOrEmpty(filterValue))
{
// if there is a parent column but no filter value
// then make sure control is empty and disabled
listControl.Items.Clear();
if (Mode == DataBoundControlMode.Insert || !Column.IsRequired)
listControl.Items.Add(new ListItem("[Not Set]", ""));
// make sure control is disabled
listControl.Enabled = false;
}
else
{
// get the child columns table
var childTable = ChildrenColumn.ChildTable;
IList entityList = null;
ObjectContext objectContext = null;
if (Mode == DataBoundControlMode.Edit)
{
// Get the real entity from the wrapperobject entity = ((ICustomTypeDescriptor)Row).GetPropertyOwner(null);
// Get the collection of territories for this employee and make sure it's loaded
RelatedEnd entityCollection = (RelatedEnd)Column.EntityTypeProperty.GetValue(entity, null);
entityCollection.Load();
// Get an IList from it (i.e. the list of territories for the current employee)
// REVIEW: we should be using EntityCollection directly, but EF doesn't have a
// non generic type for it. They will add this in vnext
entityList = ((IListSource)entityCollection).GetList();
// Get the current ObjectContext
// REVIEW: this is quite a dirty way of doing this. Look for better alternative
ObjectQuery objectQuery = (ObjectQuery)entityCollection.GetType().GetMethod(
"CreateSourceQuery").Invoke(entityCollection, null);
objectContext = objectQuery.Context;
}
// get query {Table(Details)}
var query = ChildrenColumn.ChildTable.GetQuery(objectContext);
// get list of values filtered by the parent's selected entity
var itemlist = query.GetQueryFilteredByParent(ParentColumn, filterValue).OrderBy(childTable.SortColumn.SortExpression);
// clear list controls items collection before adding new items
listControl.Items.Clear();
// assign all valuesforeach (object row in itemlist)
{
// Create a checkbox for it
ListItem listItem = new ListItem(
childTable.GetDisplayString(row),
childTable.GetPrimaryKeyString(row));
if (Mode == DataBoundControlMode.Edit)
{
// mark assiciated
listItem.Selected = entityList.Contains(row);
}
listControl.Items.Add(listItem);
}
// make sure control is enabled
listControl.Enabled = true;
}
}
This function will be called by ManyToMany_Edit.aspx
using System;
using System.Data;
using System.Data.Objects;
using System.Data.Objects.DataClasses;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using System.Configuration;
using System.Collections;
using System.Collections.Specialized;
using System.Linq;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
using System.Xml.Linq;
using System.Web.DynamicData;
using KHS.Global.Web.DynamicData.CascadeExtensions;
namespace KHS.Innopas.Web.DynamicData.FieldTemplates
{
public partial class ManyToMany_EditField : CascadingFieldTemplate
{
protected void Page_Init(object sender, EventArgs e)
{
// add event handler if dependee existsif (ParentControl != null)
{
// subscribe to event
ParentControl.SelectionChanged += SelectedIndexChanged;
}
}
public void Page_Load(object sender, EventArgs e)
{
// Register for the DataSource's updating event
EntityDataSource ds = (EntityDataSource)this.FindDataSourceControl();
// This field template is used both for Editing and Inserting
ds.Updating += new EventHandler<EntityDataSourceChangingEventArgs>(DataSource_UpdatingOrInserting);
ds.Inserting += new EventHandler(DataSource_UpdatingOrInserting);
}
#region Event// consume eventprotected void SelectedIndexChanged(object sender, SelectionChangedEventArgs e)
{
PopulateListControl(CheckBoxList1, e.Value);
}
#endregion
void DataSource_UpdatingOrInserting(object sender, EntityDataSourceChangingEventArgs e)
{
MetaTable childTable = ChildrenColumn.ChildTable;
// Comments assume employee/territory for illustration, but the code is generic
// Get the collection of territories for this employee
RelatedEnd entityCollection = (RelatedEnd)Column.EntityTypeProperty.GetValue(e.Entity, null);
// In Edit mode, make sure it's loaded (doesn't make sense in Insert mode)if (Mode == DataBoundControlMode.Edit)
entityCollection.Load();
// Get an IList from it (i.e. the list of territories for the current employee)
// REVIEW: we should be using EntityCollection directly, but EF doesn't have a
// non generic type for it. They will add this in vnext
IList entityList = ((IListSource)entityCollection).GetList();
// Go through all the territories (not just those for this employee)foreach (object childEntity in childTable.GetQuery(e.Context))
{
// Check if the employee currently has this territorybool isCurrentlyInList = entityList.Contains(childEntity);
// Find the checkbox for this territory, which gives us the new statestring pkString = childTable.GetPrimaryKeyString(childEntity);
ListItem listItem = CheckBoxList1.Items.FindByValue(pkString);
if (listItem == null)
continue;
// If the states differs, make the appropriate add/remove changeif (listItem.Selected) {
if (!isCurrentlyInList)
entityList.Add(childEntity);
}
else {
if (isCurrentlyInList)
entityList.Remove(childEntity);
}
}
}
protected void CheckBoxList1_DataBound(object sender, EventArgs e)
{
if (ParentControl != null)
PopulateListControl(CheckBoxList1, ParentControl.ListControl.SelectedValue);
else
PopulateListControl(CheckBoxList1, "");
}
public override Control DataControl {
get {
return CheckBoxList1;
}
}
}
}
But at the moment I still have a problem with new PopulateListControl function on line 37 after SelectedIndexChanged event was called .
Error says something like "Variable 'Row' can only be used on databound controls" (very bad german/english translation).
Somebody any ideas?
Not today, not tomorrow, but maybe for monday! [:D]
Enjoy your weekend
Loopmaster
Marked as answer by Loopmaster on Jun 23, 2009 06:52 AM
Loopmaster
Member
15 Points
15 Posts
How to create a "Many To Many Cascade" Control
Jun 15, 2009 10:31 AM|LINK
Hi all
Does anyone have an idea, how to extend the ManyToMany_Edit control, so that we are able to make is cascadable.
I know that you can define a CascadeAttribute and I've seen it working on cascade filter control.
The default control (dropdownlist) works also for this attribute (But magic must be somewhere in function 'PopulateListControl()').
So I still have no idea, how GetQuery() stuff has to look like. [^o)]
Thanks for your help.
Loopmaster
sjnaughton
All-Star
27330 Points
5459 Posts
MVP
Re: How to create a "Many To Many Cascade" Control
Jun 15, 2009 03:32 PM|LINK
How do you mean making it cascade? do you want to filter the options based on another field?
Dynamic Data
Always seeking an elegant solution.
Loopmaster
Member
15 Points
15 Posts
Re: How to create a "Many To Many Cascade" Control
Jun 17, 2009 09:11 AM|LINK
Yep, that is exactly what I want to achieve.
Let's say I have a list of TOPICS and a list of DETAILS.
Each of these TOPICS and DETAILS can be belong to a certain department.
TOPICS and DETAILS themself have a n:m relation.
Now someone from department A has to define relations for a certain TOPIC.
1. He selects his department (A)
2. Dropdownlist containing TOPICS is prefiltered for department A (that is working for me)
3. ManyToMany_Edit Control has to prefilter DETAILS for selected department.
How does the code have to look like for ManyToMany_Edit Control?
Hope this helps you to understand me better. Technical stuff in a foreign language... [^o)]
Thanks for your help
Loopmaster
sjnaughton
All-Star
27330 Points
5459 Posts
MVP
Re: How to create a "Many To Many Cascade" Control
Jun 17, 2009 11:04 AM|LINK
OK I think you want to have a look at this article on my blog here Cascading Filters and Fields – Dynamic Data Entity Framework Version
Dynamic Data Cascading Filters Cascading FieldTemplates
Always seeking an elegant solution.
Loopmaster
Member
15 Points
15 Posts
Re: How to create a "Many To Many Cascade" Control
Jun 17, 2009 12:56 PM|LINK
Hi Steve
Thank you for the link. I will check that... Tomorrow! [:)]
Loopmaster
Member
15 Points
15 Posts
Re: How to create a "Many To Many Cascade" Control
Jun 19, 2009 05:57 AM|LINK
I'm still working on this issue.
Am I correct, if ManyToMany_Edit.aspx control inherts from CascadingFieldTemplate class mentioned in sample code given?
sjnaughton
All-Star
27330 Points
5459 Posts
MVP
Re: How to create a "Many To Many Cascade" Control
Jun 19, 2009 12:38 PM|LINK
No sorry it inhertis from FieldTemplateUserControlSorry I think I see what you mean so the answer is yes if you are making the ManyToMany_Edit.aspx a CascadingFieldTemplate.
Dynamic Data Many to Many Cascading FieldTemplates
Always seeking an elegant solution.
Loopmaster
Member
15 Points
15 Posts
Re: How to create a "Many To Many Cascade" Control
Jun 19, 2009 02:55 PM|LINK
Okay
This is what works for me.
Here are the changes I did to ForeignKey_Edit.aspx
// includes... namespace KHS.Innopas.Web.DynamicData.FieldTemplates { public partial class ForeignKey_EditField : CascadingFieldTemplate { protected void Page_Init(object sender, EventArgs e) { // fixed: Assign ListControl information ListControl = DropDownList1; // add event handler if dependee exists if (ParentControl != null) { // subscribe to event ParentControl.SelectionChanged += SelectedIndexChanged; // fixed: For performance reasons // Make sure, that ParentControl.ListControl has AutoPostBack enabled. // Default behaviour for this control was AutoPostBack = True. // This caused a full postback for all controls that use this class, even // if they don't need to do a postback (because they don't have a parent control).Okay but back to my problem...
This is the new function I've placed in CascadingFieldTemplate.cs
This function will be called by ManyToMany_Edit.aspx
sjnaughton
All-Star
27330 Points
5459 Posts
MVP
Re: How to create a "Many To Many Cascade" Control
Jun 23, 2009 09:21 AM|LINK
The issue here is you are trying to access Row before the OnDataBound event, because before that is does not contain a valid object. [:D]
Dynamic Data FieldTemplate Row OnDataBound
Always seeking an elegant solution.
Parimal
Member
10 Points
6 Posts
Re: How to create a "Many To Many Cascade" Control
Dec 08, 2009 12:15 AM|LINK
Hi
I am looking for something like that you are doing, Many To Many cascade filter. Is it possible you can share cascade extension so i can implement .
Thanks