Convert User Controls to Server Controls - c#

I'm wondering if anyone has any experience converting User controls to Web controls?
Ideally, I'd like to offload some of the design work to others, who would give me nicely laid out User Controls. Then, I could go through the process of converting, compiling, testing and deploying.
Until MS comes up with the magic "Convert to Server Control" option, it looks like I'm pretty well stuck with re-writing from scratch. Any ideas?

Is there a reason you must convert these user controls to server controls? Remember that it is possible to compile a user control into an assembly.

You are right there is no magic bullet here but since you already have a User Control its not that difficult.
Make sure all properties, events, etc. are set in the code behind since you won't have any mark up when you're done
Create a new Server Control
Paste all of the event handling and property setting code into the new control
override the Render method for each child control call the RenderControl Method passing in the supplied HtmlTextWriter
protected override void Render(HtmlTextWriter writer)
{
TextBox box = new TextBox();
//Set all the properties here
box.RenderControl(writer);
base.Render(writer);
}

I searched for hours and found many blogs about it.
The only thing worked for me was this article https://blogs.msdn.microsoft.com/davidebb/2005/10/31/turning-an-ascx-user-control-into-a-redistributable-custom-control/.
It says self-contained with given restrictions, but it does not mentions that the codebehind must be included in ascx file.
I used a Web Site project (not Web application!) and had to inline the code behind into the ascx file and only use control directive like:
<%# Control Language="C#" ClassName="MyPackage.MyControl"%>
So basically i just have a single file left for the user control. When codebehind was a separate file all control's where null when i referenced the final dll.
I also tried http://blog.janjonas.net/2012-04-06/asp_net-howto-user-control-library-compile-dll-file but with reflection the ascx file could not be found.

Related

Adding ASP.NET User Controls at runtime via <script runat="server">

I am having trouble executing a control inside the <script runat="server"> tags in an *.aspx page.
The control works when it is defined declaratively in the HTML section of the page, but I am unable to make it work when placed within the script tag itself.
At the beginning of the page I register my control with:
<%# Register assembly="App_Web_exemple.ascx.cc671b29" namespace="Moncontrol" tagprefix="moncontrol" %>
Then, in the HTML, I call it (successfully) with the following declaration:
<moncontrol:exemple ISBN="9782894646151" runat="server" />
When I try to add it programmatically within the <script runat="server">, however, I am unable to execute it. I tried with the tags <asp:Text /> and <asp:Literal />, as follows, but that also doesn't doesn’t work.
In the HTML part:
<asp:Text id="TestControl" runat="server" />
In the script part
TestControl.Text = "<moncontrol:exemple ISBN=\"9782894646151\" runat=\"server\" />";
To clarify, what you're looking to do is programmatically add a User Control to your Web Forms page at runtime. There are a few ways of accomplishing this.
Before we begin, it's worth noting that the code you wrote likely "works" insomuch that it compiles and doesn't throw a runtime error. But it's also not executing the control. I suspect if you look at your HTML, you'll find the control declaration being output as a string literal (i.e., unprocessed by the server). It is then disregarded by the browser since it doesn't know what the <moncontrol:exemple /> tag represents. That's obviously not what you want.
Establishing a Control Container
Regardless of which approach you take, you'll want to start with some type of container on your page that you can add the control to, such as a Panel. If you don't want the container to output any wrapper markup, you can use a Placeholder:
<asp:Placeholder id="ControlContainer" runat="server" />
This serves a similar purpose as your current Text control, except its only purpose is to provide a container that you will add your user control to. From ASP.NET's perspective, however, this can be any type of server control, including a <script runat="server">, as per your request. More on that later.
Programmatically Creating the Control
Next, you're going to create the control programmatically. This is where we run into various options. The most universal approach is to use ParseControl() method (reference). This looks something like this:
Control control = Page.ParseControl("<%# Register assembly=\"App_Web_exemple.ascx.cc671b29\" namespace=\"Moncontrol\" tagprefix=\"moncontrol\" %><moncontrol:exemple ISBN=\"9782894646151\" runat=\"server\" />");
That will parse the control using the same method that processes the declarative syntax on the page, and return a Control object with your Exemple control as the first control in its Controls collection.
I find that syntax a bit sloppy, however, since it's representing a .NET object and its properties as a string literal. Given that, there are some cleaner approaches. In this case, it appears that your control is being compiled into an assembly and, therefore, likely has a Code Behind defined which inherits from UserControl. If so, you should be able to simply do something like:
Exemple control = new Exemple();
And then set the properties on it programmatically, the way you would in any other C# object. Much cleaner!
If your control was instead being compiled dynamically by the server, then you'd instead use the Reference directive with the LoadControl() method, as described in the MSDN article How to: Create Instances of ASP.NET User Controls Programmatically. I don't believe that method will work for you, however.
Adding the Control Instance to the Page
Regardless of which approach you take, the next step is the same: you then add the control you've programmatically added to your page by adding it to the Controls collection of the target container. E.g.,:
ControlContainer.Controls.Add(control);
Note: You can technically just add this to the Page class's Control collection, too, but that doesn't give you any control over where on the page it is placed; having a PlaceHolder control (or equivalent) lets you specify exactly where you want the control to appear.
I hope this helps. There are a couple of caveats depending on how you wrote and compiled your control, but this should give you the basic structure needed to address your problem.

