Totally form Disposing and free up memory - vb.net

I already read a ton of topics "class disposing" about and I did understand how to do it and it works fine! Meanwhile "form disposind" is not same and resources still leaking!
What I am doing:
Initializing form by "using" method:
Using f as New Form
f.ShowDialog()
'my code
End using
In this case by "end using" form terminated with "Dispose" method.
For example:
I have a form which have a class (it contain parameters and other classes).
On initialization form event, form (itself) take 12Mb of memory (I measure it in process explorer) and plus my class take 10Mb (which Disposable and also disposing before Dispose form on Dispose event). After my form disposed (I measure it again) I see my class disposed and resources (of class) are free totaly, the form is not freeing resources. In other words I kill 10Mb (of class) BUT DON'T kill 12Mb (of form).
My Dispose code:
Private Sub Form_Disposed(sender As Object, e As EventArgs) Handles
Me.Disposed
If Not fDisposed Then
MyPersonalClass.Dispose()'class
MyPersonalClass = Nothing
fDisposed = True
GC.SuppressFinalize(Me)
GC.Collect()
Finalize()
End If
End Sub
It's very bad. If most of time I working with these forms and if they are don't free resources after dispose, each opened form will be leave approx 10-12Mb in memory after closed. And if I open my form 100 times it will freezes more then 1Gb of memory.
What I doing wrong?

I'm not really familiar with VB, but I think it will do things similar as to how they are done using winforms for C#
The easiest way to make sure that all Disposable objects of A Form are disposed when the form is disposed, to keep a collection of Disposable objects. You could use the existing class Sytem.ComponentModel.Component class for this. The disadvantage is that it only accepts objects that implement interface IComponent. If you have only a few classes that must be disposed that don't have this interface yet, this is the easiest method. Otherwise design your own DisposableCollection
class DisposableCollection : List<object>, IDisposable
{
public bool IsDisposed {get, private set} = false;
private IEnumerable<IDisposable> DisposableItems => this.OfType<IDisposable>();
public void Dispose()
{
if (!this.IsDisposed)
{
// Dispose all disposable items
foreach (IDisposable disposableItem in this.DisposableItems)
{
disposableItem.Dispose();
}
this.disposed = true;
}
}
}
Usage:
class MyForm : Form
{
private readonly DisposableCollection disposables = new DisposableCollection();
public MyForm()
{
// create and add all your items to disposables
}
protected override void OnDisposing(bool disposing)
{
this.disposables.Dispose();
}
}
If desired you can add event handlers to notify others that the object is being disposed

Related

C# to VB6 COM events (“object or class does not support the set of events”), but different

