Overriding new sub form's event - c#

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

Related

For which purpose the events pattern declares the event firerer method as virtual?

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.

Web forms prevent Page_Load event in control when inside placeholder that visible false

i need to prevent UserControl Page_Load event in case the control placed inside PlaceHolder that Visible property set to false.
I have some base class that all my user control derived from, and this class derived from UserControl class.
I found this : How to stop the execution of UC at page load on Visible false
The answer was to use "this.Visible" inside the Page_Load event handler
Or to override OnPreRender method and use it instead of the Page_Load.
I need some way to solve this problem inside my BaseControl,
in order to avoid multiple code changes.
Is it possible?
Thanks in advance!
Finally i found a solution:
public abstract class BaseClass : UserControl
{
protected override void OnLoad(EventArgs e)
{
if (this.Visible)
{
base.OnLoad(e);
}
}
}
public partial class WebUserControl1 : BaseClass
{
protected void Page_Load(object sender, EventArgs e)
{
// running only if this.Visible = true
}
}
There is nothing you can do to circumvent the execution of Page_Load. This event will be raised regardless because it is part of the page life cycle. What you can do however, is to conditionally execute any heavy logic based on this.Visible.
If you want to check visibility of a child control from a base class, and then conditionally handle additional shared logic there (whatever that may be), you can do something like this:
// DerivedChildControlA.ascx
<uc1:ChildControl runat="server" ID="someChildControlID" />
public abstract class BaseControl : UserControl
{
protected abstract ChildControl DerivedChild { get; }
}
public class DerivedChildControlA : BaseControl
{
protected override ChildControl DerivedChild
{
get { return this.someChildControlID; }
}
}
Once you obtain the reference to that child, you can check its visibility and perform desired actions in the base class.
For example, what I normally do for all my UserControls is put the main loading logic in a separate method called Load(). Then I call this method from the parent. The thing is, you can conditionally call Load() which gives you more control. In your instance, you can call Load() from the parent base class depending on the child control's visibility.
EDIT:
There may be a way by removing the child control from the page's child control collection, but this feels like a hack. For additional info check out the comment by Aterra on ASP.NET Forums.
You could load the User Controls dynamically. Then you won't have the problem of them being loaded even though they are not visible. So on the aspx page you can do this:
if (showControl == true)
{
//create an instance of the user control
WebUserControl1 control1 = (WebUserControl1)LoadControl("~/WebUserControl1.ascx");
//add it to the page when needed
PlaceHolder1.Controls.Add(control1);
}
The only downside is that the Control will be gone after each PostBack, so you will have to keep track if the Control was shown somewhere and recreate it if needed.
Another thing you can do is leave the Page_Load of the User Control empty and create a Method that you call from the parent page.
User Control
protected void Page_Load(object sender, EventArgs e)
{
//empty
}
public void doStuffInUserControl()
{
Label1.Text = "Called from parent!";
}
Parent aspx page
protected void Page_Load(object sender, EventArgs e)
{
someChildControlID.doStuffInUserControl();
}

Override an override of onLoad(e), but call the lowest base implementation

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.

.net default event handler

