Hi there,
I had a look at the System.Web.UI.W ebControls code, and it seems there’s a
tiny *bug* - ConvertEmptyStr ingToNull is not used in
ControlParamete r.Evaluate() method. Let me explain the problem in details.
Every Parameter in ObjectDataSourc e.SelectParamet ers collection inherits from
System.Web.UI.W ebControls.Para meter class, which defines virtual method
protected virtual object Evaluate(HttpCo ntext context, Control control)
{
Return null;
}
As you can see default implementation returns null reference, but every
derived parameter class overrides this method with its own implementation
(this mechanism is called polymorphism). For instance, ControlParamete r class
provides its own, following implementation:
protected override object Evaluate(HttpCo ntext context, Control control)
{
if (control == null)
{
return null;
}
string text1 = this.ControlID;
string text2 = this.PropertyNa me;
if (text1.Length == 0)
{
throw new
ArgumentExcepti on(SR.GetString ("ControlParame ter_ControlIDNo tSpecified", new
object[] { base.Name }));
}
Control control1 = DataBoundContro lHelper.FindCon trol(control, text1);
if (control1 == null)
{
throw new
InvalidOperatio nException(SR.G etString("Contr olParameter_Cou ldNotFindContro l", new object[] { text1, base.Name }));
}
ControlValuePro pertyAttribute attribute1 =
(ControlValuePr opertyAttribute )
TypeDescriptor. GetAttributes(c ontrol1)[typeof(ControlV aluePropertyAtt ribute)];
if (text2.Length == 0)
{
if ((attribute1 == null) || string.IsNullOr Empty(attribute 1.Name))
{
throw new
InvalidOperatio nException(SR.G etString("Contr olParameter_Pro pertyNameNotSpe cified", new object[] { text1, base.Name }));
}
text2 = attribute1.Name ;
}
object obj1 = DataBinder.Eval (control1, text2);
if (((attribute1 != null) && string.Equals(a ttribute1.Name, text2,
StringCompariso n.OrdinalIgnore Case)) && ((attribute1.De faultValue != null) &&
attribute1.Defa ultValue.Equals (obj1)))
{
return null;
}
return obj1;
}
A lot of code but nothing really interesting – the only thing missing is use
of ConvertEmptyStr ingToNull. However, the problem shows up somwehere else -
in ParameterCollec tion class. As you may know every BaseDataBoundCo ntrol
(including FormView) populates the data on prerender event. Before doing so,
control performs a simple check to see if the data needs to be (re)populated
(actually this task is delegated to SelectParameter s member which is an
instance of ParameterCollec tion class, control is notified by handling
ParametersChang ed event which occurrence indicates data should be retrieved
again):
public void ParameterCollec tion.UpdateValu es(HttpContext context, Control
control)
{
foreach (Parameter parameter1 in base)
{
parameter1.Upda teValue(context , control);
}
}
And here comes the problem:
internal void Parameter.Updat eValue(HttpCont ext context, Control control)
{
object originalValue = this.ViewState["ParameterValue "];
object evaluatedValue = this.Evaluate(c ontext, control);
this.ViewState["ParameterValue "] = obj2;
if (((evaluatedVal ue == null) && (originalValue! = null)) ||
((evaluatedValu e!= null) && ! evaluatedValue. Equals(original Value)))
{
this.OnParamete rChanged();
}
}
In your case, originalValue is null, evaluatedValue is String.Empty
therefore parameter is considered as changed (TextBox.Text never returns null
reference but String.Empty, unfortunately, as I mentioned,
ControlPatamete r.Eval() method does not replace empty string with null value
even if ConvertEmptyStr ingToNull == true. It doesn’t happen for Parameter
class because Parameter.Eval( ) always returns null, so the condition
if (((evaluatedVal ue == null) && (originalValue! = null)) ||
((evaluatedValu e!= null) && ! evaluatedValue. Equals(original Value)))
{
this.OnParamete rChanged();
}
is never met.
There are two easy ways to solve the problem.
1. Do not use Page_Load event to popuate the dropdownlist, use pre_render:
protected void Page_PreRender( object sender, EventArgs e)
{
if (!IsPostBack)
PopulateDDL();
}
2. Create your own parameter class derived from ControlParamete r
public class MyControlParame ter : ControlParamete r
{
protected override void LoadViewState(o bject savedState)
{
base.LoadViewSt ate(savedState) ;
}
protected override object Evaluate(HttpCo ntext context, Control control)
{
object value = base.Evaluate(c ontext, control);
if (value is String)
{
if (ConvertEmptySt ringToNull && ((string)value) == String.Empty)
return null;
else
return value;
}
else
return value;
}
}
<asp:FormView ID="ItemFormVie w" DataSourceID="m yODS" runat="server"
DefaultMode="In sert">
<InsertItemTemp late>
<asp:DropDownLi st ID="myDDL" runat="server"/>
</InsertItemTempl ate>
</asp:FormView>
<asp:ObjectData Source ID="myODS" runat="server">
<SelectParamete rs>
<cc1:MyControlP arameter ControlID="faa" PropertyName="T ext"/>
</SelectParameter s>
</asp:ObjectDataS ource>
<asp:TextBox ID="faa" runat="server" visible="true"/>
--
Milosz
"np****@gmail.c om" wrote:
I have a simple Formview like this:
<%@ Page Language="C#" EnableViewState ="true" AutoEventWireup ="true"
CodeFile="Hello World.aspx.cs" Inherits="_Hell oWorld"%>
<html>
<body>
<form runat="server">
<asp:FormView DataSourceID="m yODS"
ID="ItemFormVie w"
runat="server">
<InsertItemTemp late>
<asp:DropDownLi st ID="myDDL" runat="server"> </
asp:DropDownLis t>
</InsertItemTempl ate>
</asp:FormView>
<asp:ObjectData Source ID="myODS" runat="server" >
<SelectParamete rs>
<asp:ControlPar ameter ControlID="faa" />
</SelectParameter s>
</asp:ObjectDataS ource>
<asp:TextBox ID="faa" runat="server" visible="false" ></
asp:TextBox>
</form>
</body>
</html>
and a codebehind file
using System;
using System.Data;
using System.Configur ation;
using System.Web;
using System.Web.Secu rity;
using System.Web.UI;
using System.Web.UI.W ebControls;
using System.Web.UI.W ebControls.WebP arts;
using System.Web.UI.H tmlControls;
public partial class _HelloWorld : System.Web.UI.P age
{
protected void Page_Load(objec t sender, EventArgs e)
{
ItemFormView.Ch angeMode(FormVi ewMode.Insert);
if (!IsPostBack)
PopulateDDL();
}
private void PopulateDDL()
{
DropDownList ddl =
(DropDownList)I temFormView.Fin dControl("myDDL ");
ddl.Items.Add(" aaa");
ddl.Items.Add(" bbb");
ddl.Items.Add(" ccc");
}
}
When I run this page, the dropdown list is expected to be populated,
but it's not. However, if I remove the line
<asp:ControlPar ameter ControlID="faa" />
, it then works. It also works perfectly if using other type of
parameter, like
<asp:Paramete r Name="woo"/>
So, I don't understand what happen behind the scene. Any idea???
Thanks in advance!
Nate