locked
Setting ValidationGroup on DynamicValidator and DynamicControl has no effect RRS feed

  • Question

  • User1475640560 posted

    Has anyone found a way to have multiple Dynamic Data DetailsView controls on the same page and have their child controls validate in different ValidationGroups?  When I set ValidationGroup on the DynamicValidator and/or DynamicControl, the elements inside the DetailsView (DynamicField or DynamicControl) don't receive the ValidationGroup attribute (they validate in the default ValidationGroup and appear in the ValidationSummary only if it is not assigned to a ValidationGroup).

     Richard
       
     

    Thursday, July 10, 2008 5:24 PM

Answers

  • User-330204900 posted

    This is the working version [:D]

     

    using System;
    using System.Collections;
    using System.Collections.Generic;
    using System.Web.DynamicData;
    using System.Web.UI;
    using System.Web.UI.WebControls;
    
    public class ValidationGroupFieldsManager : IAutoFieldGenerator
    {
    	protected MetaTable _table;
    	protected String _validationGroup;
    
    	public ValidationGroupFieldsManager(MetaTable table, String validationGroup)
    	{
    		_table = table;
    		_validationGroup = validationGroup;
    	}
    
    	public ICollection GenerateFields(Control control)
    	{
    		List<DYNAMICFIELD> oFields = new List<DYNAMICFIELD>();
    
    		foreach (MetaColumn column in _table.Columns)
    		{
    
    			// carry on the loop at the next column  
    			// if scaffold table is set to false or DenyRead
    			if (!column.Scaffold)
    				continue;
    
    			// create a new field with its validation group set
    			DynamicField f = new ValidationGroupDynamicField(_validationGroup);
    
    			f.DataField = column.Name;
    			oFields.Add(f);
    		}
    		return oFields;
    	}
    }
    
    // special thanks to David Ebbo for this
    public class ValidationGroupDynamicField : DynamicField
    {
    	protected String _validationGroup;
    
    	public ValidationGroupDynamicField(String validationGroup)
    	{
    		_validationGroup = validationGroup;
    	}
    
    	public override void InitializeCell(
    		DataControlFieldCell cell,
    		DataControlCellType cellType,
    		DataControlRowState rowState,
    		int rowIndex)
    	{
    		if (cellType == DataControlCellType.DataCell)
    		{
    			var control = new DynamicControl()
    				{
    					DataField = DataField,
    					// Copy various properties into the control
    					UIHint = UIHint,
    					HtmlEncode = HtmlEncode,
    					NullDisplayText = NullDisplayText,
    					// set ValidationGroup
    					ValidationGroup = _validationGroup
    				};
    
    			if ((rowState & DataControlRowState.Edit) != 0)
    				control.Mode = DataBoundControlMode.Edit;
    
    			if ((rowState & DataControlRowState.Insert) != 0)
    				control.Mode = DataBoundControlMode.Insert;
    
    			cell.Controls.Add(control);
    		}
    		else
    		{
    			base.InitializeCell(cell, cellType, rowState, rowIndex);
    		}
    	}
    }
    
     
    • Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
    Friday, July 11, 2008 2:01 PM
  • User660823006 posted

    We are adding ValidationGroup to the DynamicField in the next version of Dynamic Data based on your guys feedback.

    • Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
    Monday, January 19, 2009 12:54 PM

