implementing IPostbackHandler .net - c#

I have a server control, inheriting from PlaceHolder.
Basically, all it is, is a placeholder, with the top part having a "<div class etc...", and the bottom closing it off.
So, typical usage would be
<control:control runat="server" id="phControl">
<asp:TextBox runat="server" id="txtControl">
<asp:DropDownList runat="server"id="ddlControl">
</control:control>
or something similar.
It has struck me that if I postback to the control, it loses all the items in the ddlControl (or whatever), and that implementing IPostBackHandler apparently would solve all my woes.
I had a quick glance through the documentation, but am still not really sure what I am implementing (obviously I have the method names, but I don't really get what is expected in here)
Any pointers in the right direction would be greatly appreciated.
Thanks,
Tim

Its looks like you just want a server control that can contains other controls or a "template", I have just done this using the example at: http://msdn.microsoft.com/en-us/library/ms178657.aspx
This should handle all the work done on postback.
A basic example adapted from the above link:
using System;
using System.ComponentModel;
using System.Security.Permissions;
using System.Web;
using System.Web.UI;
using System.Web.UI.Design;
using System.Web.UI.WebControls;
namespace Made4Print.Web.UI
{
[AspNetHostingPermission(SecurityAction.InheritanceDemand, Level = AspNetHostingPermissionLevel.Minimal), AspNetHostingPermission(SecurityAction.Demand, Level = AspNetHostingPermissionLevel.Minimal), Designer(typeof(VacationHomeDesigner)), DefaultProperty("Title"), ToolboxData("<{0}:TemplateContainer runat=\"server\"> "),]
public class TemplateContainer : CompositeControl
{
private ITemplate templateValue;
private TemplateOwner ownerValue;
[Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public TemplateOwner Owner
{
get
{
return ownerValue;
}
}
[Browsable(false), PersistenceMode(PersistenceMode.InnerProperty), DefaultValue(typeof(ITemplate), ""), Description("Control template"), TemplateContainer(typeof(TemplateContainer))]
public virtual ITemplate Template
{
get
{
return templateValue;
}
set
{
templateValue = value;
}
}
protected override void CreateChildControls()
{
Controls.Clear();
ownerValue = new TemplateOwner();
ITemplate temp = templateValue;
if (temp == null)
{
temp = new DefaultTemplate();
}
temp.InstantiateIn(ownerValue);
this.Controls.Add(ownerValue);
}
public override void DataBind()
{
CreateChildControls();
ChildControlsCreated = true;
base.DataBind();
}
}
[ToolboxItem(false)]
public class TemplateOwner : WebControl
{
}
#region DefaultTemplate
sealed class DefaultTemplate : ITemplate
{
void ITemplate.InstantiateIn(Control owner)
{
// Create Controls Here
//Label title = new Label();
//title.DataBinding += new EventHandler(title_DataBinding);
//owner.Controls.Add(title);
}
//void title_DataBinding(object sender, EventArgs e)
//{
// Label source = (Label)sender;
// TemplateContainer container = (TemplateContainer)(source.NamingContainer);
// source.Text = container.Title;
//}
}
#endregion
public class VacationHomeDesigner : ControlDesigner
{
public override void Initialize(IComponent Component)
{
base.Initialize(Component);
SetViewFlags(ViewFlags.TemplateEditing, true);
}
public override string GetDesignTimeHtml()
{
return "<span>[Template Container Control]</span>";
}
public override TemplateGroupCollection TemplateGroups
{
get
{
TemplateGroupCollection collection = new TemplateGroupCollection();
TemplateGroup group;
TemplateDefinition template;
TemplateContainer control;
control = (TemplateContainer)Component;
group = new TemplateGroup("Item");
template = new TemplateDefinition(this, "Template", control, "Template", true);
group.AddTemplateDefinition(template);
collection.Add(group);
return collection;
}
}
}
}

Related

How do I access ASP.NET ITemplate Container Properties

I'm trying to learn how to use ITemplate for nicer custom controls. I have it mostly working but I haven't been able to figure out how to access any properties of the container from the page.
Here is my templated control:
[ParseChildren(true)]
[PersistChildren(false)]
public partial class Example : UserControl
{
private ITemplate _CustomPanelContainer;
[PersistenceMode(PersistenceMode.InnerProperty)]
[TemplateContainer(typeof(CustomPanelContainer))]
[TemplateInstance(TemplateInstance.Single)]
public virtual ITemplate CustomPanel
{
get { return _CustomPanelContainer; }
set { _CustomPanelContainer = value; }
}
protected override void CreateChildControls()
{
Controls.Clear();
if (_CustomPanelContainer != null)
{
var p = new Panel();
p.ID = "CustomPanel";
Controls.Add(p);
_CustomPanelContainer.InstantiateIn(p);
}
base.CreateChildControls();
}
public class CustomPanelContainer : Panel, INamingContainer
{
private string _Test = "TESTING!";
public string TextTest
{
get
{
return _Test;
}
set
{
_Test = value;
}
}
}
}
Here is the page implementation:
<uc1:Example runat="server" ID="Example1">
<CustomPanel>
<strong>Test: </strong> <%# Container.TextTest %>
</CustomPanel>
</uc1:Example>
It is mostly working but the problem is that <%# Container.TextTest %> always returns an empty string. When I run it on the debugger, I put a breakpoint at the line inside the TextTest property of CustomPanelContainer and the breakpoint is never hit, so the property is never actually being accessed.
What am I missing here? How do I enable access to the container's public properties via <%#Container ?
I finally figured out how to make it act the way I want.
I removed ITemplate as the type of the Container and set the type as the actual type and added a DataBind() command to CreateChildControls().
Maybe not quite the correct way to do this, but it works.
Keeping the question open for a bit to see if anyone offers any critique or a better approach, since I really don't know what I'm doing here yet.
Simplified Working code:
[ParseChildren(true)]
[PersistChildren(false)]
public partial class Example : UserControl
{
[PersistenceMode(PersistenceMode.InnerProperty)]
[TemplateInstance(TemplateInstance.Single)]
public virtual CustomPanelContainer Template { get; set; }
protected override void CreateChildControls()
{
Controls.Clear();
if (Template != null)
{
Template.DataBind();
Controls.Add(Template);
}
base.CreateChildControls();
}
public class CustomPanelContainer : Panel, INamingContainer
{
public string TextTest
{
get { return "TESTING!"; }
}
}
}
Page Implementation:
<uc1:Example runat="server" ID="Example">
<Template>
<strong>Test: </strong><span><%# Container.TextTest %></span>
</Template>
</uc1:Example>
EDIT: This also works when needing to hide the type of the template.
i,e., the code above exposes the type of Template to allow manipulating properties of the Panel as attributes of Template, whereas the code below hides the type of Template to block manipulation of its properties.
[ParseChildren(true)]
[PersistChildren(false)]
public partial class Example : UserControl
{
[PersistenceMode(PersistenceMode.InnerProperty)]
[TemplateInstance(TemplateInstance.Single)]
[TemplateContainer(typeof(CustomPanelContainer))]
public virtual ITemplate Template { get; set; }
protected override void CreateChildControls()
{
Controls.Clear();
if (Template != null)
{
var p = new CustomPanelContainer();
Template.InstantiateIn(p);
p.DataBind();
Controls.Add(p);
}
base.CreateChildControls();
}
public class CustomPanelContainer : Panel, INamingContainer
{
public string TextTest
{
get { return "TESTING!"; }
}
}

Setting default size/text of custom control in c#

I am creating a custom control in my C# application in order to add a new property (MyProperty below). It is inheriting from Label. One thing I would like it to do, is display at a particular size when I drag it on to my form (200x132). I'd also like it to display no text. However, no matter how I try to do this, it doesn't seem to work. I am able to set BackColor and BorderStyle with no problem, however. I'm fairly new to C#, so maybe I'm missing something obvious.
Here is my code:
using System.Drawing;
using System.Windows.Forms;
namespace MyProgram
{
public enum MyEnum
{
Value1, Value2, Value3
}
public partial class MyControl : Label
{
public MyControl()
{
BackColor = Color.LightCoral;
BorderStyle = BorderStyle.FixedSingle;
AutoSize = false;
Size = new Size(200, 132);
Text = "";
InitializeComponent();
}
protected override void OnPaint(PaintEventArgs pe)
{
base.OnPaint(pe);
}
private MyEnum myProperty;
public MyEnum MyProperty
{
get { return myProperty; }
set { myPropery = value; }
}
}
}
The answer provided via Dispersia's link has a bug, in my opinion. The text reset should happen once and then whatever a user does after that shouldn't matter. In Dispersia's link you can't actually set the text back to the control name because it will keep blanking it out.
The answer provided by cramopy doesn't technically answer your question, it is a way to do it by using the defaults on a UserControl though. You'll also need to bind the Text property of the UserControl to the label's.
The following should work while inheriting from a Label and will only reset the Text property once.
public partial class MyControl : Label
{
#region fields
private IComponentChangeService _changeService;
private bool canResetText = false;
#endregion
#region properties
protected override Size DefaultSize
{
get { return new Size(200, 132); }
}
[Browsable(false)]
public override bool AutoSize
{
get { return false; }
set { base.AutoSize = false; }
}
public override ISite Site
{
get { return base.Site; }
set
{
base.Site = value;
if (!base.DesignMode)
return;
this._changeService = (IComponentChangeService)base.GetService(typeof(IComponentChangeService));
if (this._changeService != null)
this._changeService.ComponentChanged += new ComponentChangedEventHandler(this.OnComponentChanged);
}
}
#endregion
#region constructors
public MyControl()
{
base.BackColor = Color.LightCoral;
base.BorderStyle = BorderStyle.FixedSingle;
}
#endregion
#region methods
protected override void InitLayout()
{
base.InitLayout();
this.canResetText = true;
}
private void OnComponentChanged(object sender, ComponentChangedEventArgs ce)
{
if (ce.Component != null &&
ce.Component == this &&
ce.Member.Name == "Text" &&
base.DesignMode &&
this.canResetText)
{
((MyControl)ce.Component).Text = string.Empty;
this.canResetText = false;
if (this._changeService != null)
this._changeService.ComponentChanged -= new ComponentChangedEventHandler(this.OnComponentChanged);
}
}
#endregion
}
#Dispersia reply only answers the myControl1 thing. (deleted meanwhile)
Here comes a full guide for solving your problem:
Add a new UserControl named MyLabel
Change the following within Designer Mode:
BorderStyle:= FixedSingle
Size:= 200; 132
Now Drag&Drop a new Label onto the control
Edit those Label values (also within Designer Mode):
AutoSize:= false
BackColor:= LightCoral
Dock:= Fill
Text:= clear/empty this box!! (don't write this inside the box, you really have to clear it!)
TextAlign:= MiddleCenter
Just recompile your project && add a MyLabel control from the Toolbar.
Now it show up as you wanted!!

Display specific properties in the Property grid

When we press the btnSettings, all the user controls properties will be displayed in Property grid. I want display specific properties (only TemperatureValue and TemperatureUnit), is possible? User control code as follows:
using System;
using System.Windows.Forms;
namespace Temperature
{
public partial class temperatureUc : UserControl
{
public enum temperatureUnit
{
Celsius, // default
Delisle, // °De = (100 − °C) * 3⁄2
Fahrenheit, // °F = °C * 9⁄5 + 32
Kelvin, // °K = °C + 273.15
Newton, // °N = °C * 33⁄100
Rankine, // °R = (°C + 273.15) * 9⁄5
Réaumur, // °Ré = °C * 4⁄5
Rømer // °Rø = °C * 21⁄40 + 7.5
}
public temperatureUc()
{
InitializeComponent();
this.cboTemperatureUnit.DataSource = Enum.GetValues(typeof(temperatureUnit));
}
#region "Event"
public delegate void SettingsStateEventHandler(object sender, EventArgs e);
public event SettingsStateEventHandler settingsStateChanged;
private void OnSettingsChanged(object sender, EventArgs e)
{
if (this.settingsStateChanged != null)
this.settingsStateChanged(sender, e);
}
#endregion
#region "Properties"
private Single _TemperatureValue;
public Single TemperatureValue
{
get
{
return this._TemperatureValue;
}
set
{
if (value.GetType() == typeof(Single))
{
_TemperatureValue = value;
this.txtTemperatureValue.Text = _TemperatureValue.ToString();
}
}
}
private temperatureUnit _TemperatureUnit;
public temperatureUnit TemperatureUnit
{
get
{
return this._TemperatureUnit;
}
set
{
if (value.GetType() == typeof(temperatureUnit))
{
_TemperatureUnit = value;
this.cboTemperatureUnit.Text = _TemperatureUnit.ToString();
}
}
}
#endregion
private void btnSettings_Click(object sender, EventArgs e)
{
this.OnSettingsChanged(sender, e);
}
}
}
User control above code will be called from code bellow:
using System;
using System.Windows.Forms;
using Temperature;
using System.Diagnostics;
using System.Drawing;
namespace TemperatureImplements
{
public partial class Form1 : Form
{
private PropertyGrid pGrid = new PropertyGrid();
public Form1()
{
InitializeComponent();
this.temperatureUc1.settingsStateChanged += new temperatureUc.SettingsStateEventHandler(temperatureUc1_settingsStateChanged);
}
void temperatureUc1_settingsStateChanged(object sender, EventArgs e)
{
pGrid.Size = new Size(300, 500);
pGrid.Location = new Point(300,10);
pGrid.SelectedObject = temperatureUc1;
this.Controls.Add(pGrid);
}
}
}
Picture as follows:
There is a way. This article has a section called "Customizing the PropertyGrid Control" that explains how to do it http://msdn.microsoft.com/en-us/library/aa302326.aspx#usingpropgrid_topic5
Basically you just want to define the AppSettings class to only include TemperatureUnit andTemeratureValue`.
AppSettings appset = new AppSettings();
MyPropertyGrid.SelectedObject = appset;
Define AppSettings as follows;
[DefaultPropertyAttribute("SaveOnClose")]
public class AppSettings{
private bool saveOnClose = true;
private string tempUnit;
private int tempValue;
[CategoryAttribute("Global Settings"),
ReadOnlyAttribute(false),
DefaultValueAttribute("Celsius")]
public string TemperatureUnit
{
get { return tempUnit; }
set { tempUnit = value; }
}
[CategoryAttribute("Global Settings"),
ReadOnlyAttribute(false),
DefaultValueAttribute(0)]
public string TemperatureValue
{
get { return tempValue; }
set { tempValue = value; }
}
}
By the way, I'm changing the category from Misc to Global Settings, don't know if that's what you want but it makes sense when they're the only options. You may have to explicitly declare the other attributes this BrowsableAttribute(false) so they're not displayed but I don't think it's necessary.
There might be a way to hide those properties but I think that's the wrong way to go about it.
Instead of passing the user control itself you should create a model with TemperatureUnit and TemperatureValue. Move your defined events to this model.
Then you need to extend a user control which you pass the model to and listens for these events.
Finally set pGrid.SelectedObject to your model and you'll be good to go.

Control HTML rendered by CompositeControl Templated Server Controls

I'm building my first custom server control which inherits from CompositeControl
The reason for the control is to be able to have a consistent content area (HTML elements) for multiple online applications that we develop.
So instead of having to constantly type out:
<div class="titleBar">
</div>
<div class="actionBar">
</div>
<div class="workspace">
</div>
the developer could add a server control as follows:
<custom:Workspace id="..." runat="server" Title="MyTitle">
<TitleBar>
Here is the title
</TitleBar>
<ActionBar>
<asp:button id="..." runat="server" Title="MyButton" />
</ActionBar>
<Content>
<asp:DataGrid id="..." runat="server" />
</Content>
</custom:Workspace>
I read the article at http://msdn.microsoft.com/en-us/library/ms178657.aspx and it works, but the problem is... I don't understand why. (Does anyone have a link to a layman's version of an article that describes how to build these kinds of server controls?)
Main thing I notice so far is that Asp.net is rendering a bunch of SPAN elements, which of course I don't want.
How does one control the HTML that the new CompositeControl is outputting?
Thanks,
Jacques
PS. Here's my code so far:
using System;
using System.ComponentModel;
using System.Drawing;
using System.Security.Permissions;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.Design;
namespace TemplatedServerControl
{
[DefaultProperty("Title")]
[ToolboxData("<{0}:Workspace runat=server></{0}:Workspace>")]
public class Workspace : CompositeControl
{
#region FIELDS
private ITemplate _TitleBarTemplateValue;
private ITemplate _ActionBarTemplateValue;
private TemplateOwner _TitleBarOwnerValue;
private TemplateOwner _ActionBarOwnerValue;
#endregion
#region PROPERTY - TitleBarOwner
[Browsable(false),
DesignerSerializationVisibility(
DesignerSerializationVisibility.Hidden)]
public TemplateOwner TitleBarOwner
{
get
{
return _TitleBarOwnerValue;
}
}
#endregion
#region PROPERTY - ActionBarOwner
[Browsable(false),
DesignerSerializationVisibility(
DesignerSerializationVisibility.Hidden)]
public TemplateOwner ActionBarOwner
{
get
{
return _ActionBarOwnerValue;
}
}
#endregion
#region PROPERTY - Title
[Bindable(true)]
[Category("Appearance")]
[DefaultValue("[Provide the title for the workspace]")]
[Localizable(true)]
public string Title
{
get
{
String s = (String)ViewState["Title"];
return ((s == null) ? "[" + this.ID + "]" : s);
}
set
{
ViewState["Text"] = value;
}
}
#endregion
#region PROPERTY - TitleBar
[Browsable(false),
PersistenceMode(PersistenceMode.InnerProperty),
DefaultValue(typeof(ITemplate), ""),
Description("Control template"),
TemplateContainer(typeof(Workspace))]
public virtual ITemplate TitleBar
{
get
{
return _TitleBarTemplateValue;
}
set
{
_TitleBarTemplateValue = value;
}
}
#endregion
#region PROPERTY - ActionBar
[Browsable(false),
PersistenceMode(PersistenceMode.InnerProperty),
DefaultValue(typeof(ITemplate), ""),
Description("Control template"),
TemplateContainer(typeof(Workspace))]
public virtual ITemplate ActionBar
{
get
{
return _ActionBarTemplateValue;
}
set
{
_ActionBarTemplateValue = value;
}
}
#endregion
#region METHOD - CreateChildControls()
protected override void CreateChildControls()
{
//base.CreateChildControls();
Controls.Clear();
_TitleBarOwnerValue = new TemplateOwner();
_ActionBarOwnerValue = new TemplateOwner();
ITemplate temp1 = _TitleBarTemplateValue;
ITemplate temp2 = _ActionBarTemplateValue;
temp1.InstantiateIn(_TitleBarOwnerValue);
temp2.InstantiateIn(_ActionBarOwnerValue);
this.Controls.Add(_TitleBarOwnerValue);
this.Controls.Add(_ActionBarOwnerValue);
}
#endregion
#region METHOD - RenderContents(HtmlTextWriter writer)
protected override void RenderContents(HtmlTextWriter writer)
{
base.RenderContents(writer);
}
#endregion
}
[ToolboxItem(false)]
public class TemplateOwner : WebControl
{
}
}
The extra <span> elements are coming from the TemplateOwner controls because a WebControl (which TemplateOwner inherits from) renders <span> tags by default. You could change TemplateOwner to specify the tag to render:
public class TemplateOwner : WebControl
{
public TemplateOwner() :
base(HtmlTextWriterTag.Div)
{
}
}
But you don't need to create your own class to use templates. For example, you can just use Panel controls:
private Panel _TitleBarPanel;
private Panel _ActionBarPanel;
protected override void CreateChildControls()
{
_TitleBarPanel = new Panel { CssClass = "titleBar" };
_TitleBarTemplateValue.InstantiateIn(_TitleBarPanel);
this.Controls.Add(_TitleBarPanel);
_ActionBarPanel = new Panel { CssClass = "actionBar" };
_ActionBarTemplateValue.InstantiateIn(_ActionBarPanel);
this.Controls.Add(_ActionBarPanel);
}
A simpler solution us to use the PlaceHolder control.
Like CompositeControl, this is a container control.
Unlike CompositeControl however, it doesn't render any content at all - no containing or tags.
It does mean that you can't refer to the entire control programatically, like you can with a CompositeControl, but depending on what you are doing, that may not be necessary.
Each subcontrol will have a unique ID though, so you can refer to child controls programatically (deal with events etc)

ASP.Net Custom Server Control Not Firing Custom Event

I have created a custom server control. It looks great and the rendered HTML is also as it should be. I initially had it extending the ControlContainer and now it extends the WebControl (both behave the same.) It has two properties, ImageUrl and Text. Essentially it will render a generic HTML tag with an and tags within it.
My problem is that the ServerClick event that is exposed (by NamingContainer I beleive) doesn't seem to fire. If I add any of the ASP buttons (Link, Image or regular) and associate to that Click event it fires but of course I have extra rendered content. It successfully runs the javascript and does the __dopostback call. But it must not see the given control ID or something because the event never gets fired.
using System;
using System.ComponentModel;
using System.Drawing.Design;
using System.Web.UI;
using System.Web.UI.HtmlControls;
using System.Web.UI.WebControls;
namespace PLSO.Info.Web.UI {
[DefaultEvent("Submit")]
[DefaultProperty("Text")]
[ToolboxData("<{0}:ComboButton runat=\"server\"> </{0}:ComboButton>")]
public class ComboButton : WebControl {
private HtmlImage imageControl;
private HtmlGenericControl spanControl;
private static readonly object EventSubmitKey = new object();
[Bindable(true)]
[Category("Appearance")]
[DefaultValue("")]
[Description("The text to display on the button.")]
public string Text {
get { return ViewState["NewText"] as string; }
set { ViewState["NewText"] = value; }
}
[DefaultValue("")]
[Bindable(true)]
[Category("Appearance")]
[UrlProperty()]
[Editor("System.Web.UI.Design.ImageUrlEditor, System.Design, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a", typeof(UITypeEditor))]
public string ImageUrl {
get {
EnsureChildControls();
return this.imageControl.Src;
}
set {
EnsureChildControls();
this.imageControl.Src = value;
}
} // ImageUrl - Property
public override string CssClass {
get { return ViewState["CssClass"] as string; }
set { ViewState["CssClass"] = value; }
}
[Category("Action")]
[Description("Raised when the user clicks the button.")]
public event EventHandler Submit {
add { Events.AddHandler(EventSubmitKey, value); }
remove { Events.RemoveHandler(EventSubmitKey, value); }
}
protected virtual void OnSubmit(EventArgs e) {
EventHandler SubmitHandler = (EventHandler)Events[EventSubmitKey];
if (SubmitHandler != null)
SubmitHandler(this, e);
}
void ComboButton_Submit(object sender, EventArgs e) {
OnSubmit(EventArgs.Empty);
}
protected override void CreateChildControls() {
Controls.Clear();
imageControl = new HtmlImage();
imageControl.Src = this.ImageUrl;
imageControl.Alt = this.Text;
this.Controls.Add(imageControl);
spanControl = new HtmlGenericControl("span");
spanControl.InnerText = this.Text;
this.Controls.Add(spanControl);
this.Submit += new EventHandler(ComboButton_Submit);
ChildControlsCreated = true;
}
protected override void Render(HtmlTextWriter writer) {
PostBackOptions pbo = new PostBackOptions(this);
AddAttributesToRender(writer);
writer.AddAttribute(HtmlTextWriterAttribute.Class, this.CssClass);
writer.AddAttribute("onclick", string.Format("javascript:{0}", Page.ClientScript.GetPostBackEventReference(pbo)));
writer.RenderBeginTag(HtmlTextWriterTag.Button);
imageControl.RenderControl(writer);
spanControl.RenderControl(writer);
writer.RenderEndTag();
}
}
}
Here is my markup. I put in this control and then a regular ASP:Button. That regular button's event gets hit! Not mine.
<ucs:ComboButton ID="btnT4" runat="server" Text="Please" CssClass="PButtonCombo" ImageUrl="~/Styles/icons/edit-find.png" OnSubmit="btnT4_Submit" />
<asp:Button ID="btnT5" runat="server" Text="TEST" onclick="btnT5_Click" UseSubmitBehavior="False" />
And here is the rendered HTML:
<button id="MainContent_btnT4" class="PButtonCombo" onclick="javascript:__doPostBack('ctl00$MainContent$btnT4','')"><img src="../Styles/icons/edit-find.png" alt="Please" /><span>Please</span></button>
<input type="button" name="ctl00$MainContent$btnT5" value="TEST" onclick="javascript:__doPostBack('ctl00$MainContent$btnT5','')" id="MainContent_btnT5" />
I have to believe I am close but just missing something. Been tweaking it for hours today, PLEASE HELP!
EDIT:
Thanks to #James answer, all I did was add the following to the top of the above example. It did the trick but now fires twice. Not sure why? So that is my current question:
public class ComboButton : WebControl, IPostBackEventHandler {
public void RaisePostBackEvent(string eventArgument) {
OnClick(new EventArgs());
}
[Category("Action")]
[Description("Raised when the user clicks the button.")]
public event EventHandler Click;
protected virtual void OnClick(EventArgs e) {
if (Click != null)
Click(this, e);
}
EDIT 2 == SOLUTION
using System.ComponentModel;
using System.Drawing.Design;
using System.Web.UI;
using System.Web.UI.HtmlControls;
using System.Web.UI.WebControls;
namespace PLSO.Info.Web.UI {
[DefaultEvent("Submit")]
[DefaultProperty("Text")]
[ToolboxData("<{0}:ComboButton runat=\"server\"> </{0}:ComboButton>")]
public class ComboButton : Button {
private HtmlImage imageControl;
private HtmlGenericControl spanControl;
[DefaultValue("")]
[Bindable(true)]
[Category("Appearance")]
[UrlProperty()]
[Editor("System.Web.UI.Design.ImageUrlEditor, System.Design, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a", typeof(UITypeEditor))]
public string ImageUrl {
get {
EnsureChildControls();
return this.imageControl.Src;
}
set {
EnsureChildControls();
this.imageControl.Src = value;
}
} // ImageUrl - Property
protected override void CreateChildControls() {
Controls.Clear();
imageControl = new HtmlImage();
imageControl.Src = this.ImageUrl;
imageControl.Alt = this.Text;
this.Controls.Add(imageControl);
spanControl = new HtmlGenericControl("span");
spanControl.InnerText = this.Text;
this.Controls.Add(spanControl);
ChildControlsCreated = true;
} // CreateChildControls - Method - Override
protected override void Render(HtmlTextWriter writer) {
PostBackOptions pbo = new PostBackOptions(this);
AddAttributesToRender(writer);
writer.RenderBeginTag(HtmlTextWriterTag.Button);
imageControl.RenderControl(writer);
spanControl.RenderControl(writer);
writer.RenderEndTag();
} // Render - Event - Override
}
}
Try implementing the IPostBackEventHandler interface:
public class ComboButton : WebControl, IPostBackEventHandler
{
public void RaisePostBackEvent(string eventArgument)
{
OnSubmit(EventArgs.Empty);
}
}
Here's an article that explains the implementation of the IPostBackEventHandler interface:
http://msdn.microsoft.com/en-us/library/system.web.ui.ipostbackeventhandler.aspx
EDIT
If your events are in some way dependent on data, you need to implement the IPostBackDataHandler interface. For example, you would use the IPostBackDataHandler interface to fire the OnTextChanged event of a TextBox:
public class ComboButton : WebControl, IPostBackDataHandler
{
public virtual bool LoadPostData(string postDataKey, NameValueCollection postCollection)
{
return true;
}
public virtual void RaisePostDataChangedEvent()
{
}
}
Here's an article that explains the implementation of the IPostBackDataHandler interface:
http://msdn.microsoft.com/en-us/library/system.web.ui.ipostbackdatahandler.aspx
You need to look into IPostBackEventHandler
If you dont implement this interface in your control ASP.net engine wont forward the events to your control.

Categories