I am aware of a 10 year old question with the same title as this one but I have double checked and I am not mistakenly using the delegate name. This is a different issue.
Here at work we have an old VB6 application I need to teach new(er) tricks. The first thing I had to do was have it call methods from a .Net COM-visible DLL written in C#. I have that working. Now I need to have it handle incoming progress notification events from that same DLL. I asked a similar question yesterday wherein the VB6 IDE was not even seeing that the DLL had events to offer. That issue was solved by decorating the C# interfaces and classes correctly.
First, the C# codez:
namespace NewTricksDLL
{
[ComVisible(true)]
[Guid("16fb3de9-3ffd-4efa-ab9b-0f4117259c75")]
[InterfaceType(ComInterfaceType.InterfaceIsIDispatch)]
public interface ITransfer
{
[DispId(2)]
string SendAnEvent();
}
[ComVisible(true)]
[Guid("16fb3de9-3ffd-4efa-ab9b-0f4117259c74")]
[InterfaceType(ComInterfaceType.InterfaceIsIDispatch)]
public interface IManagedEventsToCOM
{
[DispId(2)]
void NotificationEvent();
}
[ComVisible(true)]
[Guid("dcf177ab-24a7-4145-b7cf-fa06e892ef21")]
[ComSourceInterfaces(typeof(IManagedEventsToCOM))]
[ProgId("ADUTransferCS.NewTricks")]
public class NewTricks : ITransfer
{
public delegate void NotificationEventHandler();
public event NotificationEventHandler NotifificationEvent;
public string SendAnEvent()
{
if (NotifificationEvent != null)
NotifificationEvent();
}
}
}
An now my attempt to use it in VB6. Please note that the _tricky_NotificationEvent event handler was generated by the IDE by picking _tricky from the left-hand dropdown and NotificationEvent from the right-hand dropdown so I know this event is visible to the VB6 IDE.
Option Explicit
Public WithEvents _tricky As NewTricksDLL.NewTricks
Private Sub Command1_Click()
' The next line fails with 'Object or class does not support the set of events'
Set _tricky = CreateObject("NewTricksDLL.NewTricks")
' Execution never makes to the next line
_tricky.SendAnEvent()
End Sub
Private Sub _tricky_NotificationEvent()
' This handler was auto generated by the IDE
End Sub
Hopefully this can help - here's a minimal bare bones VB.net implementation of your requirements: COM interface consumable by VB6, one event, one method.
Option Explicit On
Option Strict On
<ComClass(newTricks.ClassId, newTricks.InterfaceId, newTricks.EventsId)>
Public Class newTricks
#Region "COM GUIDs"
' These GUIDs provide the COM identity for this class
' and its COM interfaces. If you change them, existing
' clients will no longer be able to access the class.
Public Const ClassId As String = "386d540d-f8b8-46e1-939d-7b69dd5eff0a"
Public Const InterfaceId As String = "78b4036e-86a0-4671-997d-da5a33bf026f"
Public Const EventsId As String = "7b0fa5b5-b45e-4db2-9282-c06e09852161"
#End Region
' A creatable COM class must have a Public Sub New()
' with no parameters, otherwise, the class will not be
' registered in the COM registry and cannot be created
' via CreateObject.
Public Sub New()
MyBase.New()
End Sub
Public Event NotificationEvent()
Public Sub SendAnEvent()
RaiseEvent NotificationEvent()
End Sub
End Class
This was created by starting a new project (Windows class library), delete from the project the Class1.vb that's automatically created, add a COM Class item renaming it to NewTricks. Then added the event declaration and the sub declaration and code; also added the Option statements. Built the project.
This was successfully used from this VB6 code. Clicking the button resulted in "Event fired" being written to the immediate window. This was successful with using both New and CreateObject methods of creating the reference to newTricks.
Option Explicit
Private WithEvents oTricks As NewTricksDll.newTricks
Private Sub Command1_Click()
Set oTricks = New NewTricksDll.newTricks
'Set oTricks = CreateObject("NewTricksDll.newTricks")
oTricks.SendAnEvent
End Sub
Private Sub oTricks_NotificationEvent()
Debug.Print "Event fired"
End Sub
Here is the corresponding C# code for the VB.net code, as converted straight-up by https://converter.telerik.com/
using Microsoft.VisualBasic;
[ComClass(newTricks.ClassId, newTricks.InterfaceId, newTricks.EventsId)]
public class newTricks
{
// These GUIDs provide the COM identity for this class
// and its COM interfaces. If you change them, existing
// clients will no longer be able to access the class.
public const string ClassId = "386d540d-f8b8-46e1-939d-7b69dd5eff0a";
public const string InterfaceId = "78b4036e-86a0-4671-997d-da5a33bf026f";
public const string EventsId = "7b0fa5b5-b45e-4db2-9282-c06e09852161";
// A creatable COM class must have a Public Sub New()
// with no parameters, otherwise, the class will not be
// registered in the COM registry and cannot be created
// via CreateObject.
public newTricks() : base()
{
}
public event NotificationEventEventHandler NotificationEvent;
public delegate void NotificationEventEventHandler();
public void SendAnEvent()
{
NotificationEvent?.Invoke();
}
}
I have not tried this C# code.
If you use CreateObject, it creates an object of type Object I believe. You should create the object simply by using New:
Set _tricky = New NewTricksDLL.NewTricks
Since you declared the variable as WithEvents, you can't just declare it using As New NewTricksDLL.NewTricks which I imagine you probably tried.

