Link to home
Start Free TrialLog in
Avatar of veruthandai
veruthandaiFlag for United States of America

asked on

Interface for Event Handler in ASP.NET

This is a difficult question to properly phrase.

I have a user control that is fairly complex in appearance - but I need it to be open ended in functionality. Specifically an event or two that it fires off based on a built in component.

I've tried inheriting from it to make a second control that wraps it for more specific means (the control needs to be used in several places, always looking the same, but behaving differently under the hood). This proved fruitless ,as while the code is preserved the HTML styling is not - which entirely defeats the purpose of wrapping the control to begin with.

So my thought was to try an interface. It's been a long time since I've worked with them, and I don't think I've ever done them with ASP.NET. But essentially this is the scenario.

Interface iEventHandlers needs to have an abstract event handler method that the wrapper user control implements, and whenever the child control that is embedded on that user control fires it's event, this interface event handler is fired and passed up to the parent control for handling.

Any suggestions?
Avatar of raterus
raterus
Flag of United States of America image

I personally like your first idea better.  What exactly were you doing that would have changed the HTML formatting?  That doesn't seem like it should happen to me.

Interfaces may work here too, but they are not inheritance, they just merely tell a class what methods they need to create.
Avatar of veruthandai

ASKER


public partial class BaseControl : System.Web.UI.UserControl
{
}

[HTML]
...

public partial class EncapsulatedControl : BaseControl
{
}

The HTML from BaseControl never renders. I've tried it over and over, followed dozens of guides ,it just plain does not render the base Control HTML from the ascx page. It inherits the class, but the html code is not rendered in any manner at all.
Included is the full source code for the two controls.
[WebUploader.ascx]
=============================================================
<%@ Control Language="C#" AutoEventWireup="true" CodeFile="WebUploader.ascx.cs" Inherits="Azure.UserControls.WebUploader" %>
<%@ Register Assembly="ComponentArt.Web.UI" Namespace="ComponentArt.Web.UI" TagPrefix="ComponentArt" %>
 
<div class="upload">
	<ComponentArt:Upload ID="ctrUpload" runat="server" 
		UploadCompleteClientTemplateId="CompletedTemplate"
		FileInputClientTemplateId="FileInputTemplate"
		ProgressClientTemplateId="ProgressTemplate" 
		FileInputImageUrl="Resources/Images/Dialogs/_browse.png"
		FileInputHoverImageUrl="Resources/Images/Dialogs/_browse-h.png" 
		OnUploaded="OnUploaded"
		OverwriteExistingFiles="true">
		<ClientTemplates>
			<ComponentArt:ClientTemplate ID="FileInputTemplate">
				<div>	
					<div class="filename">
						<input value="## DataItem.FileName ? DataItem.FileName : "Please select a file to upload"; ##" onfocus="this.blur();" />
					</div>
					<a href="javascript:void(0);" class="browse" onclick="this.blur();return false;" title="Browse for a file">#$FileInputImage</a>
					<a href="javascript:void(0);" onclick="ctrUpload.upload();this.blur();return false;" class="upload" id="btn-upload"></a>
				</div>
			</ComponentArt:ClientTemplate>
			<ComponentArt:ClientTemplate ID="ProgressTemplate">
				<div style="WIDTH: 250px; PADDING: 40px; BORDER: 1px solid #000; BACKGROUND: #ccc;
					COLOR: #000;">
					<strong>## Math.floor(DataItem.Progress * 100) ##%</strong> complete</div>
			</ComponentArt:ClientTemplate>
			<ComponentArt:ClientTemplate ID="CompletedTemplate">
				<div style="WIDTH: 250px; PADDING: 40px; BORDER: 1px solid #000; BACKGROUND-COLOR: #ccc;
					COLOR: #000;">
					Upload complete.</div>
			</ComponentArt:ClientTemplate>
		</ClientTemplates>
	</ComponentArt:Upload>
</div>
[WebUploader.ascx.cs]
=============================================================
using System;
using System.IO;
 
using System.Web;
using System.Web.UI;
 
using System.ComponentModel;
 
namespace Azure.UserControls
{
	public partial class WebUploader : System.Web.UI.UserControl
	{
		/// <summary>
		/// Handles the image uploading procedure.
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
		public void OnUploaded(object sender, ComponentArt.Web.UI.UploadUploadedEventArgs e)
		{
			foreach (ComponentArt.Web.UI.UploadedFileInfo oInfo in e.UploadedFiles)
				oInfo.SaveAs(Path.Combine(Server.MapPath("~/Resources/pictures"), oInfo.FileName));
		}
 
		/// <summary>
		/// The Upload Control Exposed
		/// </summary>
		[ Browsable( true ) ]
		public ComponentArt.Web.UI.Upload Upload
		{
			get { return ctrUpload; }
			set { ctrUpload = value; }
		}
	}
}
 
