Event handler memory leak using ChildWindows - c#

I just want to ensure that the code below will not be causing the ChildWindow Login in this case to never be collected by the GC. Just to clarify the sample this comes from a silverlight page that is inherited by all other pages therefore the virtual void pageloaded method.
public class MyPage : Page
{
// Executes when the user navigates to this page.
protected override void OnNavigatedTo(NavigationEventArgs e)
{
_user = App.AuthenticatedUser;
if (!_user.IsValid)
{
Login loginWindow = new Login(_user);
loginWindow.Closed += new EventHandler(PageLoaded);
loginWindow.Show();
}
else
PageLoaded(this, e);
}
//to be overridden by the pages extending this page control
protected virtual void PageLoaded(object sender, EventArgs e) { }
Thanks for your help.

This is fine. The loginWindows's Close event knows of your handler, not the other way around, so the form will not have any ties preventing the GC from picking it up.
Unregistering event handlers becomes important if the object your event is defined on will persist in the application for a long time (and you do not want the event handler association to persist for the same duration).

Related

Implement destructor/dispose in code behind

I use asp net 4.5.
I have Marker.aspx page and code behind page Marker.aspx.cs.
Whenever postback occurred Page_Load function is fired in code behind and GeoMarkup class created.
GeoMarkup markupManager;
protected void Page_Load(object sender, EventArgs e)
{
markupManager = new GeoMarkup("constans",
"mapName",
null);
}
Whenever postback is implemented I need destructor to be fired and put inside destructor this row:
markupManager.Dispose();
My question is how can I implement destructor in code behind?;
Your code behind class is a subclass of Page which has a virtual Dispose method.
You should override that method in your code behind
public override void Dispose()
{
if (markupManager != null) {
markupManager.Dispose();
markupManager = null;
}
}
The HTTP pipeline will call Dispose on classes when they are no longer needed for the processing of the current HTTP request.

How to stop my WPF usercontrol from loading, if i have basecontrol

I have a BaseControl, of which almost all my controls inherit from.
Right now I am working on security and I want to block users from viewing certain items if they do not have access.
I am able to do so on the Loaded event of the base control, but this is too late, this meanse the whole control gets rendered, and then replaced. I would like to replace it before it renders
here is an example of my code:
public class BaseControl : UserControl
{
public BaseControl()
{
this.Loaded +=BaseControl_Loaded;
}
private void BaseControl_Loaded(object sender, RoutedEventArgs e)
{
if (!userHasAccess)
{
this.Content = new AccessDenied();
}
}
}
The above code works perfectly, but a bit too late, Is there a way that I can do this before the Loaded event?
You want to override the OnInitialized where the constructor and properties are being set up before the Render happens.
protected override void OnInitialized(EventArgs e)
{
if (!userHasAccess)
{
this.Content = new AccessDenied();
}
base.OnInitialized(e);
}
More information can be found here.
Check out following sites:
http://msdn.microsoft.com/en-us/library/ms745025(v=vs.110).aspx
Also check object lifetime events that is what you asking for.
http://msdn.microsoft.com/en-us/library/ms754221(v=vs.110).aspx

Postback delegate is null

I am building server control with custom events and as example used this MSDN reference.But events are never fired while postback - clickEventDelegate is always null:
if (clickEventDelegate != null)
{
clickEventDelegate(this, e);
}
Here is how I add delegate:
if (!Page.IsPostBack)
{
.....
MYCONTROL.LeftClick+= FUNCTION;
}
Any ideas?
You did not post enough of your code to find out why your event is null. But I am gonna list the standard pattern.
This is how you define an argument class for your custom event:
public class MyEventArgs : EventArgs
{
private string MyField { get; private set; }
public MyEventArgs(string myField)
{
MyField = myField;
}
}
This is how you define a custom event:
public event EventHandler<MyEventArgs> MyEvent;
This is how you write an event raiser in the same class as the event:
protected virtual void OnMyEvent(MyEventArgs e)
{
EventHandler<MyEventArgs> myEvent = MyEvent; // for thread safety
if (myEvent != null)
{
myEvent(this, e);
}
}
This is how you raise the event in the class it is defined in (or a derived class):
OnMyEvent(new MyEventArgs("Test"));
This is how you react to the event in a derived class:
protected override void OnMyEvent(MyEventArgs e)
{
// TODO: Here you react to your event.
base.OnMyEvent(e);
}
This is how you register on the event in a foreign class:
otherClass.MyEvent += delegate(object sender, EventArgs e)
{
// TODO: Here you react to your event.
};
The other answer just explains how events work but is completely ignoring the main point of the question: Delegate is null during a postback
The answer was quite simple. Just subscribe to your event every times even during Postback, so you just had to remove your condition if (!Page.IsPostBack)
MYCONTROL.LeftClick+= FUNCTION;
I know this is a very old question and there is no way you are still searching for the answer. But when I read
You did not post enough of your code to find out why your event is
null
from the previous answer I couldn't let this wrong statement like this.
EDIT:
To add more explanations, every time the server returns the final page to be rendered in the browser it then looses the state of this particular connection. Imagine if the server should keep in memory all connections with their associated states, you have maybe thousands of users a day, and also when to "clean" this memory?
So no that won't be doable that's why they created the ViewState so the browser can send previous information to the server. However this ViewState can save values of some variables or objects but doesn't save the binding between an event and its delegate(s).
Back to concrete examples. If you do this
<asp:Button runat="server" ID="ButtonTest" OnClick="buttonTest_Click" Text="test" />
The subscription to the event is made internally by ASP.NET on a very early stage in the life cycle before you reach the page's Page_Load. You can read about the ASP.NET life cycle here
If you assign the event handler like this
<asp:Button runat="server" ID="ButtonTest" Text="test" />
and on your page's server side:
protected void Page_Load(object sender, EventArgs e)
{
ButtonTest.Click += ButtonTest_Click;
}
It will work the same except that the subscription is made a bit later.
But if instead you decorate it in a condition
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
ButtonTest.Click += ButtonTest_Click;
}
}
This won't work because the event handler has not been assigned. Remember that your server forgot the state of this particular connection and has to initialize everything at each HTTP POST request (PostBack).
This is exactly like in the sample code of your question, so as you can see events are working the same on native ASP.NET controls or custom ones you declared.