VB.NET Handle event from one class in another without them knowing eachother...?

I have an application.
Module1 - Main application
DataAccessMananger - Class in main application to handle data
Configuration - Class in a different project (common dll) that handles configuration settings.
The problem / Question. How can the Configuration class handle a data changed event in the DataAccessMananger without it knowing what a DataAccessManager is since they are in different classes?
The only way I can think of making it work is to have Module 1 handle the event from the DataAccessMananger and have it call a method in the Configuration class, however I dont like this, I would rather Configuration be able to handle its own data updates...
Clear as mud? Any ideas? VB.NET 4.5, and I know a bit about delegates, but not sure how I could use them here, they must be the answer some how...
Ideally, I would like to be able to pass an "Event" to the config class from the DAM class using the module...
The best way I can think of would be to add an interface in the configuration class (common.dll) that would be implemented by the DataAccessMananger. I assume the mainmodule is aware of both the DataAccessMananger and the Configuration, right ? If so, the following might be a solution.
Add an interface to common.dll for the Configuration class to use (not implement) that contains the event to be managed. For instance:
Public Interface IConfiguration
Event ConfigChanged(sender As Object, e As configPropertyChanged)
End Interface
In my case, I also create a class inheriting Event args.
Public class configPropertyChanged
Inherits EventArgs
Public Property PropertyName() As string
Public Property NewValue() As String
Public Property OldValue() As String
Public sub New(Newvalue as string,OldValue as string,<CallerMemberName()> optional PropertyName as string = "")
Me.NewValue = Newvalue
Me.OldValue =OldValue
Me.PropertyName = PropertyName
End sub
End Class
The configuration class is then modified to be able to monitor any class (which means that in the main module, the configuration must be made aware of the DataAccessManager class (Notice Idisposable is implemented to cleanup).
Public Class Configuration
Implements IDisposable
Private _ConfigList As New List(Of IConfiguration)
Public Sub RegisterConfig(Config As IConfiguration)
_ConfigList.Add(Config)
AddHandler Config.ConfigChanged, AddressOf ConfigChanged
End Sub
Public Sub ConfigChanged(sender As Object, e As configPropertyChanged)
Console.WriteLine("Config has changed.")
End Sub
#Region "IDisposable Support"
Private disposedValue As Boolean ' To detect redundant calls
Public Sub Dispose() Implements IDisposable.Dispose
For Each config As IConfiguration In _ConfigList
RemoveHandler config.ConfigChanged, AddressOf ConfigChanged
Next
_ConfigList.clear()
End Sub
#End Region
End Class
DataAccessManager does implement the Iconfiguration interface (available from common.dll)
Public Class DataAccessMananger
Implements IConfiguration
Public Event ConfigChanged(sender As Object, e As configPropertyChanged) Implements IConfiguration.ConfigChanged
Private _Name As String
Public Property Name() As String
Get
Return _Name
End Get
Set(value As String)
If String.Compare(_Name, value, True) <> 0 Then
RaiseEvent ConfigChanged(Me, New configPropertyChanged(Value,_Name))
_Name = value
End If
End Set
End Property
End Class
Finally, the main module, which is the only one to be aware of the existence of both Configuration and DataAccessManager, register the DataAccessManager into the configuration.
Public Sub Main()
Dim MyManager As New DataAccessMananger
Dim MyConfig As New Configuration
MyConfig.RegisterConfig(MyManager)
MyManager.Name = "New name"
End Sub
In this scenario.
The main module load the configuration and the data access manager at some point and then, register the data access manager into the configuration object. It can also register any other class implementing the Iconfiguration process.
At some point, something triggers a raise event into the data access manager (In my example, changing the property name do exactly that). The data access manager raise the event, which the configuration object handles it since we registered the data class into the configuration object.
If you wanted, you could have skipped the interface entirely and just had the DataAccessManager raise an event to the main module, then in the main module event handler, call a public method from the configuration class.

Use of static local variables in lazy loading property in VB.NET

I just recently learned about the uses of static local variables in VB.NET and wondered about it's potential use in lazy loading properties.
Consider the following example code.
Public Class Foo
Implements IFoo
End Class
Public Interface IFoo
End Interface
Public Class Bar
Private _fooImplementation As IFoo
Public ReadOnly Property FooImplementation As IFoo
Get
If _fooImplementation Is Nothing Then _fooImplementation = New Foo
Return _fooImplementation
End Get
End Property
End Class
This would be a usual, simplified lazy-loading property. You may even want to use the generic Lazy Class to get (as far as i know) the same behaviour.
Now, let's look at the property while using a static variable.
Public Class Bar
Public ReadOnly Property FooImplementation As IFoo
Get
Static _fooImplementation as IFoo = New Foo
Return _fooImplementation
End Get
End Property
End Class
As far as i can see, this has a few advantages over the usual implementation, primary your inability to access the variable outside of the property, as well as not having to use an additional variable.
My question to you is: Which of those is the "right" way to do it? I know that static variables have additional overhead, but is it bad enough to create, in my personal opinion, unclearer code that can be misused easier? How much performance do you lose compared to the "traditional" method? How does it matter for small classes compared to huge factories?
Thanks in advance.
The Static keyword has rather a lot of overhead, the compiler generates a big chunk of IL to implement it. What it does do that your 1st snippet doesn't do is ensure that threading doesn't cause problems. If that is not a concern then your 1st snippet is a lot cheaper. Not just because it has a lot less IL but also because it will be inlined. A getter with Static will never be inlined since it contains Try/Finally code.
If you are targeting .NET 4 then you definitely should take a look at the Lazy(Of T) class.
That question was interesting enough for me to find the answer...how exactly does VB.NET implement static. Here's a C# equivilent:
public class Bar
{
[SpecialName]
private IFoo \u0024STATIC\u0024get_FooImplementation\u0024200122C\u0024_fooImplementation;
[SpecialName]
private StaticLocalInitFlag \u0024STATIC\u0024get_FooImplementation\u0024200122C\u0024_fooImplementation\u0024Init;
public IFoo FooImplementation
{
get
{
Monitor.Enter((object) this.\u0024STATIC\u0024get_FooImplementation\u0024200122C\u0024_fooImplementation\u0024Init);
try
{
if ((int) this.\u0024STATIC\u0024get_FooImplementation\u0024200122C\u0024_fooImplementation\u0024Init.State == 0)
{
this.\u0024STATIC\u0024get_FooImplementation\u0024200122C\u0024_fooImplementation\u0024Init.State = (short) 2;
this.\u0024STATIC\u0024get_FooImplementation\u0024200122C\u0024_fooImplementation = (IFoo) new Foo();
}
else if ((int) this.\u0024STATIC\u0024get_FooImplementation\u0024200122C\u0024_fooImplementation\u0024Init.State == 2)
throw new IncompleteInitialization();
}
finally
{
this.\u0024STATIC\u0024get_FooImplementation\u0024200122C\u0024_fooImplementation\u0024Init.State = (short) 1;
Monitor.Exit((object) this.\u0024STATIC\u0024get_FooImplementation\u0024200122C\u0024_fooImplementation\u0024Init);
}
return this.\u0024STATIC\u0024get_FooImplementation\u0024200122C\u0024_fooImplementation;
}
}
[DebuggerNonUserCode]
public Bar()
{
this.\u0024STATIC\u0024get_FooImplementation\u0024200122C\u0024_fooImplementation\u0024Init = new StaticLocalInitFlag();
}
}

Setting the DataContext on an Entity instance after it's retrieved

I'm trying to find a way to have the DataContext available from within Entities.
I want to do something like this:
partial public class MyEntity
public DataContext as MyDataContext
private sub OnLoaded()
Me.DataContext = <the context that retrieved this instance>
end sub
end class
First, can something like this be done?
Second, assuming that I'm not going to use this entity with any other DataContext, is there any dangers or gotchas in doing such a thing?
This is the way I do it currently:
partial public class MyDataContext
public function GetMyEntity(byval id as integer) as MyEntity
dim o = MyEntities.SingleOrDefault(function(e) e.id = id)
if o isnot nothing then o.DataContext = Me
return o
end function
end class
Although you didn't specify a real reason for it, just a sidenote from MSDN:
In general, a DataContext instance is
designed to last for one "unit of
work" however your application defines
that term. A DataContext is
lightweight and is not expensive to
create. A typical LINQ to SQL
application creates DataContext
instances at method scope or as a
member of short-lived classes that
represent a logical set of related
database operations.
and one more:
Do not try to reuse instances of
DataContext. Each DataContext
maintains state (including an identity
cache) for one particular edit/query
session. To obtain new instances based
on the current state of the database,
use a new DataContext.
and finally,
... Any instance members are not
guaranteed to be thread safe.
But still in some cases semi-persistent solutions could be very helpful. Take a look onto Rick Strachl's article: Linq to SQL DataContext Lifetime Management. There are different approaches of DataContext management is reviewed in it. On of them - Create a per business object DataContext is exactly what you need.
You could use a singleton pattern on the DataContext, but you will need some kind of lifetime management on it, as it is not good to keep it around to long. (request ends dispose it maybe)
Example in C#, but I hope you can understand it.
public class MyDataContext
{
public static MyDataContext Current
{
get
{
MyDataContext context = (MyDataContext)HttpContext.Current.Items["Context"];
if(context == null)
{
context = new MyDataContext();
HttpContext.Current.Items["Context"] = context;
}
return context;
}
}
}
public class MyEntity
{
public MyDataContext DataContext
{
get{ return MyDataContext.Current;}
}
}
In Global.asax you can hook up the event Application_EndRequest and call MyDataContext.Current.Dispose(); to dispose of the context manually instead of waiting for the GC to do it.

EventAggregation quick start?

I am created a MainView that it's DataContext is a MainViewModel initialized in xaml.
The MainView contains a ContentControl that is bound to the Content property of the MainViewModel.
I added some content in the MainViewModel constructor, so that if the current user is not logged in, it automatucally loads LoginView (and correspondingly it's DataContext LoginViewModel) into this Content property.
Now my question is, what should I do when the user successfully logs in:
'To be called from the LoginCommand
Private Sub Login
'Do Login
If WebContext.Current.User.IsAuthenticated Then
' - Publish a global event to be subscribed and caught from the MainViewModel
' - Close LoginView
' - The MainViewModel should set it's Content property back
' to what the user initially intended to open
End If
End Sub
How is this done?
Note: I prefer using prism's EventAggregator rathen then other stuff, but I have no clue:
How to spread it out between the ViewModels
How to create events (I don't need to pass parameter, nor do I need it to be generic, just Action, LoginAction - no parameters.
How do I subscribe from the MainViewMode.
I do NOT use MEF or Unity, nor do I use seperated modules, all my application is in one single assembly.
I prefer not to write any code in the code-behind at all
Answer in both VB.NET or C# are welcommed the same
Any help would be recommended
You can go here for info regarding the EventAggregator.
You could also use the following code to create an instance of the EventAggregator without using MEF or Unity:
internal static class EventAggregatorHelper
{
private static IEventAggregator _Current = new EventAggregator();
public static IEventAggregator Current
{
get
{
return _Current;
}
}
}
And you could then call the EventAggregator like so passing in the required information to the aggregator:
EventAggregatorHelper.Current.GetEvent<SelectedItemChangedEvent>().
Subscribe(HandleSelectedItemChangedEvent);
In this case the SelectedItemChangedEvent and the subscriber that deals with this event.
The SelectedItemChangedEvent is a class declared as shown below:
public class SelectedItemChangedEvent : CompositePresentationEvent<String>
{
}
and the subscriber would be something like this:
internal void HandleSelectedItemChangedEvent(string viewName)
{
if (!String.IsNullOrEmpty(viewName))
{
//Do whatever you need to do here.
}
}
The link to the Event Aggregator I posted at the start should clear most things up for you.
Hope this helps.