[WebGalleryUploader.ascx]
=============================================================
<%@ Control Language="C#" AutoEventWireup="true" CodeFile="WebGalleryUploader.ascx.cs" Inherits="Azure.UserControls.Uploaders.WebGalleryUploader" %>
<%@ Register Assembly="ComponentArt.Web.UI" Namespace="ComponentArt.Web.UI" TagPrefix="ComponentArt" %>
<%@ Register TagName="WebUploader" TagPrefix="asp" Src="~/UserControls/WebUploader.ascx" %>
 
[WebGalleryUploader.ascx.cs]
=============================================================
using System;
 
namespace Azure.UserControls.Uploaders
{
	public partial class WebGalleryUploader : System.Web.UI.UserControl
	{
	}
}

Open in new window

I did play around with this some, never done something quite like this so there may be better options.  This seems like a hack, but it might just work.

I have two UserControls,
-MyBaseControl.ascx, i.e. your main control with lots of form design, etc.
-MyControl.ascx, "Inherits" from MyBaseControl.

Anyway, here is the source of MyControl, I was able to render the contents of MyBaseControl from it.



<%@ Reference Control="~/Test/MyBaseControl.ascx" %>
<%@ Control Language="C#" AutoEventWireup="true" CodeFile="MyControl.ascx.cs" Inherits="Test_MyControl" %>
 
 
 
using System;
using System.Data;
using System.Configuration;
using System.Collections;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
 
public partial class Test_MyControl : System.Web.UI.UserControl
{
    UserControl m_base;
 
    protected override void OnInit(EventArgs e)
    {
        base.OnInit(e);
        m_base = (Test_MyBaseControl)Page.LoadControl("MyBaseControl.ascx");
    }
 
    protected override void Render(HtmlTextWriter writer)
    {
        base.Render(writer);
        m_base.RenderControl(writer);
    }
}

Open in new window

That still doesn't solve the issue though. I still cannot override the OnUploaded event because the control doesn't inherit, it merely implements the other user control - which is the same as just placing the user control in the top-level control in the first place.
Unfortunately, as you are figuring out, user controls are just not the best controls when it comes to extending them.  I tried a few more ways to get it to work the way you want, however I couldn't come up with anything.

I guess rewriting the user control so it is a custom composite control is out of the question?
How would I do that?
I'd read up on custom composite controls, but the basics are your base control inherits from System.Web.UI.Control, and you override the CreateChildControls method to build your control collection.  So very simplistic, if your original UserControl design looked like this.

<asp:panel id='pnlTest' runat="server">
  <asp:button id='btnTest' runat="server">
</asp:panel>

in CreateChildControls you do something like this

Panel pnlTest = new Panel();
pnlTest.ID = "pnlTest";

Button btnTest = new Button();
btnTest.Id = 'btnTest'

pnlTest.Controls.Add(btnTest);

this.Controls.Add(pnlTest);

You basically have to wire up anything else, like event handlers, and if you wanted to use the control in other areas of the control you have to declare it publicly at the class level.  There is nothing the User Control can do that this method can't do, you just don't get the "pretty" design of the User Control.  But you can inherit easily.
If I expose the internal control via property, how can I hook up it's Uploaded event to an event handler in the container control? That might solve the problem entirely and I'll just bypass the need for inheritence altogether.
I think what I understood is you want to override the Uploaded event to provide your own functionality.  I think this will be more difficult in the first method I provided, as you won't be able to "override" anything through inheritance.  Do you only foresee yourself overriding this event, or multiple events.  If it was one function, you could "hack" it, but for many, I wouldn't go this route.
This is the only event - at this scope of the project.
Here's the overall problem. I'm using ComponentArt's Uploader control. Now, it's all fine and dandy. It has some issues but what doesn't? This specific control doesn't map URLs relative to the server (and they still won't fix it... ) so it's a real headache to skin the blasted thing.
My goal was to get it how I wanted it and wrap it up in a sub-control for each different behavior. The behavior is modified using the OnUploaded event which fires after files are dropped into a temporary folder and a list of all of the uploaded files is returned to me via that Event.
If I can handle the event, it doesn't matter if it's inherited or not - I just need to be able to have different versions of the Event Handler for each 'Type' of Uploader I need.
See the issue? So either I waste a lot of time re-skinning and copy/paste everytime an update occurs or something changes or heaven forbid if they fix the Url Mapping problems and I could have just used a .skin file to begin with - or I find a fix now and avoid the underlying issue from the getgo.
Please forgive my ignorance - but I'm uncertain what you mean by 'hack' it. Could you elaborate?
Here are my thoughts on that, and I know it can be done, but I don't know the specific code yet.  You know when you have a Gridview, or another control, you set "AllowSorting" or another feature, but if you don't implement a sorting event handler, asp.net will raise an error "Gridview blah blah raised event OnSorting but it wasn't handled"?

I'm sure you can do the same here.  Your User Control raises an event that it can check whether it was handled or not.  If it wasn't handled, you use the default implementation, if it was handled, you don't do anything (your other control did what needed to be done).

I'll have to do some research to figure out what .Net is using for the built-in controls to determine whether an event was handled or not.
ASKER CERTIFIED SOLUTION
Avatar of raterus
raterus
Flag of United States of America image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial