I have an issue with overriding a method. I have created a base class with custom code that I want to run during the OnLoad event. The code in this overridden method applies to 90% of the pages that inherit from it, but on a few pages I need to override the override. My issue is that I still need to run the System.Web.UI.Page's OnLoad implementation. If I include the base.OnLoad(e) line in the second class (see below), it calls the BasePageEdit's logic, but if I remove it, the Page_Load event is never called. How can I skip over the logic in BaseEditPage's, and still get the functionality from System.Web.UI.Page?
public class BasePageEdit : System.Web.UI.Page
{
protected override void OnLoad(EventArgs e)
{
// I need this to raise the Page_Load Event!
base.OnLoad(e); // Calls System.Web.UI.Page OnLoad Event which I want.
// Logic that I want to run in ADDITION to base Implementation;
}
// Other classes and methods;
}
public class WebPageThatNeedsSpecialOnLoadImplementation : BasePageEdit
{
protected override void OnLoad(EventArgs e)
{
// I need this to raise the Page_Load Event!
base.OnLoad(e); // If I include this, it runs the BasePageEdit, I don't want that...
// But I still need to run the System.Web.UI.Page onLoad event or Page_Load will not be called.
// Logic that I want to run INSTEAD of the logic from the override from BasePageEdit.
}
}
Thank you very much Slaks! I am editing my question to show how I implemented so that others viewing this post can implement the same way if they choose!
public class BasePageEdit : System.Web.UI.Page
{
protected override void OnLoad(EventArgs e)
{
BasePage_OnLoad(e);
// Logic that I want to run in ADDITION to base Implementation;
}
protected virtual void BasePage_OnLoad(EventArgs e)
{
base.OnLoad(e);
}
// Other classes and methods;
}
public class WebPageThatNeedsSpecialOnLoadImplementation : BasePageEdit
{
protected override void OnLoad(EventArgs e)
{
BasePage_OnLoad(e);
// Logic that I want to run INSTEAD of the logic from the override from BasePageEdit.
}
}
You can't do that.
However, you can make a new method in BasePageEdit which just calls its base.OnLoad, and call that directly from the derived class instead.
Related
I am trying to understand for which purpose the events pattern decided that the method that fires the event should be declared virtual.
From C#6 in a Nutshell, from Joseph and Ben Albahari, O'Reilley:
Finally, the pattern requires that you write a protected virtual method that fires the
event. The name must match the name of the event, prefixed with the word On, and
then accept a single EventArgs argument:
Below a snippet I created to try to investigate.
I had the impression that the idea was to allow inheriting classes to completely overwrite how the event is handled, out of the box (original class). But the snippet below shows this is not possible, because deriving classes will never be able to invoke the event objects themselves (by the one one of the goals of the constraints imposed by the keyword event on delegates). The event can be invoked only in the containing class.
Now, since the pattern also asks that the method that fires the event simply check if the the event is not null and then call the delegate, with whatever every subscriber asked to do, what is left to be achieved by having the method that fires the event as virtual ? Inheriting classes are obliged to invoke the event the way it is in the broadcaster class, so all that is left for them is to add functionality. But this is exactly what they can achieve by subscribing to the event, in other words, by adding a call to an external function the time the event is fired.
I hope my wording is clear enough.
namespace eventsPatternVirtualEventFirerer
{
internal class Program
{
private static void Main(string[] args)
{
var obj = new X();
obj.ev += Obj_ev;
obj.Start();
}
private static void Obj_ev(object sender, EventArgs e)
{
Console.WriteLine("subscriber code...");
}
}
public class X
{
public event EventHandler<EventArgs> ev;
protected virtual void OnEvent(EventArgs e)
{
Console.WriteLine("original implementation...");
ev?.Invoke(this, e);
}
public void Start()
{
OnEvent(EventArgs.Empty);
}
}
public class X2 : X
{
public X2()
{
}
protected override void OnEvent(EventArgs e)
{
Console.WriteLine("inheriting class implementation overwrite...");
//compilation error - "the event 'X.ev' can only appear on the left hand side of += or -= (except when used from within the type 'X')"
ev?.Invoke(this, e);
}
}
}
I think the purpose is to allow derived classes to do something before/after the event is fired
public class X2 : X
{
public X2()
{
}
protected override void OnEvent(EventArgs e)
{
// Do something before the event
base.OnEvent(e);
// Do something after the event
}
}
There are a few things you can add/change in a derived class
Add a OnBeforeEvent / OnAfterEvent addition.
Choose not to broadcast the event (by conditionally not calling base.OnEvent(e)).
Vary the event args in some way.
Additionally, If you think about the way something like a page model works, it typically fires a Load event to notify when the page is loaded. Without a protected OnLoad method, derived classes would have to subscribe to it's own Load event to perform some action on load
public class MyPage : Page
{
protected override void OnLoad(EventArgs e)
{
// do something when the page is loaded
base.OnLoad(e);
}
}
versus:
public class MyPage : Page
{
public MyPage() : base()
{
this.Load += (sender,e) => {
// bleugh - subscribing to my own events
}
}
}
A good example might be the Paint event in Windows Forms.
// in MyButton : BaseButton : Control
void override OnPaint(object s, PaintEveargs e)
{
base.OnPaint(s, e); // Control: Draw background, BaseButton: draw border
// draw my own stuff
}
A button has several layers of base class, each drawing on top of each other.
According to my knowledge, event methods are protected and can be override and used only within derived classes.
So, having the following Form defined in the main Form:
Form ModelBuilderSAS = new Form()
{
//Stuff..
};
Is it somehow possible to override its OnPaint inside the operating method or at least in the same class?
This is my current solution:
public partial class ModelBuilder : Form
{
public partial class ModelBuilderSAS : Form
{
protected override void OnPaint(PaintEventArgs e)
{
//Do Stuff Before OnPaint..
base.OnPaint(e);
}
}
}
But it's not so practical since there are at least 10 sub-forms in each of my primary forms.
Addition: The reason for overriding the OnPaint instead of just handling the event is that i want to perform some actions first then continue with the OnPaint
We are using asp .Net with C#. I have page(.aspx) consist of multiple Web User Controls(.ascx)
I would like to have an error handling machanism in such a way that if there is any exception in one of the user control, asp .net should show some friendly error message on a control. All other control should render as expected.
Is there any way this can be done without putting place holder on each control which you show/hide in case of exception?
You could do something like this.
An abstract base class with an abstract OnLoad() that each UserControl has to implement. You can use this same model for any event that you want to have shared error handling.
public abstract class BaseUserControl : UserControl
{
protected void Page_Load(object sender, EventArgs e)
{
try
{
OnLoad();
}
catch (Exception)
{
//Custom error handling here
}
}
protected abstract void OnLoad();
}
public class MyUserControl: BaseUserControl
{
protected override void OnLoad()
{
//My normal load event handling here
}
}
1) In app_code, create a class MyPage.cs that inherits Page
class MyPage : Page { }
2) Change the inherits of your pages to MyPage.
public partial class _Default : MyPage { ...
There's an attribute in the web.config you can use to change it if you want
3) Back to MyPage.cs, add the generic error handler of all pages
protected override void OnError(EventArgs e)
{
/* here you can intercept the error and show the controls that you want */
base.OnError(e);
}
First create a base user controlclass which overrides default onerror event.
public class MyControlClass:UserControl
{
protected override void OnError(EventArgs e)
{
//here you sould add your friendly msg implementation
//base.OnError(e); here should remain commented
}
}
Then you can create your user controls:
public class Control1:MyControlClass
{
// ....
// ....
}
So, if any control creates an exception , the rest will keep on working.
I have a base class and a derived class .
The base class has a simple button with a virtual protected button click method.
I am using the ovverride keyword (not using new as i want the buttonclick method in the derived class to override the base class buttonclick method)
However , the code inside the derived class buttonclick method executes twice instead of once
Here is the code example
In the Base Class:
this.ok.Click += new System.EventHandler(this.ok_Click);
protected virtual void ok_Click(object sender, EventArgs e)
{
MessageBox.Show("From the Base class");
}
In the Derived Class:
this.ok.Click += new System.EventHandler(this.ok_Click);
protected override void ok_Click(object sender, EventArgs e)
{
MessageBox.Show("From the Derived class");
}
You haven't said what's actually calling the buttonclick method, but I suspect it's an event handler... and I suspect you're subscribing to it in both the subclass and base class constructors. Don't do that - you only need to subscribe once.
(If that's not the case, please show a short but complete example.)
Is it the wrong way I am doing this:
- first I created a class inheriting from Combobox and I am gonna override some events, so something like this:
public override void SelectedIndexChanged(object sender, EventArgs e)
but it tells me : "There is no suitable method for override"
Thanks
You should override the method OnSelectedIndexChanged instead. The On[EventName] methods are the ones that raises the events. What you should do is to override that method, do the extra things you want to do and then call base.OnSelectedIndexChanged(e) when you want to raise the event:
protected override void OnSelectedIndexChanged(EventArgs e)
{
// do extra stuff here
base.OnSelectedIndexChanged(e);
// perhaps you want to do something after the event
// handlers have been invoked as well
}
You cannot override events. Instead you will find a method called OnSelectedIndexChanged, override this.