Why is my C# Singleton not working? - c#

Im new to .net and this is also my first post here so apologies in advance for any newb mistakes I may be doing:)
Background of the problem.
I’m working on a C# project and as part of it I have to store windows form data onto a database. I am using a data class “person” to transport the windows form data to a class responsible for accessing the database on the windows forms behalf. I wish to use the Singleton pattern on the windows forms code to prevent multiple instances of the window from existing.
Problem
In the save buttons event handling code I wish to create a “Person” object, populate it with user entered values and send it to be saved onto the database. The problem occurs here. The “Person” object does not get populated!
I’ve tried doing this in another form where I have not modified the code to accommodate the singleton pattern and that works.
So what am I doing wrong here? Is there a way for me to still keep the singleton pattern and make it work?
Window Form Code
namespace AgTrain
{
public partial class CreateAdmin : Form
{
private static CreateAdmin instance;
private CreateAdmin()
{
InitializeComponent();
}
private void CreateAdmin_Load(object sender, EventArgs e)
{
}
public static CreateAdmin getInstance()
{
if(instance==null)
{
instance = new CreateAdmin();
instance.InitializeComponent();
}
return instance;
}
public void makeInstanceNull()
{
instance = null;
}
private void button1_Click(object sender, EventArgs e)
{
Person personToBeSaved = new Person();
PersonDAO personDAO = new PersonDAO();
personToBeSaved.FirstName = textBox1.Text;
personToBeSaved.LastName = textBox2.Text;
personToBeSaved.Address = textBox3.Text;
personToBeSaved.TelNo = textBox4.Text;
personToBeSaved.UserName = textBox5.Text;
personToBeSaved.Password = textBox6.Text;
personToBeSaved.UserType = "admin";
personDAO.addPerson(personToBeSaved);
}
}
}
Caller Code
private void createAdminToolStripMenuItem_Click(object sender, EventArgs e)
{
CreateAdmin creAdmin = CreateAdmin.getInstance();
creAdmin.Closed += (s, ex) => { creAdmin.makeInstanceNull(); };
creAdmin.MdiParent=this;
creAdmin.Show();
}
Thanks.
Dumidu

You are calling InitializeComponent twice.
Try that:
private static CreateAdmin _instance;
public static CreateAdmin Instance
{
get { return _instance ?? (_instance = new CreateAdmin()); }
}

In my opionion is thefiloe's solution the cleanest, but there is a further possibility to introduce (effective) singletons in C#:
public static readonly CreateAdmin Instance = new CreateAdmin();
Client Code:
CreateAdmin.Instance.DoSomething()
But as already mentioned I recommend thefiloe's way!

Related

Call non static method from partial class

I have two forms in the same namespace.
One is the main form that displays the list of accounts.
public partial class Server : Form
{
public Server()
{
InitializeComponent();
LoadAcounts();
}
public void LoadAcounts()
{
AccountDB acc = new AccountDB();
userListBox.DataSource = acc.ListUsers();
this.userListBox.SelectedIndex = 0;
}
}
Second is the registration form.
public partial class RegForm : Form
{
public RegForm()
{
InitializeComponent();
passBox.Text = "";
passBox.PasswordChar = '*';
passBox.MaxLength = 14;
passBox2.Text = "";
passBox2.PasswordChar = '*';
passBox2.MaxLength = 14;
}
private void button1_Click(object sender, EventArgs e)
{
if (passBox.TextLength >= 4 && passBox.Text == passBox2.Text && usernameBox.TextLength >= 4)
{
AccountDB acc = new AccountDB();
if (acc.UserExist(usernameBox.Text))
{
MessageBox.Show("User already exists!");
}
else
{
string user = usernameBox.Text;
string pw = PasswordHash.HashPassword(passBox.Text);
WriteDB(user, pw);
this.Close();
MessageBox.Show("Registration successful!");
//LoadAccounts();
}
}
}
}
I am currently stuck on how can I call LoadAccounts() after Registration successful so the userListBox will be refreshed to include the newly added account.
I am not sure about your design, but you can create an instance property of the "Server" class in your "RegForm" class. BUT, I should say that is increasing class coupling and definitely is not a good pattern.
public partial class RegForm : Form
{
public Server serverFormInstance {get; set;}//must be filled from caller code
...
...
If you have only one instance of the Server form, you can make it as a singleton to be able to call the method.
public class Server : Form
{
static internal readonly Server Instance = new Server ();
private Server()
{
InitializeComponent();
LoadAcounts();
}
}
Or any singleton implementation you like.
So you'll change all access to Server by Server.Instance.
Now you can call:
Server.Instance.LoadAcounts();
But if you plan to allow several instances of Server, a registration method may be used but it requires more code of your project to think about that.
You can also read this:
Communicate between two windows forms in C#

WinForms REST API Server With Grapevine

I would like to add a REST API server to my WinForms application. I have chosen to use Grapveine for that purpose.
Here's my code:
namespace RestServerTest
{
public partial class Form1 : Form
{
private RestServer mServer;
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
mServer = new RestServer();
mServer.Start();
}
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
mServer.Stop();
mServer.Dispose();
}
}
[RestResource]
class MyRoute
{
[RestRoute]
public IHttpContext HelloWorld(IHttpContext context)
{
// Todo: how access form object from here?
context.Response.SendResponse("Hello, world.");
return context;
}
}
}
Currently I have no idea how to actually access my Form object from the REST route (without using an ugly global/static variable).
How would one do that elegantly?
If you want the current form (or any other object/variable in your project) to be accessible to your routes, you can take advantage of Dynamic Properties. Both the IRestServer and IHttpContext implement IDynamicProperties, which gives you two ways to accomplish your goal.
Add either of these to your Form1_Load() method.
Add a Reference On The Server
server.Properties.Add("CurrentForm", this);
Add a BeforeRouting Event Handler
server.Router.BeforeRouting += cxt =>
{
cxt.Properties.Add("CurrentForm", this);
};
Access a Property In a Route
In either case, you can access the property using the built in extensions methods:
// On the server
var form = context.Server.GetPropertyValueAs<Form1>("CurrentForm");
// On the context
var form = context.GetPropertyValueAs<Form1>("CurrentForm");

