?
Solved

Interface for Event Handler in ASP.NET

Posted on 2009-02-11
14
Medium Priority
?
966 Views
Last Modified: 2012-05-06
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?
0
Comment
Question by:veruthandai
  • 7
  • 7
14 Comments
 
LVL 33

Expert Comment

by:raterus
ID: 23616176
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.
0
 

Author Comment

by:veruthandai
ID: 23616338

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.
0
 

Author Comment

by:veruthandai
ID: 23616569
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

0
Independent Software Vendors: We Want Your Opinion

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 
LVL 33

Expert Comment

by:raterus
ID: 23617023
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

0
 

Author Comment

by:veruthandai
ID: 23617210
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.
0
 
LVL 33

Expert Comment

by:raterus
ID: 23621820
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?
0
 

Author Comment

by:veruthandai
ID: 23622043
How would I do that?
0
 
LVL 33

Expert Comment

by:raterus
ID: 23622119
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.
0
 

Author Comment

by:veruthandai
ID: 23622343
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.
0
 
LVL 33

Expert Comment

by:raterus
ID: 23622595
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.
0
 

Author Comment

by:veruthandai
ID: 23622631
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.
0
 

Author Comment

by:veruthandai
ID: 23622730
Please forgive my ignorance - but I'm uncertain what you mean by 'hack' it. Could you elaborate?
0
 
LVL 33

Expert Comment

by:raterus
ID: 23623144
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.
0
 
LVL 33

Accepted Solution

by:
raterus earned 2000 total points
ID: 23625584
Here is an example out of the framework (below).  I honestly don't understand this completely, but maybe you can tinker with the idea.  Basically what I'm thinking is in your UserControl, you'll need to raise a custom event you define for sorting, so your base page can handle it.

Then you have something like this in your OnUploaded function to check whether the event was handled, and if it was ignore the default code, else, obviously run it.
protected virtual void OnSorting(GridViewSortEventArgs e)
{
    bool isBoundUsingDataSourceID = base.IsBoundUsingDataSourceID;
    GridViewSortEventHandler handler = (GridViewSortEventHandler) base.Events[EventSorting];
    if (handler != null)
    {
        handler(this, e);
    }
    else if (!isBoundUsingDataSourceID && !e.Cancel)
    {
        throw new HttpException(SR.GetString("GridView_UnhandledEvent", new object[] { this.ID, "Sorting" }));
    }
}

Open in new window

0

Featured Post

Free Tool: Path Explorer

An intuitive utility to help find the CSS path to UI elements on a webpage. These paths are used frequently in a variety of front-end development and QA automation tasks.

One of a set of tools we're offering as a way of saying thank you for being a part of the community.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Lots of people ask this question on how to extend the “MembershipProvider” to make use of custom authentication like using existing database or make use of some other way of authentication. Many blogs show you how to extend the membership provider c…
It was really hard time for me to get the understanding of Delegates in C#. I went through many websites and articles but I found them very clumsy. After going through those sites, I noted down the points in a easy way so here I am sharing that unde…
Is your data getting by on basic protection measures? In today’s climate of debilitating malware and ransomware—like WannaCry—that may not be enough. You need to establish more than basics, like a recovery plan that protects both data and endpoints.…
In a question here at Experts Exchange (https://www.experts-exchange.com/questions/29062564/Adobe-acrobat-reader-DC.html), a member asked how to create a signature in Adobe Acrobat Reader DC (the free Reader product, not the paid, full Acrobat produ…
Suggested Courses

829 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question