In my product I need process wide events. For that I used code like this:
public class Global
{
public static event EventHandler<MyEventArgs> Message;
public static void ShowMessage();
}
Now let's say I have a WinForms user interface. In form's code I will subscribe to this event and handle it in some default way (eg. by using System.Windows.Forms.MessageBox.Show() method). Now the question is how do I allow user to create derived form and override my default Message event handler implementation?
Just subscribing to the event for the second time with custom implementation doesn't solve the problem (both event handlers would be executed and potentially two message boxes shown). The options I see are either:
//call OnSubscribeToMessageEvent() from either form's constructor or OnLoad event handler
protected virtual void OnSubscribeToMessageEvent()
{
Global.Message += new EventHandler<MyEventArgs>(Global_Message);
}
private void Global_Message(object sender, MyEventArgs e)
{
//my default implementation
}
or
//subscribe in either form's constructor or OnLoad event handler
protected virtual void Global_Message(object sender, MyEventArgs e)
{
//my default implementation
}
Which version is better and why? Or maybe there are any other options?
I still have some doubts as I have never seen such a design pattern in any .NET library
Yes, you're right to worry about this. These kind of event subscriptions are very fickle, the event source always outlives the subscriber. There's only one class in the framework I know that does this, SystemEvents. The problem is that every subscriber has to very carefully unsubscribe itself when its lifetime ends or the object will stay referenced forever. A memory leak that's very hard to diagnose.
A better pattern here is to use an interface. Let's declare one:
public class MyEventArgs { /* etc.. */ }
public interface IGlobalNotification {
event EventHandler Disposed;
void OnMessage(MyEventArgs arg);
}
Now you can have a form implement the interface:
public partial class Form1 : Form, IGlobalNotification {
public Form1() {
InitializeComponent();
GlobalMessages.Register(this);
}
void IGlobalNotification.OnMessage(MyEventArgs arg) {
// do something
}
}
The Register method registers the form with the GlobalMessages class, the Dispose event ensures that the class can detect that the form is dying:
public static class GlobalMessages {
public static void Register(IGlobalNotification listener) {
listener.Disposed += delegate { listeners.Remove(listener); };
listeners.Add(listener);
}
public static void Notify(MyEventArgs arg) {
foreach (var listener in listeners) listener.OnMessage(arg);
}
private static List<IGlobalNotification> listeners = new List<IGlobalNotification>();
}
Call GlobalMessages.Notify() to get the OnMessage() method to run in all live form instances. The major advantage of this approach is that a client programmer can never screw up.
I would let the derived class override the Global_Message. The subscription to the event is generic and why would you want to implement it in every child again? It also gives you the option to call base.Global_Message(sender, e) in case your child class just wants to add some decoration to it and use the default behaviour otherwise.
I would prefer your second example, as that way, classes that extend your base class only have to override one method and do not have to remove the handler added by the base class from the event.
The key is adding the virtual keyword, so that a derived type can overide the method and the method they created will be called instead.
//subscribe in either form's constructor or OnLoad event handler
protected virtual void Global_Message(object sender, MyEventArgs e)
{
//my default implementation
}
Now that you've added virtual to both, I'd go with the first and override the one that subscribes to the event, if they didn't want the event subscribed to.
Though there is another option, call it #3.
protected EventHandler GlobalMessageEvent = new EventHandler<MyEventArgs>(Global_Message);
protected virtual void OnSubscribeToMessageEvent()
{
// this could be done in the Form_Load() or constructor instead.
Global.Message += GlobalMessageEvent;
}
Then potentially an inherited class could do somewhere: (note the -=)
{
Global.Message -= GlobalMessageEvent;
}

How to call an EventHandler in a parent class

I have added an EventHandler for the Click-event to a picturebox but on runtime this handler is never called (the debugger shows me that it is added to the control directly but when I click on the picturebox nothing happens).
I assume it has something to do with my inheritance. I have a usercontrol called AbstractPage (its not really abstract since the designer doesnt like that) which only consists of a heading and this picturebox but it provides quite some functions the actual pages rely on.
#region Constructor
public AbstractPage()
{
InitializeComponent();
lblHeading.Text = PageName;
picLock.Click += new EventHandler(picLock_Click);
}
#endregion
#region Events
void picLock_Click(object sender, EventArgs e)
{
...do some stuff
}
#endregion
The page implementations just inherit this class and add their controls and behavior. We recently figured out that subclassing UserControl is not performant and we lose some performance there, but its the best way to do it (I dont want to c&p function for 25 pages and maintain them).
My pageA looks like this
public partial class PageA : AbstractPage
{
#region Constructor
public PageA()
{
// I dont call the base explicitely since it is the
// standard constructor and this always calls the base
InitializeComponent();
}
#endregion
public override string PageName
{
get { return "A"; }
}
public override void BindData(BindingSource dataToBind)
{
...
}
Anyway, the picLock_Click is never called and I dont know why?
The pages are all put into a PageControl which consists of a TreeView and a TabContainer where the pages are put once I call addPage(IPage)
public partial class PageControl {
...
protected virtual void AddPages()
{
AddPage(new PageA());
AddPage(new PageD());
AddPage(new PageC());
...
}
protected void AddPage(IPage page)
{
put pagename to treeview and enable selection handling
add page to the tabcontainer
}
Thanks in advance
If I understand your problem correctly, this worked for me out of the box (using VS2k8). My code:
public partial class BaseUserControl : UserControl
{
public BaseUserControl()
{
InitializeComponent(); //event hooked here
}
private void showMsgBox_Click(object sender, EventArgs e)
{
MessageBox.Show("Button clicked");
}
}
public partial class TestUserControl : BaseUserControl
{
public TestUserControl()
{
InitializeComponent();
}
}
I moved the TestUserControl to a form, clicked the button and got the message box as expected. Can you paste some more code, e.g. how do you use your AbstractPage?
I found the problem. We are using the Infragistics WinForms but in that case I used the standard picturebox. I replaced it with the UltraPictureBox and now it works.

Categories