ISupportInitialize for ASP.NET?

B

breeve

From my testing ISupportInitialize is not honored in ASP.NET We have a
control like the following...

<ni:Meter ID="Meter1" runat="server" Range="67, 73" Value="70" >
</ni:Meter>

The Value property checks the range and throws an exception if the range is
outside its value. The default for the Range is 0-10. The trouble is when a
user saves the above mark up and closes the designer and reopens it, the
ASP.NET designer first tries to set the value to 70 before the range has been
set. The exception is thrown because the range is still its default value of
0-10. Interestingly, at run time the Range is set first so there is no issue.
It seems the evaluation of properties is inconsistant:

RunTime -> left to right
DesignTime -> right to left.

Is there anyway I can influence the ordering of properties or set them
together somehow?
 
S

Steven Cheng[MSFT]

Hello Breeve,

As for the custom webserver control, the design-time property setting and
persisting does differ from runtime property setting. At runtime, the
control will initializing the properties according to their sequence in the
inline aspx template.

For your scenario, I suggest you separate the validation code (for
design-time and runtime) into two places:

1. For runtime validation, you can still put them in the property's setter
method, but you need to check whether the code is running in ASP.NET
runtime(or in design-time surface). e.g:

=================
if (this.DesignMode)
{
...
}
==================

2. For design-time valiation, I suggest you consider put the validatino
code in a custom control designer, since there're some methods in the
ControlDesigner class in which we can validate the properties:

#ControlDesigner Class
http://msdn2.microsoft.com/en-us/library/system.web.ui.design.controldesigne
r.aspx

For example, you can override the designer's "GetDesignTimeHtml" method and
do the valiadtion against the two properties there since this method is
called then the deigner will refresh the control's html in deigner surface.

Hope this helps.


Sincerely,

Steven Cheng

Microsoft MSDN Online Support Lead



This posting is provided "AS IS" with no warranties, and confers no rights.
 
B

breeve

If I throw an exception inside of ControlDesigner.GetDesignTimeHtml it
doesn't get propagated to the user. It is swallowed somewhere up the call
stack. This is a problem with the approach you suggested above. A user can
edit the mark up themselves. When I set the Range and Value (int that order)
in GetDesignTimeHtml I need to let the user know if the value is outside the
range.

A better approach, and something I have looked at before, is to use a custom
ControlBuilder. What I would like to do is to call
ISupportInitialize.BeginInit before the control is initialized and
ISupportInitialize.EndInit after. We already have logic in place for this to
work on the control. Looking at the ControlBuilder API, there is a
BuildObject method that is virtual. I would like to override this and get the
instance of the created control and call BeginInit on it. The problem is the
API does not let me do this. If I call the base version it creates the
control and there is no way for me to access the control before it starts to
set properties. For example,

public override object BuildObject()
{
//I would like to Create the instance and pass it to BuildObject so I can call
//BeginInit on it. If I call the base, the base doesn't let me hook in
anywhere.
object buildObject = base.BuildObject();
//This is too late to call BeginInit. The properties have already been set.
}

I guess the issue is how can I get a reference in ControlBuilder of the
build object without doing everything myself (building the entire object
myself)?
 
S

Steven Cheng[MSFT]

Thanks for your reply Breeve,

Yes, throw an exception in GetDesignTimeHtml method won't behave quite same
as in runtime code. However, since the GetDesignTimeHtml method just return
the html code which will be displayed on design surface, you can return the
error info as return value.

BTW, as for the exception handling, the design-time service does capture
the exception internally, however, you can override the
ControlDesigner.GetErrorDesignTimeHtml method. And when we throw exception
in GetDesignTimeHtml method, this will trigger the "GetErrorDesignTimeHtml"
method and we can return our own error message. e.g.

==================
protected override string GetErrorDesignTimeHtml(Exception e)
{
return e.ToString();
}
===================

Sincerely,

Steven Cheng

Microsoft MSDN Online Support Lead


This posting is provided "AS IS" with no warranties, and confers no rights.
 
B

breeve

For the interested, I was able to get this to work throught
ControlBuilder.Init function. It took awhile to figure out because there is
no documentation:


private class NumericPointerBuilder : ControlBuilder
{
public override void Init(TemplateParser parser, ControlBuilder
parentBuilder, Type type, string tagName, string id, IDictionary attribs)
{
IDictionary order = new Order(attribs);
base.Init(parser, parentBuilder, type, tagName, id, order);
}

private class Order : Hashtable
{
public Order(IDictionary items)
: base(items)
{
}

public override IDictionaryEnumerator GetEnumerator()
{
return new Enumerator(this);
}

private class Enumerator : IDictionaryEnumerator
{
private const string ValueProperty = "Value";
private const string RangeProperty = "Range";

private List<DictionaryEntry> _list;
private int _currentIndex;

public Enumerator(Hashtable hashTable)
{
_currentIndex = -1;
_list = new List<DictionaryEntry>();

// getting the IEnumerable interface to call the
explicit implementation
// to aviod a recrusive stack overflow here.
IEnumerable enumerable = hashTable;
int valueKeyIndex = -1;

foreach (DictionaryEntry entry in enumerable)
{
if (entry.Key is string && ((string)entry.Key)
== ValueProperty)
{
valueKeyIndex = _list.Count;
}
if (entry.Key is string && ((string)entry.Key)
== RangeProperty)
{
//Value property has been added
if (valueKeyIndex != -1)
{
//Insert range property before Value
property.
_list.Insert(valueKeyIndex, entry);
continue;
}
}

_list.Add(entry);
}
}

public void Reset()
{
_currentIndex = -1;
}

public object Current
{
get
{
return Entry;
}
}

public bool MoveNext()
{
_currentIndex++;
if (_currentIndex >= _list.Count)
{
_currentIndex = _list.Count;
return false;
}

return true;
}


public DictionaryEntry Entry
{
get
{
if (_currentIndex < _list.Count && _currentIndex
return _list[_currentIndex];
else
throw ExceptionBuilder.InvalidOperation();
}
}

public object Key
{
get
{
return Entry.Key;
}
}

public object Value
{
get
{
return Entry.Value;
}
}
}
}
}
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,767
Messages
2,569,572
Members
45,046
Latest member
Gavizuho

Latest Threads

Top