C# Multiple class events

Im making a program what connects to multiple 3th party systems. The connect with different formats so i created multiple classes to deal with them. I have now three 4 classes.
The MainForm is the first class. This is the basic windows form class with the user interface.
SDKCommunication is the second class.
VMS (this class handles the events given of by the 2th party system and activates methods on SDK COmmunication)
Events
Events Class
public class Events
{
public event EventHandler LoginStateChanged;
private bool loginstate;
public bool LogInState
{
get { return this.loginstate; }
set
{
this.loginstate = value;
if (this.LoginStateChanged != null)
this.LoginStateChanged(this, new EventArgs());
}
}
}
part of SDKCommunicatie class
Events events = new Events();
public void onLogon(string username, string directory, string system)
{
events.LogInState = false;
}
MainForm Class
SDKCommunicatie sdkcommunicatie = new SDKCommunicatie();
Events events = new Events();
public MainForm()
{
InitializeComponent();
events.LoginStateChanged += new EventHandler(events_LoginStateChanged);
}
void events_LoginStateChanged(object sender, EventArgs e)
{
log.Info("EventFired loginstateChanged");
}
When the LogInState Changes in the SDKCommunicatie class. There needs to be an event fired in the MainForm class. But sadly that doesn't work.
But when I change the loginstate in the mainform(with a buttonclick)(see code below) the event is fired. But that is not the intention i would like to have.
private void button1_Click(object sender, EventArgs e)
{
events.LogInState = true;
}
If my question isn't clear enough, please let me know.
VMS class Added as reply to #Astef
class VMS {
private static readonly log4net.ILog log = log4net.LogManager.GetLogger(typeof(MainForm));
GxUIProxyVB m_UIProxy = new GxUIProxyVB();
public string username2;
public string directory2;
public string Status;
public void initOmni()
{
m_UIProxy.CreateInstance();
m_UIProxy.OnLogon += new _IGxUIProxyVBEvents_OnLogonEventHandler(m_UIProxy_OnLogon);
m_UIProxy.OnLogoff += new _IGxUIProxyVBEvents_OnLogoffEventHandler(m_UIProxy_OnLogoff);
m_UIProxy.OnError += new _IGxUIProxyVBEvents_OnErrorEventHandler(m_UIProxy_OnError);
m_UIProxy.OnAlarmStatusEx2 += new _IGxUIProxyVBEvents_OnAlarmStatusEx2EventHandler(m_UIProxy_OnAlarmStatusEx2);
}
public void login(string username, string password, string directory)
{
username2 = username;
directory2 = directory;
initOmni();
m_UIProxy.LogOn(directory, username, password,false);
}
public void logOff()
{
m_UIProxy.LogOff();
}
void m_UIProxy_OnLogon()
{
SDKCommunicatie sdkcommunicatie = new SDKCommunicatie();
sdkcommunicatie.onLogon(username2, directory2, "Genetec Omnicast");
}
I have fixed this with deleting the following:
SDKCommunicatie sdkcommunicatie = new SDKCommunicatie();
And adding the following in the base of VMS:
SDKCommunicatie sdkcommunicatie;
But now i got a new error in the mainform when i tried to call a class in SDKCommunicatie
connectedStatus = sdkcommunicatie.connectedStatus();
I got the following error:
NullReferenceException was unhandled
You are not using the same instance of the Events class, and that's why on button click you catch LoginStateChanged. You should inject the same instance of Events class to SDKCommunicatie class, then you'll be able to listen to event changes.
Edit:
Jeremy Todd and I were both writing at the same time.
Events in your SDKCommunicatie are not fired because you've created an individual instance of class Events for it. That is not the instance you have placed on the MainForm.
Inject the right instance (pass a reference) to SDKCommunicatie from MainForm through constructor, property or somehow else. For example:
MainForm:
SDKCommunicatie sdkcommunicatie;
Events events = new Events();
public MainForm()
{
InitializeComponent();
events.LoginStateChanged += new EventHandler(events_LoginStateChanged);
sdkcommunicatie = new SDKCommunicatie(events);
}
void events_LoginStateChanged(object sender, EventArgs e)
{
log.Info("EventFired loginstateChanged");
}
SDKCommunicatie:
Events events;
public SDKCommunicatie(Envents eventsInstance)
{
events = eventsInstance;
}
public void onLogon(string username, string directory, string system)
{
events.LogInState = false;
}
Your SDKCommunication class and your MainForm class each have their own separate instance of Events, so any events you trigger from one won't be visible from the other -- they're being raised on an entirely different object.
What you need is a single instance of the Events class that both SDKCommunication and MainForm can share -- that way they'll both be seeing the same thing. There are several different approaches you could take for this. Depending on what it needs to do, one very simple possibility might be to make Events a static class, and then the events would be visible everywhere without needing to create any instances.
I have solved the riddle.
When i need a method is a class i can call the method directly like this:
public class MainForm : Form
{
SDKCommunication sdkcommunication = new SDKCommunication();
public MainForm()
{
}
private void Button1_Click(oject sender, EventArgs e)
{
sdkcommunication.method("Test")
}
}
This is pretty straightforward. Look here the receiverclass:
public class SDKCommunication
{
method(string word)
{
//do something with word
}
}
The biggest problem is calling the class with the form(the original class). I have solved this with a eventhandler.
class CustomEventHandler1 : EventArgs
{
public CustomEventHandler1(string u, string d)
{
msgu = u;
msgd = d;
}
private string msgu;
private string msgd;
public string Username
{
get { return msgu; }
}
public string Directory
{
get { return msgd; }
}
}
Then the SDKCOmmunication class should look like this:
class SDKCommunication
{
public event EventHandler<CustomEventHandler1> RaiseCustomEventHandler1;
protected virtual void OnRaiseCustomEventHandler1(CustomEventHandler1 e)
{
EventHandler<CustomEventHandler1> handler = RaiseCustomEventHandler1;
if (handler != null)
{
handler(this,e);
}
}
//Custom Method that is called somewhere
internal void custommethod()
{
OnRaiseCustomEventHandler1(new CustomEventHandler1("johnsmith", "localhost");
}
}
Then in the mainform class:
public class MainForm : Form
{
public MainForm()
{
sdkcommunication.RaiseCustomEventHandler1 += new EventHandler<CustomEventHandler1>(sdkcommunication_RaiseCustomEventHandler1);
}
void sdkcommunication_RaiseCustomEventHandler1(object sender, CustomEventHandler1 e)
{
//Do something.
}
}
The information sended with the event you can get with e.Username and e.Directory. In this example they are strings where e.Username = johnsmith and e.Directory = localhost.
I hope somebody can use this information for their own code.

c# - "NullReferenceException was unhandled" but List isn't null

I'm trying to get a ListBox (AlbumsListBox) to list everything in a List (AlbumList).
AlbumList and AlbumsListBox are both created on Form FormMain. A new Album (with Album.Name defined in NameTextBox.Text on FormAlbumAC) is created to go into AlbumList on Form FormAlbumAC.
From what I've seen, making the AlbumsList the datasource of the AlbumsListBox seems to be the right way to go. But I get the error "NullReferenceException was unhandled, object reference not set to instance of an object" when I run the program.
Ln 16 of the FormAlbumAC excerpt is where it occurs.
formMain.AlbumsListBox.DataSource = MusicCollection.FormMain.PublicVars.AlbumList;
I don't understand why this is happening, since the message box just before that point shows that AlbumList.Count = 1, so AblumList isn't null?
What am I doing wrong? Is this the right way to achieve what I want? How can I fix this? Any advice is appreciated, thank you.
Form FormAlbumAC:
private FormMain formMain;
public FormAlbumAC(FormMain callerInstance)
{
InitializeComponent();
formMain = callerInstance;
}
private void buttonSave_Click(object sender, EventArgs e)
{
if (MusicCollection.FormMain.PublicVars.AlbumList.Count != 100)
{
MusicCollection.FormMain.PublicVars.AlbumList.Add(new Album(NameTextBox.Text));
MessageBox.Show("New Album added: " + NameTextBox.Text);
MessageBox.Show(MusicCollection.FormMain.PublicVars.AlbumList.Count.ToString());
formMain.AlbumsListBox.DataSource = MusicCollection.FormMain.PublicVars.AlbumList;
this.Close();
}
else
{
MessageBox.Show("No room for new album.");
this.Close();
}
}
Form FormMain:
public const int MAX_ALBUMS = 100;
public FormMain()
{
InitializeComponent();
}
private void buttonAddAlbum_Click(object sender, EventArgs e)
{
FormAlbumAC addAlbumForm = new FormAlbumAC(this);
addAlbumForm.ShowDialog();
}
public static class PublicVars
{
public static List<Album> AlbumList { get; set; }
static PublicVars()
{
AlbumList = new List<Album>(MAX_ALBUMS);
}
}
public ListBox AlbumListBox
{
get
{
return AlbumListBox;
}
}
The local variable private FormMain formMain; has never been initialized.
And thus is NULL when you use it on the failing line.
You are trying to use the information stored statically in the class FormMain through an instance variable of type FormMain. But this variable is NULL and cannot access the data.
You could remove the error using
formMain = new FormMain();
formMain.AlbumsListBox.DataSource = MusicCollection.FormMain.PublicVars.AlbumList;
....
but at this point I think you will have other problems because this local instance of FormMain is not the same instance of the FormMain that, I suppose, has created the current instance of FormAlbumAC
If my assumption is correct, then you need to pass the instance of FormMain that creates FormAlbumAC inside the class.
private FormMain formMain;
public FormAlbumAC(FormMain callerInstance)
{
InitializeComponent();
formMain = callerInstance;
}
and then, somewhere in FormMain, when you construct the FormAlbumAC
....
FormAlbumAC album = new FormAlbumAC(this);
album.ShowDialog();
....

How can I get a class to "reset"?

I am writing a C#.NET application. I have a form. When the form is created I create an instance of a class. When I close the form, I want to dispose of the class so that the next time I open the form I can just create a fresh new instance of the class. So, in the form_Closing event I added code like this: classInstance = null; The problem is, for some reason, the next time I open the form the class is not equal to null but rather it is in the same state as it was right before I closed the form. Why is this happening?
EDIT: Adding Info:
myHandler is a field in the Form class.
it looks like this:
private HSFW_Handler myHandler;
The Class that I am referring to is a singleton so I create it like this:
public static HSFW_Handler GetInstance()
{
if (myHSFW == null)
{
myHSFW = new HSFW_Handler();
return myHSFW;
}
else return myHSFW;
}
I create an initial instance of it in the Form_Shown event
private void SetupDialogForm_Shown(object sender, EventArgs e)
{
try
{
myHandler = HSFW_Handler.GetInstance();
UpdateDisplay();
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
The Form Closing looks like this...
private void SetupDialogForm_FormClosing(object sender, FormClosingEventArgs e)
{
myHandler = null;
}
Let's look at this code:
public static HSFW_Handler GetInstance()
{
if (myHSFW == null)
{
myHSFW = new HSFW_Handler();
return myHSFW;
}
else return myHSFW;
}
And this:
private void SetupDialogForm_FormClosing(object sender, FormClosingEventArgs e)
{
myHandler = null;
}
Notice anything?
You're setting myHandler to null; but this appears to be an instance-level member of SetupDialogForm. Or anyway, it's not the same as myHSFW, which is your static variable in the HSFW_Handler class.
When you do this...
myHandler = HSFW_Handler.GetInstance();
...you're making myHandler a reference to the same object pointed to by HSFW_Handler.myHSFW; but they're still two separate references. Setting one to null has no impact on the other.
The point of all this is that you need to actually change the value of myHSFW to null to get the behavior you seem to want.
I'd do it like this:
public class HSFW_Handler
{
public static void DeleteInstance()
{
myHSFW = null;
}
}
Then:
private void SetupDialogForm_FormClosing(object sender, FormClosingEventArgs e)
{
HSFW_Handler.DeleteInstance();
}
Are you certain that the form_Closing event is being fired, so that you're closing the form and not hiding it?
If so, then search through the code looking for every time classInstance is set to something. You'll probably find the culprit in or around the constructor or another event such as Load or Shown.

Categories

Resources