All replies

  • User-330204900 posted

    Hi I've not done the validation yet but I don't see why it won't work see my blog post on CustomPages Part 1 - Standard Custom Page Dynamic Data and Custom Pages 

    Hope this helps [:D]

    Thursday, July 10, 2008 6:16 PM
  • User1475640560 posted

    I've been doing stuff similar to that, and I'm looking forward to part 3!  

    However, if you use the same Orders Custom Page from Northwind that we were talking about in the other thread, and try to add a ValidationGroup, you'll see that it doesn't work.  For example, replace the default ValidationSummary and DynamicValidator with these:

                <h3>Default Validation Summary:</h3>
                <asp:ValidationSummary ID="ValidationSummary1" runat="server" ValidationGroup=""
                    HeaderText="List of validation errors" />
                <h3>"Group1" Validation Summary:</h3>
                <asp:ValidationSummary ID="ValidationSummary2" runat="server" ValidationGroup="Group1"
                    HeaderText="List of validation errors" />
                <asp:DynamicValidator runat="server" ID="DetailsViewValidator" ValidationGroup="Group1" ControlToValidate="DetailsView1" Display="Static" />


    Also add a Dynamic Control (along with the auto-generated rows) so you can explicitly set a ValidationGroup there:

                 <asp:DetailsView ID="DetailsView1" runat="server" DataSourceID="DetailsDataSource" DefaultMode="Edit"
                    AutoGenerateEditButton="True" OnItemCommand="DetailsView1_ItemCommand" OnItemUpdated="DetailsView1_ItemUpdated"
                    CssClass="detailstable" FieldHeaderStyle-CssClass="bold" AutoGenerateRows="true" >
                    <Fields>
                        <asp:DynamicField DataField="OrderDate"></asp:DynamicField>
                        <asp:TemplateField>
                            <EditItemTemplate><asp:DynamicControl runat="server" DataField="OrderDate" ValidationGroup="Group1" />
                            </EditItemTemplate>
                        </asp:TemplateField>
                    </Fields>
                </asp:DetailsView>


    Finally, add a couple of buttons, one for each "group":

    <asp:Button ID="Button1" runat="server" CausesValidation="true" ValidationGroup="" Text="Validate Default Group" />
    <asp:Button ID="Button2" runat="server" CausesValidation="true" ValidationGroup="Group1" Text="Validate Group1" />

    Then try some validation with each button and see when and where the messages show up.  You'll quickly realize there is nothing in "Group1".

     Richard
     

    Thursday, July 10, 2008 7:14 PM
  • User1475640560 posted

     Oh, and if you haven't employed my DateTime validation hack, then you'll want to choose something other than "OrderDate" for the DynamicControl DataField or else it won't validate at all with the buttons!

    Thursday, July 10, 2008 7:20 PM
  • User933528419 posted

    I guess the problem here is that you have the same field using different validation groups. So it's always using the blank one for the DynamicField.
    If you remove the DynamicField, set the AutoGenerateRows to false and leave the DynamicControl only, it should start showing messages for Group1 validation group (in this case I set a RequiredAttribute so I could see the validation happening).
    You also need to set the Mode property in your DynamicControl to Edit, otherwise it won't display the field for editing, only read-only.

    But do you really need to set the ValidationGroup in this case?
    I would recommend using the ValidationGroup when you have a ListView control for example and you're trying to differentiate controls that should be validated by the Update button from the ones validated by the Insert button.

    I hope this helps.

    Maíra

    Thursday, July 10, 2008 9:49 PM
  • User1475640560 posted

    I think I misunderstood the purpose of the asp:DynamicValidator in this scenario.  Since it was set to validate the DetailsView, I thought that would convey the ValidationGroup to the DynamicFields within the DetailsView.  As far as I can tell, there is no way to set the ValidationGroup for a DynamicField.  You are correct that if I convert everything to DynamicControl, I can successfully set the validation group for the entire DetailsView.  However, if I go that route, I also have to set AutoGenerateEditButton to false because the auto-generated "Update" link always validates the default validation group (meaning it will not cause validation on any asp:DynamicControls with their ValidationGroup set).  So then I have to create my own update and cancel buttons.  All in all, not quite as dynamic as I would have hoped. 

    As to your question of why I need to use validation groups... basically I have UserControls that I add to the page programmatically.  Within those, I have various views (FormViews, DetailsViews, ListViews, soemetimes just WebForms--depending on the module).  Because these have separate purposes and disparate placements on the page, I need to be able to segment them into validation groups.  Ultimately I'd like to be able to set the ValidationGroup at runtime, but it's easier to demonstrate the problem with a trivial static example like above (and below).  I've been leaning toward doing as much as possible with the model and DynamicField because it's the fastest and tersest approach, but it seems like when I need to set the ValidationGroup that's not going to be an option.

    Here's my test Orders/Edit.aspx page.  I have Freight and OrderDate set to [Required] in the model.  If you click "Update" validation does not occur. 

    <%@ Page Language="C#" MasterPageFile="~/Site.master" CodeFile="Edit.aspx.cs" Inherits="Edit" %>
    <asp:Content ID="Content1" ContentPlaceHolderID="ContentPlaceHolder1" Runat="Server">
        <asp:DynamicDataManager ID="DynamicDataManager1" runat="server" AutoLoadForeignKeys="true" />
        <h2>Edit entry from table <%= table.DisplayName %></h2>

        <asp:ScriptManagerProxy runat="server" ID="ScriptManagerProxy1" />
       

        <h3>Validation Summary ""</h3>
        <asp:ValidationSummary ID="ValidationSummary1" runat="server" ValidationGroup="" EnableClientScript="true"
            HeaderText="List of validation errors" />
       

        <h3>Validation Summary Group1</h3>
        <asp:ValidationSummary ID="ValidationSummary2" runat="server" ValidationGroup="Group1" EnableClientScript="true"
            HeaderText="List of validation errors" />
       

        <asp:DynamicValidator runat="server" ID="DetailsViewValidator" ControlToValidate="DetailsView1" ValidationGroup="Group1" Display="None" />

        <asp:DetailsView ID="DetailsView1" runat="server" DataSourceID="DetailsDataSource" DefaultMode="Edit"
            AutoGenerateEditButton="True" OnItemCommand="DetailsView1_ItemCommand" OnItemUpdated="DetailsView1_ItemUpdated"
            CssClass="detailstable" FieldHeaderStyle-CssClass="bold" AutoGenerateRows="false">
        <Fields>
            <asp:TemplateField>
                <EditItemTemplate><asp:DynamicControl ID="DynamicControl2" runat="server" Mode="Edit" DataField="Freight" ValidationGroup="Group1" />
                </EditItemTemplate>
            </asp:TemplateField>
            <asp:TemplateField>
                <EditItemTemplate><asp:DynamicControl ID="DynamicControl3" runat="server" Mode="Edit" DataField="OrderDate" ValidationGroup="Group1" />
                </EditItemTemplate>
            </asp:TemplateField>
        </Fields>
        </asp:DetailsView>

        <asp:LinqDataSource ID="DetailsDataSource" runat="server" EnableUpdate="true">
            <WhereParameters>
                <asp:DynamicQueryStringParameter />
            </WhereParameters>
        </asp:LinqDataSource>
       

        <asp:Button ID="Button2" runat="server" CausesValidation="true" ValidationGroup="Group1" Text="Validate Group1" />
        <asp:Button ID="Button1" runat="server" CausesValidation="true" ValidationGroup="" Text="Validate Default Group" />
    </asp:Content>
     

     Richard
     

    Thursday, July 10, 2008 11:27 PM
  • User933528419 posted

    I was able to repro the problem you're having. I'll follow up with the team on this one as well. Maybe it's the same problem as Marcin reported in the other thread.

    Maíra

    Friday, July 11, 2008 12:30 AM
  • User-330204900 posted

    This is just a thought on applying a validation group.

    What I thought you could do is if create a class that implements IAutoFieldGenerator and pass it the string value of your ValidationGroup you could then apply the validation group by creating your own ValidationGroupDynamicField that inherits DynamicField as below:

    using System;
    using System.Collections;
    using System.Collections.Generic;
    using System.Web.DynamicData;
    using System.Web.UI;
    using System.Web.UI.WebControls;
    
    public class FilteredFieldsManager : IAutoFieldGenerator
    {
    	protected MetaTable _table;
    	protected String _validationGroup;
    
    	public FilteredFieldsManager(MetaTable table, String validationGroup)
    	{
    		_table = table;
    		_validationGroup = validationGroup;
    	}
    
    	public ICollection GenerateFields(Control control)
    	{
    		List<DYNAMICFIELD> oFields = new List<DYNAMICFIELD>();
    
    		foreach (MetaColumn column in _table.Columns)
    		{
    
    			// carry on the loop at the next column  
    			// if scaffold table is set to false or DenyRead
    			if (!column.Scaffold)
    				continue;
    
    			// create a new field with its validation group set
    			DynamicField f = new ValidationGroupDynamicField(_validationGroup);
    
    			f.DataField = column.Name;
    			oFields.Add(f);
    		}
    		return oFields;
    	}
    }
    
    // special thanks to david Ebbo for this
    public class ValidationGroupDynamicField : DynamicField
    {
    	protected String _validationGroup;
    
    	public ValidationGroupDynamicField(String validationGroup)
    	{
    		_validationGroup = validationGroup;
    	}
    	public override void InitializeCell(
    		DataControlFieldCell cell,
    		DataControlCellType cellType,
    		DataControlRowState rowState,
    		int rowIndex)
    	{
    		if (cellType == DataControlCellType.DataCell)
    		{
    			var control = new DynamicControl() { DataField = DataField };
    
    			// Copy various properties into the control
    			control.UIHint = UIHint;
    			control.HtmlEncode = HtmlEncode;
    			control.NullDisplayText = NullDisplayText;
    
    			control.ValidationGroup = _validationGroup;
    			cell.Controls.Add(control);
    		}
    		else
    		{
    			base.InitializeCell(cell, cellType, rowState, rowIndex);
    		}
    	}
    }
    

    Hopr this helps [:D]

    Friday, July 11, 2008 4:33 AM
  • User-330204900 posted

    Oh I forget to mention how to use this [:$]

    So her we go, in the page you want to use this on in the Page_Init event handler add bits in bold

    protected void Page_Init(object sender, EventArgs e)
    {
    	DynamicDataManager1.RegisterControl(GridView1, true /*setSelectionFromUrl*/);
    
    	// code to add column level security
    	table = GridDataSource.GetTable();

    // code for Editable GridView GridView1.ColumnsGenerator = new ValidationGroupFieldsManager(table, "Test");

    // code for Ediable DetailsView
    DetailsView1.RowsGenerator = new ValidationGroupFieldsManager(table, "Test");
    }

    Hope this does it [:D]

    Friday, July 11, 2008 4:55 AM
  • User1475640560 posted

    Thanks Steve!

    I just tried this, and it does work, with a few caveats:

    It only works for auto-generated rows.  If I use <asp:DynamicFields in the <Fields> collection, they still end up in the default group. 

    So what I did was take your ValidationGroupDynamicField and turn it into a freestanding field and then Register it in the page like so:

     

    namespace ValidationField.cs
    {

    using System;
    using System.Collections;
    using System.Collections.Specialized;
    using System.ComponentModel;
    using System.Security.Permissions;
    using System.Web;
    using System.Web.UI;
    using System.Web.UI.WebControls;
    using System.Collections.Generic;
    using System.Web.DynamicData;

    [AspNetHostingPermission(SecurityAction.Demand,
    Level = AspNetHostingPermissionLevel.Minimal)]
    public sealed class ValidationGroupDynamicField : DynamicField
    {
    public ValidationGroupDynamicField()
    {
    _validationGroup = "";
    }
    protected String _validationGroup;
    public String ValidationGroup { get { return _validationGroup; } set { _validationGroup = value; } }
    public ValidationGroupDynamicField(String validationGroup)
    {
    _validationGroup = validationGroup;
    }
    public override void InitializeCell(
    DataControlFieldCell cell,
    DataControlCellType cellType,
    DataControlRowState rowState,
    int rowIndex)
    {
    if (cellType == DataControlCellType.DataCell)
    {
    var control = new DynamicControl() { DataField = DataField };

    // Copy various properties into the control control.UIHint = UIHint; control.HtmlEncode = HtmlEncode; control.NullDisplayText = NullDisplayText; // was defaulting to ReadOnly control.Mode = DataBoundControlMode.Edit; control.ValidationGroup = _validationGroup; cell.Controls.Add(control); } else { base.InitializeCell(cell, cellType, rowState, rowIndex);
    }
    }
    }

    }

     
    Then in the page I can include a Register directive
      

    <%@ Register TagPrefix="aspMyField" Namespace="ValidationField.cs" Assembly="App_Code/ValidationField.cs" %>
     And then call the field inside my DetailsView:  
    <aspMyField:ValidationGroupDynamicField DataField="Freight" ValidationGroup="Group1"></aspMyField:ValidationGroupDynamicField>
    <aspMyField:ValidationGroupDynamicField DataField="OrderDate" ValidationGroup="Group1"></aspMyField:ValidationGroupDynamicField>


    However, neither of these approaches (yours or mine) seem able to pick up the "Mode" from the context.  So you'll see in my code above that I set the mode manually, which wouldn't be ideal. 

    Any idea how to set the mode from context in this scenario?  It has always seemed odd to me that we have to set the mode manually on DynamicControl but not DynamicField.

     

    Richard
     

    Friday, July 11, 2008 11:36 AM
  • User-330204900 posted

    How about this?

    <STRIKE>using System;
    using System.Collections;
    using System.Collections.Generic;
    using System.Web.DynamicData;
    using System.Web.UI;
    using System.Web.UI.WebControls;
    
    public class ValidationGroupFieldsManager : IAutoFieldGenerator
    {
    	protected MetaTable _table;
    	protected String _validationGroup;
    
    	public ValidationGroupFieldsManager(MetaTable table, String validationGroup)
    	{
    		_table = table;
    		_validationGroup = validationGroup;
    	}
    
    	public ICollection GenerateFields(Control control)
    	{
    		List<DYNAMICFIELD> oFields = new List<DYNAMICFIELD>();
    
    		foreach (MetaColumn column in _table.Columns)
    		{
    
    			</STRIKE><STRIKE>// carry on the loop at the next column  
    			// if scaffold table is set to false or DenyRead
    			if (!column.Scaffold)
    				continue;
    
    			// create a new field with its validation group set
    			DynamicField f = new ValidationGroupDynamicField(_validationGroup);
    
    			f.DataField = column.Name;
    			oFields.Add(f);
    		}
    		return oFields;
    	}
    }
    
    // special thanks to David Ebbo for this
    public class ValidationGroupDynamicField : DynamicField
    {
    	protected String _validationGroup;
    
    	public ValidationGroupDynamicField(String validationGroup)
    	{
    		_validationGroup = validationGroup;
    	}
    
    	public override void InitializeCell(
    		DataControlFieldCell cell,
    		DataControlCellType cellType,
    		DataControlRowState rowState,
    		int rowIndex)
    	{
    		if (cellType == DataControlCellType.DataCell)
    		{
    			var control = new DynamicControl()
    				{
    					DataField = DataField,
    					// Copy various properties into the control
    					UIHint = UIHint,
    					HtmlEncode = HtmlEncode,
    					NullDisplayText = NullDisplayText,
    					// set ValidationGroup
    					ValidationGroup = _validationGroup
    				};
    </STRIKE><STRIKE>			switch (rowState)
    			{
    				case DataControlRowState.Edit:
    					control.Mode = DataBoundControlMode.Edit;
    					break;
    				case DataControlRowState.Insert:
    					control.Mode = DataBoundControlMode.Insert;
    					break;
    				case DataControlRowState.Normal:
    				case DataControlRowState.Selected:
    				case DataControlRowState.Alternate:
    				default:
    					control.Mode = DataBoundControlMode.ReadOnly;
    					break;
    			}
    
    			cell.Controls.Add(control);
    		}
    		else
    		{
    			base.InitializeCell(cell, cellType, rowState, rowIndex);
    		}
    	}
    }</STRIKE>

    That switch was bogus as the rowState can have multiple values i.e. Edit | Alternate [:$] In the <STRIKE>switch</STRIKE> if statements you set the mode when the filed is genrated, what do you think?

    Friday, July 11, 2008 1:39 PM
  • User-330204900 posted

    This is the working version [:D]

     

    using System;
    using System.Collections;
    using System.Collections.Generic;
    using System.Web.DynamicData;
    using System.Web.UI;
    using System.Web.UI.WebControls;
    
    public class ValidationGroupFieldsManager : IAutoFieldGenerator
    {
    	protected MetaTable _table;
    	protected String _validationGroup;
    
    	public ValidationGroupFieldsManager(MetaTable table, String validationGroup)
    	{
    		_table = table;
    		_validationGroup = validationGroup;
    	}
    
    	public ICollection GenerateFields(Control control)
    	{
    		List<DYNAMICFIELD> oFields = new List<DYNAMICFIELD>();
    
    		foreach (MetaColumn column in _table.Columns)
    		{
    
    			// carry on the loop at the next column  
    			// if scaffold table is set to false or DenyRead
    			if (!column.Scaffold)
    				continue;
    
    			// create a new field with its validation group set
    			DynamicField f = new ValidationGroupDynamicField(_validationGroup);
    
    			f.DataField = column.Name;
    			oFields.Add(f);
    		}
    		return oFields;
    	}
    }
    
    // special thanks to David Ebbo for this
    public class ValidationGroupDynamicField : DynamicField
    {
    	protected String _validationGroup;
    
    	public ValidationGroupDynamicField(String validationGroup)
    	{
    		_validationGroup = validationGroup;
    	}
    
    	public override void InitializeCell(
    		DataControlFieldCell cell,
    		DataControlCellType cellType,
    		DataControlRowState rowState,
    		int rowIndex)
    	{
    		if (cellType == DataControlCellType.DataCell)
    		{
    			var control = new DynamicControl()
    				{
    					DataField = DataField,
    					// Copy various properties into the control
    					UIHint = UIHint,
    					HtmlEncode = HtmlEncode,
    					NullDisplayText = NullDisplayText,
    					// set ValidationGroup
    					ValidationGroup = _validationGroup
    				};
    
    			if ((rowState & DataControlRowState.Edit) != 0)
    				control.Mode = DataBoundControlMode.Edit;
    
    			if ((rowState & DataControlRowState.Insert) != 0)
    				control.Mode = DataBoundControlMode.Insert;
    
    			cell.Controls.Add(control);
    		}
    		else
    		{
    			base.InitializeCell(cell, cellType, rowState, rowIndex);
    		}
    	}
    }
    
     
    • Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
    Friday, July 11, 2008 2:01 PM
  • User-330204900 posted

    I also though of this for those situations where you have used DynamicControl but you want the Mode to be dynamic:

    protected void gvOrders_RowDataBound(object sender, GridViewRowEventArgs e)
    {
    	if (e.Row.RowType == DataControlRowType.DataRow)
    	{
    		foreach (TableCell cell in e.Row.Cells)
    		{
    			var df = cell.Controls.OfType<DYNAMICCONTROL>().SingleOrDefault();
    			if (df != null)
    			{
    				if ((e.Row.RowState & DataControlRowState.Edit) != 0)
    					df.Mode = DataBoundControlMode.Edit;
    
    				if ((e.Row.RowState & DataControlRowState.Insert) != 0)
    					df.Mode = DataBoundControlMode.Insert;
    			}
    		}
    	}
    }
    
    Friday, July 11, 2008 5:20 PM
  • User1475640560 posted

    Works perfectly!

    Thanks (again) Steve!
     

    Friday, July 11, 2008 5:23 PM
  • User933528419 posted

    Just in case somebody's searching how to set the ValidationGroup when using DetailsView...

    When you're setting the ValidationGroup, it means you're using the DynamicControl control in templates or template fields. In this case, you cannot use the auto-generated buttons for edit or insert operations, you must also place them in template fields to be able to set the ValidationGroup property. Otherwise, the auto-generated button will have an empty validation group.

    So the DetailsView control presented earlier would look something similar to this:

    <asp:DetailsView ID="DetailsView1" runat="server" 
      DataSourceID="DetailsDataSource" DefaultMode="Edit" 
      OnItemCommand="DetailsView1_ItemCommand" OnItemUpdated="DetailsView1_ItemUpdated"
      CssClass="detailstable" FieldHeaderStyle-CssClass="bold" 
      AutoGenerateRows="False">
        <Fields>
          <asp:TemplateField HeaderText="Order Date">
            <EditItemTemplate>                      
              <asp:DynamicControl runat="server" DataField="OrderDate" Mode="Edit" ValidationGroup="Group1" />
            </EditItemTemplate>
          </asp:TemplateField>
          <asp:TemplateField ShowHeader="false">
            <EditItemTemplate>                      
              <asp:LinkButton ID="LinkButton1" runat="server" CommandName="Update" Text="Update" ValidationGroup="Group1" />
              <asp:LinkButton ID="LinkButton2" runat="server" CausesValidation="False" CommandName="Cancel" Text="Cancel" />
            </EditItemTemplate>
          </asp:TemplateField>
        </Fields>
    </asp:DetailsView>

    I hope this helps.

    Maíra

    Tuesday, July 15, 2008 6:59 PM
  • User-330204900 posted

    <STRIKE>Re my post to the wrong thread [:$] here </STRIKE><STRIKE>Re: How to submit and validate a dynamic data page programatically?</STRIKE><STRIKE>  in the version which ValidationGroup and add the ValidationGroup at runtime to DynamicField and fails as in the post above if I remove ALL referance to ValidationGroup in page as well as the ValidationGroupDynamicField used in the ValidationGroupFieldsManager I get no Exception. So the problem appears to be when ValidationGroup is set in the ValidationGroupDynamicField at runtime.</STRIKE>

    <STRIKE>So my question is am I doing somthing wrong?</STRIKE>

    <STRIKE>Here's my code to set the ValidationGroup at runtime: </STRIKE>

    <STRIKE>using System;
    using System.Collections;
    using System.Collections.Generic;
    using System.Web.DynamicData;
    using System.Web.UI;
    using System.Web.UI.WebControls;
    
    public class ValidationGroupFieldsManager : IAutoFieldGenerator
    {
    	protected MetaTable _table;
    	protected String _validationGroup;
    
    	public ValidationGroupFieldsManager(MetaTable table, String validationGroup)
    	{
    		_table = table;
    		_validationGroup = validationGroup;
    	}
    
    	public ICollection GenerateFields(Control control)
    	{
    		List<DYNAMICFIELD> oFields = new List<DYNAMICFIELD>();
    
    		foreach (MetaColumn column in _table.Columns)
    		{
    
    			</STRIKE><STRIKE>// carry on the loop at the next column  
    			// if scaffold table is set to false or DenyRead
    			if (!column.Scaffold)
    				continue;
    
    			// create a new field with its validation group set
    			DynamicField f = new ValidationGroupDynamicField(_validationGroup);
    
    			f.DataField = column.Name;
    			oFields.Add(f);
    		}
    		return oFields;
    	}
    }
    
    // special thanks to David Ebbo for this
    public class ValidationGroupDynamicField : DynamicField
    {
    	protected String _validationGroup;
    
    	public ValidationGroupDynamicField(String validationGroup)
    	{
    		_validationGroup = validationGroup;
    	}
    
    	public override void InitializeCell(
    		DataControlFieldCell cell,
    		DataControlCellType cellType,
    		DataControlRowState rowState,
    		int rowIndex)
    	{
    		if (cellType == DataControlCellType.DataCell)
    		{
    			var control = new DynamicControl()
    				{
    					DataField = DataField,
    
    					// Copy various properties into the control
    					UIHint = UIHint,
    					HtmlEncode = HtmlEncode,
    					NullDisplayText = NullDisplayText,
    
    					// set ValidationGroup
    					ValidationGroup = _validationGroup
    				};
    
    			if ((rowState & DataControlRowState.Edit) != 0)
    				control.Mode = DataBoundControlMode.Edit;
    
    			if ((rowState & DataControlRowState.Insert) != 0)
    				control.Mode = DataBoundControlMode.Insert;
    
    			cell.Controls.Add(control);
    		}
    		else
    		{
    			base.InitializeCell(cell, cellType, rowState, rowIndex);
    		}
    	}
    }</STRIKE>
    

     

    I'm Dumnb! [:$]

    Wednesday, July 16, 2008 5:25 PM
  • User-330204900 posted

    <STRIKE>Relating to my previous post when using the ImprovedDynamicValidator I've noticed the following during debug:</STRIKE>

    <STRIKE>When I set the ValidationGroup at runtime (see previous post for ValidationGroupFieldsManager and ValidationGroupDynamicField which are used to set ValidationGroup at runtime).</STRIKE>

    <STRIKE><asp:DynamicField DataField="OrderID" />
    <asp:DynamicField DataField="OrderDate" />
    <asp:DynamicField DataField="Freight" />
    </STRIKE>

    <STRIKE>I have notice that the ValidationGroup of the ImprovedDynamicValidator is an empty string. </STRIKE>

    <STRIKE>And when I declariativly set the ValidationGroup as in below </STRIKE>

    <STRIKE><asp:TemplateField>
    	<EditItemTemplate>
    		<asp:DynamicControl ID="DynamicControl1" runat="Server" DataField="OrderID" Mode="Edit" ValidationGroup="Test1"/>
    	</EditItemTemplate>
    </asp:TemplateField>
    <asp:TemplateField>
    	<EditItemTemplate>
    		<asp:DynamicControl ID="DynamicControl2" runat="Server" DataField="OrderDate" Mode="Edit" ValidationGroup="Test1"/>
    	</EditItemTemplate>
    </asp:TemplateField>
    <asp:TemplateField>
    	<EditItemTemplate>
    		<asp:DynamicControl ID="DynamicControl3" runat="Server" DataField="Freight" Mode="Edit" ValidationGroup="Test1"/>
    	</EditItemTemplate>
    </asp:TemplateField>
    </STRIKE>

    <STRIKE>The ValidationGroup has a value i.e. "Test1".</STRIKE>

    Scratch that lot I've been going around in circles and made one BIG dumb mistake it all works fine [:$]

    Thursday, July 17, 2008 6:28 AM
  • User-330204900 posted

    This is the ValidationGroup issue I've been chasing around and now have nailed it down:

    The issue I’m trying to fix is where you have customised the page’s columns using DynamicField which you cannot set the ValidationGroup declaratively, I’m trying to do this at runtime on the OnDataBound event. I’ll post an update when I’ve figured it out.  

    I get the "Failed to set one or more properties on type Order.  Cannot convert value of parameter 'OrderDate' from 'System.String' to 'System.DateTime'." exception thown on the page instead of the nice error.

    The error does not occur if I use DynamicControl and declaratively set the ValidationGroup [8-)]

    So what I did was employ Marcin's ImprovedDynamicValidator setpped through it and what I noticed was that the ValidationGroup of the DynamicField's main control (usually TextBox1) was set when:

    1. I had declaratively set the ValidationGroup using DynamicControl
    2. Set the ValidationGroup at runtime via an IAutoFieldGenrator class shown below.

    and was not set when I set the ValidationGroup at runtime via the OnDataBound event of the DetailsView

    IAutoFieldGenrator class:

    using System;
    using System.Collections;
    using System.Collections.Generic;
    using System.Web.DynamicData;
    using System.Web.UI;
    using System.Web.UI.WebControls;
    
    public class ValidationGroupFieldsManager : IAutoFieldGenerator
    {
    	protected MetaTable _table;
    	protected String _validationGroup;
    
    	public ValidationGroupFieldsManager(MetaTable table, String validationGroup)
    	{
    		_table = table;
    		_validationGroup = validationGroup;
    	}
    
    	public ICollection GenerateFields(Control control)
    	{
    		List<DYNAMICFIELD> oFields = new List<DYNAMICFIELD>();
    
    		foreach (MetaColumn column in _table.Columns)
    		{
    
    			// carry on the loop at the next column  
    			// if scaffold table is set to false or DenyRead
    			if (!column.Scaffold)
    				continue;
    
    			// create a new field with its validation group set
    			DynamicField f = new ValidationGroupDynamicField(_validationGroup);
    
    			f.DataField = column.Name;
    			oFields.Add(f);
    		}
    		return oFields;
    	}
    }
    
    // special thanks to David Ebbo for this
    public class ValidationGroupDynamicField : DynamicField
    {
    	protected String _validationGroup;
    
    	public ValidationGroupDynamicField(String validationGroup)
    	{
    		_validationGroup = validationGroup;
    	}
    
    	public override void InitializeCell(
    		DataControlFieldCell cell,
    		DataControlCellType cellType,
    		DataControlRowState rowState,
    		int rowIndex)
    	{
    		if (cellType == DataControlCellType.DataCell)
    		{
    			var control = new DynamicControl();
    
    			// Copy various properties into the control
    			control.DataField = DataField;
    			control.UIHint = UIHint;
    			control.HtmlEncode = HtmlEncode;
    			control.NullDisplayText = NullDisplayText;
    
    			// set ValidationGroup
    			control.ValidationGroup = _validationGroup;
    
    			if ((rowState & DataControlRowState.Edit) != 0)
    				control.Mode = DataBoundControlMode.Edit;
    
    			if ((rowState & DataControlRowState.Insert) != 0)
    				control.Mode = DataBoundControlMode.Insert;
    
    			cell.Controls.Add(control);
    		}
    		else
    		{
    			base.InitializeCell(cell, cellType, rowState, rowIndex);
    		}
    	}
    }

    OnDataBound event handler: 

    protected void DetailsView1_DataBound(object sender, EventArgs e)
    {
    	foreach (DetailsViewRow row in DetailsView1.Rows)
    	{
    		if (row.RowType == DataControlRowType.DataRow && row.Cells.Count > 1)
    		{
    			var cell = row.Cells[1];
    			var df = cell.Controls.OfType<DYNAMICCONTROL>().SingleOrDefault();
    
    			if (df != null && !df.Column.IsReadOnly)
    			{
    				//set the appropriate ValidationGroup
    				df.ValidationGroup = "Test1";
    			}
    		}
    	}
    }

    It appears to me that the ValidationGroup is not set properly when done at the OnDataBound event stage [:S]

    Hope I've started to make sense again (as if I ever did [:D])

    Thursday, July 17, 2008 1:19 PM
  • User-330204900 posted

    This is the ValidationGroup issue I've been chasing around and now have nailed it down:

    The issue I’m trying to fix is where you have customised the page’s columns using DynamicField which you cannot set the ValidationGroup declaratively, I’m trying to do this at runtime on the OnDataBound event. I’ll post an update when I’ve figured it out.  

    I get the "Failed to set one or more properties on type Order.  Cannot convert value of parameter 'OrderDate' from 'System.String' to 'System.DateTime'." exception thown on the page instead of the nice error.

    After After running around in the OnDataBound event I have come to the conslusion that it is too late to change the ValidationGroup here because its based on a FieldTemplate user control.

    So there are two solutions:

    1. use DynmaicControl with the more complicated markup and set the ValidationGroup declaratively.
    2. Use ScaffoldColumnAttribute to hide columns you dont want and then you can use the IAutoFieldGenrator class and set the ValidationGroup at runtime.

    [:S]

    Hope this helps [:D]

    Friday, July 18, 2008 3:02 AM
  • User819964165 posted

    Thankfully there is a better way, with a lot less code (it's so simple I don't understand why Microsoft didn't include it in the first place)   

    namespace JJ.Controls
    {
       public class ValidationGroupDynamicField: DynamicField
        {

            private string _validationGroup;
            public string ValidationGroup
            {
                get
                {
                    return _validationGroup;
                }
                set
                {
                    _validationGroup = value;
                }
            }

            public override void InitializeCell(System.Web.UI.WebControls.DataControlFieldCell cell, System.Web.UI.WebControls.DataControlCellType cellType, System.Web.UI.WebControls.DataControlRowState rowState, int rowIndex)
            {
                base.InitializeCell(cell, cellType, rowState, rowIndex);

                if (cellType == DataControlCellType.DataCell)
                {
                    if (ValidationGroup != null)
                        ((DynamicControl)cell.Controls[0]).ValidationGroup = ValidationGroup;
                }
            }
        }
    }

     

     Now, all you have to do, after registering the control in your page:
    <%@ Register Assembly="CustomControls" Namespace="JJ.Controls" TagPrefix="jj" %>

    is to then include the filed in the fields template with the validationGroup parameter:

    <Fields>
       
    <jj:ValidationGroupDynamicField DataField="Url" ValidationGroup="myGroup" />
    </Fields>

    Wednesday, January 14, 2009 1:23 PM
  • User660823006 posted

    We are adding ValidationGroup to the DynamicField in the next version of Dynamic Data based on your guys feedback.

    • Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
    Monday, January 19, 2009 12:54 PM
  • User-330204900 posted

    Thanks Scott [:D]

    Monday, January 19, 2009 3:03 PM
  • User896152122 posted

    Just to throw another spanner in the ValidationGroup works.....

    I'm trying to setup some nice AJAX editing / inserting for lookup values within a master record - click "Add New" to create a new master record....Choose a lookup item from a dropdown, but the item you want isn't there.  Rather than click cancel, go to the lookup table, click add, enter the item, click save, then go back to your master record and click "Add New" again............I wanted the ability to simply add a new lookup item from within the add-new page of the master record.

    I'm doing this using the AJAX Web Toolkit modal popup.  I've got a panel which contains a detailsview, autogenerated validationgroupdynamicfields and another datasource.  The "add" works fine, except I can't get the validation working properly

    I've followed this thread and setup a ValidationGroupDynamicField, modified my AutoFieldGenerator to use it and that all looks good.  However, for some reason the validators in my modal-popup panels are being written to the page with enabled=0, so they are ignored when the "Save" button is clicked.....The server-side validation still fires, so invalid records aren't saved, but I don't get any errors - it just exits the panel.

    I've tried the ListDetails page using the modal popup from the Futures project and I that works fine with validation.....

    What am I missing?

    Friday, March 13, 2009 5:29 AM
  • User896152122 posted

     Ugh.  I seem to always post these things just before I discover the answer......

    Two issues in play here.....

    1. I didn't have a "Required" attribute on my lookup field's description column.  I only had a StringLength attribute with min and max lengths

    2. In my server Save_Click event, I was validating the page, but only hiding the modal popup if everything was valid - I needed to SHOW it again if it wasn't valid!

    So, The reason the validator had enabled=0 was because I didn't have a RequiredAttribute. 

    And the reason I wasn't getting any error message was because when it was failing the string-length validation (Which is on the server, not the client) I wasn't showing the modal panel again......

    Everything is now hunky dory! Thanks a lot for this thread.

    Friday, March 13, 2009 6:23 AM
  • User554640251 posted

    We are adding ValidationGroup to the DynamicField in the next version of Dynamic Data based on your guys feedback.

    Scott,

    Has this feature been added yet?  Thanks!   

    Monday, October 26, 2009 12:36 PM
  • User-520443374 posted

    I'm looking for the reply aswell, and found that it is a new property on DynamicField in the 4.0 version

    http://msdn.microsoft.com/en-us/library/system.web.dynamicdata.dynamicfield_properties(VS.100).aspx 

    Monday, November 9, 2009 10:01 AM