Do I need to unsubscribe from an event in a c# metro application?

I have subscribed various event in OnNavigatedTo like
protected override void OnNavigatedTo(NavigationEventArgs e)
{
Loaded += Screen_Loaded;
}
I haven't unsubscribed this event. Does it cause any memory issue when this page is not needed??
No. In this case you do not need to unsubscribe to avoid memory leaks. The reason is that you subscribe to an event on this. The garbage collector must identify this and free the object.
But, I would for other reasons still unsubscribe. For example having balanced resources makes the code easier to read. Also what if the OnNavigatedTo gets called twice? (Don't actually know if this can even happen) Then you'll have two subscriptions to the same method. Some would argue that unsubscribing in this scenario is redundant code and remove it. Although correct as such I would oppose such arguments.
You can try this short snippet to try it out yourself. Note: Never user finalizers or GC.Collect() except for learning about the GC like in this example.
public class Program
{
private class Foo
{
public event EventHandler FooChanged;
~Foo()
{
Console.WriteLine("Foo was collected");
}
public void Bar()
{
FooChanged += UpdateUI;
}
private void UpdateUI(object sender, EventArgs e)
{
}
}
public static void Main(string[] args)
{
var foo = new Foo();
foo.Bar();
foo = null;
GC.Collect();
GC.WaitForPendingFinalizers();
Console.WriteLine("End of program");
Console.ReadKey();
}
}
Yes you do have to unsubscribe from some event which might be automatically fired in a metro app
For Example :
Events such as
Window.Current.SizeChanged += Current_SizeChanged;
void Current_SizeChanged(object sender, Windows.UI.Core.WindowSizeChangedEventArgs e)
{
//your code block contining various objects and logic
}
These events are not controlled by you as they are fire in the background. Any event which might not be related to a particular page (suppose the above event is initilized in the OnNavigatedTo Event) then you have to unsubscribe from it in events like OnNavigatedFrom
For further clarification initialize this event
Window.Current.SizeChanged += Current_SizeChanged;
and just keep a break point and change the size of the window change from landscape to snapped mode and this event will fire unless you have not unsubscribed from the event.
Remember that:
You could accidentally subscribe to event several times (use -= to avoid this).
If event handler is a method from some other object, then that object will not be garbage collected until method is subscribed to an event.

Assign delegate event handler from dynamically added child control

I have a control that handles commenting. In this control, I have set a delegate event handler for sending an email.
I then have various types of controls, e.g. blog, articles etc, each of which may or may not have the commenting control added (which is done dynamically with me not knowing the id's), i.e. the commenting control is added outside this control. Each of these controls handles it's emailing differently(hence the event).
What I'm trying to determine, is how to assign the event in the parent control. At the moment, I'm having to recursively search through all the controls on the page until I find the comment control, and set it that way. Example below explains:
COMMENTING CONTROL
public delegate void Commenting_OnSendEmail();
public partial class Commenting : UserControl
{
public Commenting_OnSendEmail OnComment_SendEmail();
private void Page_Load(object sender, EventArgs e)
{
if(OnComment_SendEmail != null)
{
OnComment_SendEmail();
}
}
}
PARENT CONTROL
public partial class Blog : UserControl
{
private void Page_Load(object sender, EventArgs e)
{
Commenting comControl = (Commenting)this.FindControl<Commenting>(this);
if(comControl != null)
{
comCtrol.OnComment_SendEmail += new Commenting_OnSendMail(Blog_Comment_OnSendEmail);
}
}
}
Is there an easier way?
EDIT:
The reason I ask is that if I search from this.Page as the initial control, I am worried about time taken to search down the control tree to find it. Each different type of page would be different in how many control it would have. On some testing, it returns back quite quickly the result.
You could override the AddedControl event of your Blog class and check if the added control is instance of type Commenting. Something like:
public partial class Blog : UserControl {
protected override void AddedControl(Control control, int index) {
base.AddedControl(control, index);
Commenting commentingControl = control as Commenting;
if (commentingControl == null) return;
commentingControl.OnComment_SendEmail += new Commenting_OnSendMail(Blog_Comment_OnSendEmail);
}
}
Of course, you can put this code on a base class of all your "commentable" user controls and have an abstract method to actually handle the event.
Just one thing: the AddControl event happens AFTER the Page_Load, so be careful.
Cheers,
André

Categories

Resources