|
|||||||||||||||||||||||
|
|||||||||||||||||||||||
|
Announcements
Chapters
Services
Feature Zones
|
Updates - see at the article's endIntroductionIf you already have created a custom server control, you would have probably noticed that the intelisense in the HTML view is absent. This article will show you how to get it back. Softomatix published an article about how to create server control: ASP.NET Server Control - Updown Control 1. That's the basics. I'll go on to other topics. My code example is ClickOnce a control that becomes disabled, until postback returns. IteliSense supportAdd your code Identity to the control TagPrefix. [assembly: System.Web.UI.TagPrefix("Gootvilig.Controls","Gootvilig")]
Now when you drop your control, we will have a friendly name in the TagPrefix attribute and not something like <%@ Register TagPrefix="gootvilig" Namespace="Gootvilig.Controls"
Assembly="Gootvilig.Controls" %>
The Intelisense for web controls is in a file named "asp.xsd", that can be found in the path "Program Files\Microsoft Visual Studio .NET 2003\Common7\Packages\schemas\xml". This is the schema for any controls prefixed with "asp:", and their attributes. Furthermore, the ability to display data in the Properties Window is also dependent on this schema.
So how can do we add our schema?
<body MS_POSITIONING="GridLayout" xmlns:Gootvilig=
"urn:http://www.Gootvilig.com/schemas">
Now we will get intlisense support (And also Properties Window support).
The next code snippet is the base of the schema for my control. <?xml version="1.0" encoding="utf-8" ?>
<xsd:schema targetNamespace="urn:http://www.Gootvilig.com/schemas"
elementFormDefault="qualified"
xmlns="urn:http://www.Gootvilig.com/schemas"
xmlns:xsd="http://www.w3.org/2001/XMLSchema" target=_blank>http://www.w3.org/2001/XMLSchema"
xmlns:vs="http://schemas.microsoft.com/Visual-Studio-Intellisense" target=_blank>http://schemas.microsoft.com/Visual-Studio-Intellisense"
vs:friendlyname="Gootvilig Control Schema"
vs:ishtmlschema="false"
vs:iscasesensitive="false"
vs:requireattributequotes="true">
<xsd:annotation>
<xsd:documentation>Gootvilig Control schema.</xsd:documentation>
</xsd:annotation>
<xsd:element name="ClickOnce" type="ClickOnceDef"></xsd:element>
<xsd:complexType name="ClickOnceDef" vs:noambientcontentmodel="true">
<xsd:attributeGroup ref="
Now we have a problem. The reference to " Now there is complete intelisense for the control.
Support for the ToolboxAdding your component to the toolbar is simple. Just right click on the desired toolbox tab, choose "Add/Remove Items…", and browse to your component's assembly DLL. The component name will appear there with the following default icon: To add your Icon to the toolbox, add this attribute to your class: ToolboxBitmap(typeof(ClickOnce),"Gootvilig.Controls.ClickOnce.bmp")
// or
ToolboxBitmap(typeof(Bottun))
As you can see, there are two choices. The first choice uses an embedded BMP file and associates it to the class. The file must be 16 X 16 pixels. " The second choice associates your class with a built in class icon.
Now when you drag and drop ClickOnce to our page, lines will be added to our page: (First we have to add a reference to the assembly) <%@ Register TagPrefix="gootvilig" Namespace="Gootvilig.Controls"
Assembly="Gootvilig.Controls" %>
<Gootvilig:ClickOnce id="ClickOnce1" runat="server"
Text="Button"></Gootvilig:ClickOnce>
The ClickOnce controlThe control is designed to support long term round trip actions. In that case we want to avoid any possibility of re-clicking on a button. To achieve this action we need to add some JavaScript code, for the client to execute it before the long time server callback code will take place. Be sure not to replace the " Here is the code for implementing this: protected override void OnPreRender(EventArgs e)
{
base.OnPreRender(e);
string currentOnClick = Attributes["onclick"];
// Add javascript onclick handler
Attributes["onclick"]
+= string.Format("document.getElementById(
'{0}').disabled = true;",ClientID);
}
Now we have an additional problem: Because the control was set to " So I added a call to JavaScript method that is generally added to most ASP.NET pages -
Attributes["onclick"]
+= string.Format("document.getElementById('{0}').disabled
= true;__doPostBack('{0}','');",ClientID);
Here is the code that the <input type="hidden" name="__EVENTTARGET" value="" />
<input type="hidden" name="__EVENTARGUMENT" value="" /> <script language="javascript" type="text/javascript">
<!--
function __doPostBack(eventTarget, eventArgument) {
var theform;
if (window.navigator.appName.toLowerCase().indexOf("microsoft") > -1) {
theform = document.Form1; }
else {
theform = document.forms["Form1"]; }
theform.__EVENTTARGET.value = eventTarget.split("$").join(":");
theform.__EVENTARGUMENT.value = eventArgument;
theform.submit(); }// -->
</script>
But the page doesn't always add these snippet code. Only if one of the following controls is embedded in the page, it will call the page internal Here is the code of internal void RegisterPostBackScript()
{
if (this._fPostBackScriptRendered);
{
return;
}
if (!this._fRequirePostBackScript)
{
this.RegisterHiddenField("__EVENTTARGET", "");
this.RegisterHiddenField("__EVENTARGUMENT", "");
}
this._fRequirePostBackScript = true;
}
Here is the code to enforce the page to call //Call the internal method Page.RegisterPostBackScript()
MethodInfo methodInfo =
typeof(Page).GetMethod("RegisterPostBackScript",
BindingFlags.Instance|BindingFlags.NonPublic);
if(methodInfo != null)
{
methodInfo.Invoke(Page,new object[]{});
}
The //Code from Control
internal string UniqueIDWithDollars{
get
{
string text1 = this.UniqueID;
if (text1 == null)
{
return null;
}
if (text1.IndexOf(':') >= 0)
{
return text1.Replace(':', '$');
}
return text1;
}
}
Here is the code to call //Get the Control UniqueIDWithDollars for the call to __doPostBack()
PropertyInfo propertyInfo = typeof(Control).GetProperty(
"UniqueIDWithDollars",BindingFlags.Instance|BindingFlags.NonPublic);
string uniqueIDWithDollars = ClientID;
if(propertyInfo != null)
{
uniqueIDWithDollars = (string)propertyInfo.GetValue(this,new object[]{});
}
Wait! How will the ClickOnce control behave now? It should be enabled after the long server run: So we set protected override void OnInit(EventArgs e)
{
base.OnInit(e);
//Enable upon PostBack
Enabled = true;
}
After See also Eric Plowe's ClickOnce Button Server Control. ConclusionsWhat did we have here :
Updates
InteliSence in User ControlWe saw that, we need to copy the XSD that support our control schema to the "Asp.xsd" folder, then add our namespace to the page But what if we are working with a User Control, where we have no We can do that by enclosing all the HTML code in a tag and add the namespace to that tag.For example: <DIV xmlns:Gootvilig="urn:http://www.Gootvilig.com/schemas">
<!-- Here is all the User Control code -->
</DIV>
Or better in a way that will not rendered to the actual HTML of the client side: <% if(false) { %>
<DIV xmlns:Gootvilig="urn:http://www.Gootvilig.com/schemas">
<%}%>
<!-- Here is all the User Control code -->
<% if(false) { %>
</DIV>
<%}%>
No need to copy the XSD fileIf we have the XSD in the solution which we are working on, we don't have to copy that file to the "Asp.xsd" folder!
|
||||||||||||||||||||||