ASP.NET user control designer support

I have a user control which when added to the markup via the Toolbox or manually typing
<myNameSpc:myCtrl ... I would like to spit out:
<myNameSpc:myCtrl>
<template></template>
</myNameSpc:myCtrl>
I remember doing this for windows workflows and it involved implementing something like a TypeConverter and WorkflowXmlSerializer so it maybe possible for user controls as well I'd guess ? the only thing is that I don't have time to research this matter now, so I was wondering if anyone would be kind enough to point me in the right direction so that I don't have to dig deep into the designer serialization of VS (which I remember was a big pain).
For your custom control, you can specify a ToolboxDataAttribute which defines the default html that will be generated when you drag a control onto the design service. E.g.:
[ToolboxData("<{0}:myCtrl runat="server"><template></template></{0}:myCtrl>")]
public class myCtrl : System.Web.UI.Control
{
}
For the manual generation you can create a Code Snippet. The best way to do that is find existing ASPX snippet and modify it to gen your control. I'm assuming you are using VS 2010.

asp.Net <control> does not exist in current context

I am facing a problem: I have taken a dropdownList control and ID is
drpDownCountries in an ASP.NET project. The dropdownlist control is placed on page, in the code behind file of C#, while typing the control name drpDownCountries, this control ID is listed in object member list.
The code-behind code looks like this:
drpDownCountries.Attributes.Add("onBlur", "ErrorHighlight('" + drpDownCountries.ClientID + "','" + lblCountry.ClientID + "');");
But when I compile the project I am getting the following error:
Error: The name 'drpDownCountries' does not exist in the current context
I have checked this thing on different machines too, and the same error is occurring. I do not understand what the reason is or how to fix it.
Right-click on the ASPX (or ascx) file, and select Convert to web application (or something like that). That will force a refresh on the designer file.
I had this same problem and what worked for me was to make a change to the .ascx file in Design view and then save it. This finally forced Visual Studio to regenerate the designer.cs file and include my new control.
I have seen this error occur when there is a copy of the .aspx page in the project folder.
Example:
Error occurs in Test.aspx.
There is a Test-copy.aspx file in the project folder.
Delete, rename with a different extension, or move Test-copy.aspx to a different folder.
Error is resolved.
It's possible there is an error in your aspx/aspx file that is causing the designer file not to be updated correctly. You could confirm this by adding something new (eg. "") and see if you can access that. If not, something is probably broken in the markup that you'll need to fix.
So first check that your ascx document is defined like so
ExampleClass.ascx
<%# Control Language="C#" AutoEventWireup="true" CodeFile="ExampleClass.ascx.cs" Inherits="ExampleClass" %>
ExampleClass.ascx.cs
public partial class ExampleClass : System.Web.UI.UserControl
{
protected void Page_Load(object sender, System.EventArgs e)
{
}
}
In aspx this type of error often occurs when you miss runat="server"
Do not let Intellisense fool you. Sometimes (usually after fixing problems with duplicate class names), you simply need to rebuild the project and the reported errors go away. Reopening the file after the build might be necessary.
You should put some code to get help..
Anyway, the problem could be that drpDownCountries is contained within a Panel control.
The Panel control is a Container control, in that it can hold lots of
controls.
In order to access the controls within that Panel control,
you first need to "help" ASP.Net to find it.
The typical way of doing this is to use the FindControl method look here.
Code sample:
DropDownList myDrop = (DropDownList)this.Panel1.FindControl("drpDownCountries");
if(myDrop != null)
{
..somecode..
}
Recreate the project. Just create a new project and add the elements one by one and hope it won't happen again. If it does, well that's part of the Microsoft experience: recreate another project and so on, until you decide to quit your job and join open-source.
CORRECTION
I'm going to redo the project that I have been working on since the last 3 days using ASP .NET MVC. I should be using an open-source tech for sure, but too bad it's not my decision for this project to not use .NET.
If this is happening after copy/move pages to new location, or project, you may simply check if PageName.ascx.designer.cs is included in project.
There is a bug in visual studio (or maybe reshrper): It includes PageName.ascx and PageName.ascx.cs, but not PageName.ascx.designer.cs, which must be included manually.
The only thing that worked for me was to add a temp controller in the aspx file and saving it.
That generated the designer again, and my controllers are now recognized!
You can then remove the temp controller and save; it won't ruin anything.

Cannot change SkinID property dynamically

I get this error when I try to have my C# class change the skin of an asp control:
The 'SkinId' property can only be set in or before the Page_PreInit
event for static controls. For dynamic controls, set the property before
adding it to the Controls collection.
My goal is to provide a panel, call it ID="response", on every page, and then dynamically change it's CSS class from Error to Success, or Success to Error (so it's red or green). And also I make it visible = true, when a response is created.
Apparently, I am forced to use CssClass attribute, which is the only way this will work.
As a side-off-topic note:
In PHP, you would not have a problem of using different "pre-init" "post-init" etc. A completely unnecessary process. You would simply change the html before you send it back to the user. I'm a bit confused why ASP.NET decides to overcomplicate everything. It's a bit silly for me to take time to learn all these different complicated processes to simply display a webpage. It takes time to learn all the quirks written in difficult-to-read ASP life-cycle documents on microsoft. Not to insult any microsoft people, but it's just not practical.
If it is a static control, that is you are defining the Panel in your .aspx page, then the only place to change the SkinId is in the PreInit method e.g.:
protected override void OnPreInit(EventArgs e)
{
base.OnPreInit(e);
String panelSkin = ViewState("panelSkin").toString();
panel1.SkinId = panelSkin;
}
Of Course, the PreInit method is only called when the Page is being first Initialized -- not on a PostBack.
You could save the skinId you wanted to use to the ViewState and then call a Response.Redirect("myPage.aspx")... and as seen above grab the skinId string from the ViewState and set the Panel skinId accordingly.
Alternatively, rather than using a Panel try using an UpdatePanel from the .Net Ajax library. Clicking a button in the UpdatePanel (provided it's setup to Trigger an ASyncPostBack) will run the OnPreInit method.
That said, provided you are changing the background, going with the CssClass property would be the most efficient way to do this.
ASP, and its child ASP.NET, is basically a huge hack of vanilla HTML and the IIS page renderer. It hooks into various stages of the lifecycle that already existed in IIS, rather than having its own lifecycle like PHP. As such, there are things you can do in certain areas because the things it depends on either aren't set in stone so you can change them, or are so you can work with them. The great power of ASP.NET, which is the interop with .NET classes and the .NET Framework, IMO makes up for some of its idiosyncracies.
Anyway, Skins are part of Themes, which are loaded early in the process so the controls can be initialized with their proper default Styles. That's the key; the Theme is locked after PreInit, but the Styles (and CssClasses) behind the Skins are editable right up to and including PreRender, which includes event handlers (which fire validation). So, set the Style or the CssClass dynamically.
To do it without a full postback, you can put the controls that should change color in an AJAX UpdatePanel, which can be re-rendered separately from the other elements of the page and will keep its current contents until the DOM is modified via the JavaScript client-side.
Setting the CssClass attribute is much closer to what you'd do with PHP, so why not just do that?
The two real benefits of Skin files are setting defaults for all controls (no skinId at all) or setting properties that can't be controlled with css.

ASP.Net: User control with content area, it's clearly possible but I need some details

I have seen two suggestions for my original question about whether it is possible to define a content area inside a user control and there are some helpful suggestions i.e.
Passing in content to ASP.NET user control
and
ASP.NET User Control inner content
Now, I like the theory of the latter better than the former just for aesthetic reasons. It seems to make more sense to me but the example given uses two variables content and templateContent that the answerer has not defined in their example code. Without these details I have found that the example does not work. I guess they are properties of the control? Or some such?
EDIT - DETAILS: What I am trying to do
I have need of an ASP.Net user control that conceals some content in a panel inside a placeholder and asks for the input of a code in a visible panel.
Essentially the user will put their code into the provided textbox in Panel A and submit it, it will be checked and, if it is valid, panel B and the locked content will be displayed.
I have done a test where the content was hard coded into panel B but as soon as I need to make the content a generic input it fails. If it were just text or somesuch then I could make it a property of the control, but as it is, in fact, another User Control I am having some difficulty getting this into the "hidden" panel.
Any other workable solutions are also welcome.
EDIT NOTE: The solution I'm trying to implement this in 2.0 I did find a 3.5 solution which I cannot use.
The former example seems workable but I'd prefer to go with the latter if someone could fill in the blanks for me.
Thanks.
Okay, so this is disturbingly easy but many of the tutorials on the web that talk about this kind of thing push to do extravagant things that require the control to parse ListItems or such.
So this solution is purely so that you can build a control that, for whatever reason, has a placeholder in it that could have anything inside it (kind of like a content area on a Master page). In this instance it happens to be because the Panel containing the placeholder is hidden until appropriate input actions have taken place in another panel.
First, you need to add this:
[ParseChildren(true,"Content")]
[PersistChildren(false)]
just above the part of the control which looks like this:
public partial class MyControl : System.Web.UI.UserControl
then in the control scoped declarations at the head of the control you want to declare thus:
private Control _content;
[PersistenceMode(PersistenceMode.InnerProperty)]
public Control Content { get { return _content; } set { _content = value; } }
Finally you need to place the content into the placeholder like this:
phContent.Controls.Add((Control)_content);
That last line goes into the Page_Init event. For reference "phContent" is the name of the place holder where you want the content to appear, like this:
<asp:Panel ID="pnlLockable" runat="server" Visible="False">
<asp:Placeholder runat="server" ID="phContent" />
</asp:Panel>
On the front end the resulting implementation looks like this:
<uc:MyControl runat="server" ID="lockit1">
<Content>
//...your stuff goes here...
</Content>
<uc:MyControl>
Note that I presume that what is inbetween the Content Tags is a root control. This is because I nested another user control in there. I imagine if you put whatever content you want within a panel or placeholder it should be fine.
Also you can read "How to: Create Templated ASP.NET User Controls". Really helpful.

Categories

Resources