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

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();
....

Related

how to access array from one class to another class in C# winforms?

I want to access array from one class to another class because my end-user enter the name list on one class. That list store into array in the same class. Then that name list access from another class. I'm not getting any errors in compile time. only I'm getting a run time error. I'm literally sorry to all coz I'm absolutely noob :(
public partial class custom : Form //class one which is end user enter the name list
{
public string PresentValue;
public string NormalValue;
public string[] PValue = new string[50];//public array
public string[] NValue = new string[50];//public array
}
public static int PresentArray = 0;// this line is used to increment the array index
private void cstmsvbtn_Click(object sender, EventArgs e)//this line enter the user namelist
{
PresentValue = cstmtst1.Text + "_PV";//concatinate '_PV'
NormalValue = cstmtst1.Text + "_NV";//concatinate '_NV'
PValue[PresentArray] = PresentValue;
NValue[PresentArray] = NormalValue;
PresentArray++;
}
public partial class print : Form // class to which is end user want to access that name list
{
custom customarray = new custom();// I instantiate the custom cass object
private void button1_Click(object sender, EventArgs e)//when i press this button message box show an empty white box only
{
MessageBox.Show(CustomArray.PValue[0],CustomArray.NValue[0]);
}
}
This is a common requirement and there are many ways to achieve this outcome (some of which might be considered "hacky"). Things I don't recommend:
Changing visibility to public for data fields that should be private
Creating tight dependencies of one form to the implementation details of another.
Creating "global" variables using the static keyword.
Since you claim to be a "noob" I'd like to suggest learning about the event keyword and using Events to communicate between forms. Yes, there is a small learning curve here, but chances are you'll use this a lot and it will be a good investment. I put a link in the Comments section so you can clone or browse this example and see if it does what you want it to (I recommend setting debugger break points so you can see why it does what it does).
What you have (according to your post) is a print form and a custom form. And though you don't really say, this example will have a MainForm that can show the other two:
PrintForm
The PrintForm requires the NValue and PValue arrays to do its printing. By declaring an event named ArrayRequest we give it the ability to request these arrays. Importantly, this class doesn't need to have any knowledge of where this information might be coming from.
public partial class PrintForm : Form
{
public PrintForm() => InitializeComponent();
This is how the class can initiate the request
public event ArrayRequestEventHandler ArrayRequest;
protected virtual void OnArrayRequest(ArrayRequestEventArgs e)
{
ArrayRequest?.Invoke(this, e);
}
When the button is clicked, try and get the information by callingOnArrayRequest
private void buttonShowArray_Click(object sender, EventArgs e)
{
ArrayRequestEventArgs req = new ArrayRequestEventArgs();
OnArrayRequest(req);
if(req.Count == 0)
{
MessageBox.Show("Invalid Request");
}
else
{
String[] allValues =
Enumerable.Range(0, req.Count)
.Select(index => $"{req.NValue[index]} | {req.PValue[index]}")
.ToArray();
MessageBox.Show(
text: string.Join(Environment.NewLine, allValues),
caption: "All Values"
);
}
}
}
// Defined outside the PrintForm class
public delegate void ArrayRequestEventHandler(Object sender, ArrayRequestEventArgs e);
public class ArrayRequestEventArgs : EventArgs
{
public int Count { get; set; }
public string[] PValue { get; set; }
public string[] NValue { get; set; }
}
CustomForm
The CustomForm as shown in your post is the class that contains the arrays.
public partial class CustomForm : Form
{
public CustomForm()
{
InitializeComponent();
}
We give this class the ability to fulfill a request for the arrays.
internal void ArraysRequested(object sender, ArrayRequestEventArgs e)
{
e.Count = _presentArray;
e.NValue = _nValue;
e.PValue = _pValue;
}
The data held in this class should be private.
// These should all be private
// See naming conventions: https://stackoverflow.com/a/17937309/5438626
// Set up visual studio to do this automatically: https://ardalis.com/configure-visual-studio-to-name-private-fields-with-underscore/
private string _normalValue;
private string _presentValue;
private int _presentArray = 0;
private string[] _pValue = new string[50];//public array
private string[] _nValue = new string[50];//public array
private void cstmsvbtn_Click(object sender, EventArgs e)
{
_presentValue = $"{cstmtst1.Text}_PV"; //concatinate '_PV'
_normalValue = $"{cstmtst1.Text}_NV"; //concatinate '_NV'
// Make sure index doesn't exceed the size of the array
if ((_presentArray < _pValue.Length) && (_presentArray < _nValue.Length))
{
_pValue[_presentArray] = _presentValue;
_nValue[_presentArray] = _normalValue;
_presentArray++;
}
else MessageBox.Show("Array is Full");
Text = $"Custom: Count={_presentArray}";
cstmtst1.Text = $"Hello {_presentArray + 1}";
}
}
MainForm
It is the MainForm class that oversees the operations and "knows" how the forms should interact. The constuctor method is where the connection is made between the event fired by PrintForm and the fulfillment by the CustomForm.
public partial class MainForm : Form
{
public MainForm()
{
InitializeComponent();
// THIS IS THE "GLUE"
_printForm.ArrayRequest += _customForm.ArraysRequested;
}
private CustomForm _customForm = new CustomForm();
private PrintForm _printForm = new PrintForm();
// In MainForm.Designer.cs
protected override void Dispose(bool disposing)
{
if (disposing)
{
if (components != null)
{
components.Dispose();
}
_customForm.Dispose();
_printForm.Dispose();
}
base.Dispose(disposing);
}
private void buttonShowCustom_Click(object sender, EventArgs e)
{
_customForm.ShowDialog(owner: this);
}
private void buttonShowPrint_Click(object sender, EventArgs e)
{
_printForm.ShowDialog(owner: this);
}
}
You will need to adapt this to your specific requirements but hopefully this will give you some basics to go on.

C# pass delegates to different forms

i have a WinForms app that consists of several forms.
What I'm trying to achieve is to pass an event handler from a second form, to a third one, but i cannot achieve that. i get a casting error which i can't figure out how to overcome.
i would appreciate the help:
code + further explanation below:
This is a rough image of what is supposed to happen:
Form1 can create several forms (it also holds the methods that i want to pass) - which i can pass successfully on sub form creation.
the problem starts when i create form3 from within form2: i try to pass the event handler, but i get Error CS0029/CS0030 (casting errors)
what am i doing wrong and how to fix it?
EDIT:
what needs to happen? -- Form3 needs to control (send back data) to a Gui control placed in Form1
Code:
Form1:
public delegate void sendMessageToConsoleDelegate(string value);
public sendMessageToConsoleDelegate sendMessageToConsoleCallback;
public delegate void SetPlaceHolderDelegate(TextBox tb);
public SetPlaceHolderDelegate SetPlaceHolderCallback;
private void SetPlaceHolder(TextBox tb)
{
if (!tb.InvokeRequired)
{
if (!tb.Focused)
{
if (string.IsNullOrWhiteSpace(tb.Text))
tb.Text = tb.Tag.ToString();
return;
}
if (tb.Text == tb.Tag.ToString())
tb.Text = "";
return;
}
SetPlaceHolderDelegate call = new SetPlaceHolderDelegate(SetPlaceHolder);
tb.BeginInvoke(call, tb);
}
private void SendMessageToConsole(string msg)
{
if (!textBoxConsole.InvokeRequired)
{
textBoxConsole.AppendText(msg);
return;
}
sendMessageToConsoleDelegate call = new sendMessageToConsoleDelegate(SendMessageToConsole);
textBoxConsole.BeginInvoke(call, msg);
}
private void AddNewDeviceForm()
{
frmAddDevice add_device = new frmAddDevice(devicesDBPath);
add_device.sendMessageToConsole += SendMessageToConsole;
add_device.Show();
}
private void StartEdit()
{
frmEditDBs editdb = new frmEditDBs(devicesDBPath, commandsDBPath);
editdb.sendMessageToConsole += SendMessageToConsole;
editdb.SetPlaceHolder += SetPlaceHolder;
editdb.Show();
}
Form2 (frmEditDBs)
public delegate void EventHandler_sendMessageToConsole(string msg);
public event EventHandler_sendMessageToConsole sendMessageToConsole = delegate { };
public delegate void EventHandler_SetPlaceHolder(TextBox tb);
public event EventHandler_SetPlaceHolder SetPlaceHolder = delegate { };
private void EditDevice()
{
frmAddDevice edit_device = new frmAddDevice(devicesDBpath, current_device);
edit_device.sendMessageToConsole += sendMessageToConsole; ****<== This is the issue (same for the placeholder)****
edit_device.Show();
}
i get error CS0029
how can i pass the same delegate to other sub forms (e.g. frmAddDevice)?
Your question is how to C# pass delegates to different forms so that you can (for example) sendMessageToConsole to your MainForm from the other forms. In your code you state that this is the problem:
// This is the issue (same for the placeholder)****
edit_device.sendMessageToConsole += sendMessageToConsole;
When I look at your code, in essence you are trying to implement your own version of an Event Pattern. One solution to your issue would be to use a standard event pattern. Then intellisense will recognize your custom event delegate in the standard way:
FIRST you need to make the delegate and the inherited EventArgs class outside of your MainForm class:
namespace pass_delegates
{
public partial class MainForm : Form
{
}
// Make sure these are outside of any other class.
public delegate void SendMessageToConsoleEventHandler(object sender, SendMessageToConsoleEventArgs e);
public class SendMessageToConsoleEventArgs : EventArgs
{
public string Message { get; }
public SendMessageToConsoleEventArgs(string message)
{
Message = message;
}
}
}
Your frmAddDevice (shown here in minimal format) declares the delegate using the event keyword. Your other form frmEditDBs does exactly the same thing.
public partial class frmAddDevice : Form
{
public event SendMessageToConsoleEventHandler SendMessageToConsole;
public frmAddDevice(string devicesDBpath)
{
InitializeComponent();
}
protected virtual void OnSendMessageToConsole(SendMessageToConsoleEventArgs e)
{
SendMessageToConsole?.Invoke(this, e);
}
// Clicking the button will call this as a test.
private void btnSendTestMessage_Click(object sender, EventArgs e)
{
OnSendMessageToConsole(new SendMessageToConsoleEventArgs("Message received from 'Add Device Form'"));
}
}
A button in the MainForm code creates a new frmAddDevice like this:
frmAddDevice frmAddDevice = null;
// This handler in the Main Form creates the frmAddDevice form
private void btnFrmAddDevice_Click(object sender, EventArgs e)
{
if (frmAddDevice == null)
{
frmAddDevice = new frmAddDevice(devicesDBpath: "Some path");
// This was the problem. Not anymore ****
frmAddDevice.SendMessageToConsole += outputMessageToConsole;
}
frmAddDevice.Show();
}
private void outputMessageToConsole(object sender, SendMessageToConsoleEventArgs e)
{
textBoxConsole.AppendText(e.Message + Environment.NewLine);
}
If you do these things, you will achieve the functionality of sendMessageToConsole that your code is attempting to do. Try it out by downloading my sample from GitHub.
I think the main concept you don't understand is that delegate is "same level" as class, enum, struct etc. You need to declare it in some shared scope to make it accessible in both forms.
namespace ConsoleApp6
{
public delegate void TestDelegate();
public class ClassA
{
public TestDelegate delegateA;
}
public class ClassB
{
public TestDelegate delegateB;
}
internal class Program
{
static void Main(string[] args)
{
TestDelegate del = () => { };
var classA = new ClassA()
{
delegateA = del,
};
var classB = new ClassB()
{
delegateB = classA.delegateA
};
}
}
}
Or, if you want to keep it inside of the form, you need reference it by a class name the same way you would do with a type.
namespace ConsoleApp6
{
public class ClassA
{
public delegate void TestDelegate();
public TestDelegate delegateA;
}
public class ClassB
{
public ClassA.TestDelegate delegateB;
}
internal class Program
{
static void Main(string[] args)
{
ClassA.TestDelegate del = () => { };
var classA = new ClassA()
{
delegateA = del,
};
var classB = new ClassB()
{
delegateB = classA.delegateA
};
}
}
}
As was described previously, your "delegates" should be declared generically at the namespace of your project, not within a specific class so they are visible throughout your app. To do so, maybe make a separate file in your project for "MyDelegates" and may look something like:
using System.Windows.Forms;
namespace WinHelp1
{
// Create your own delegates outside of your classes that need to be publicly
// visible within your app or even protected if so needed.
public delegate void EventHandler_SendMessageToConsole(string msg);
public delegate void EventHandler_SetPlaceHolder(TextBox tb);
}
Now, in your form 1 that you want to define WHAT to do, do so based on the signatures matching appropriately
using System.Windows.Forms;
namespace WinHelp1
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
public void DoThisForConsole(string msg)
{
// whatever to do with string
}
public void DoThisForTextBox(TextBox tb)
{
// whatever to do with textbox
}
private void Btn2_Click(object sender, System.EventArgs e)
{
var f2 = new Form2();
f2.SendMessageToConsole += DoThisForConsole;
f2.SetPlaceHolder += DoThisForTextBox;
f2.ShowDialog();
// OR, if using the PARAMETERIZED for pass-through to call
// when form2 calls form 3
var f2b = new Form2( DoThisForConsole, DoThisForTextBox );
f2b.ShowDialog();
}
private void Btn3_Click(object sender, System.EventArgs e)
{
var f3 = new Form3();
f3.SendMessageToConsole += DoThisForConsole;
f3.SetPlaceHolder += DoThisForTextBox;
f3.ShowDialog();
}
}
}
First, form3 since that will just have the direct event handlers, and you can invoke however within form 3
using System.Windows.Forms;
namespace WinHelp1
{
public partial class Form3 : Form
{
// now, for each form you want to USE them on...
public event EventHandler_SendMessageToConsole SendMessageToConsole;
public event EventHandler_SetPlaceHolder SetPlaceHolder;
public Form3()
{
InitializeComponent();
}
}
}
Now, in your form 2, is a bit different. Since you want to make available for form2 to call form3 with the same event handler, just add those event handlers as parameters to the constructor class. Then you can preserve them in that form, but at the same time, self-register them as in the var f2b = new Form2 of the second button click event. Then use those preserved values when form2 needs to call form3
using System.Windows.Forms;
namespace WinHelp1
{
public partial class Form2 : Form
{
// now, for each form you want to USE them on...
public event EventHandler_SendMessageToConsole SendMessageToConsole;
public event EventHandler_SetPlaceHolder SetPlaceHolder;
// now, for each form you want to USE them on...
public EventHandler_SendMessageToConsole passThroughForMessage;
public EventHandler_SetPlaceHolder passThroughForTextBox;
public Form2()
{
InitializeComponent();
}
public Form2(EventHandler_SendMessageToConsole forSendMsg, EventHandler_SetPlaceHolder forPlaceHolder ) : this()
{
// preserve into properties in-case you need to call form 3
passThroughForMessage = forSendMsg;
passThroughForTextBox = forPlaceHolder;
// and the constructor can auto-set for itself so IT can notify as well
if( forSendMsg != null )
SendMessageToConsole += forSendMsg;
if( forPlaceHolder != null )
SetPlaceHolder += forPlaceHolder;
}
private void Btn3_Click(object sender, System.EventArgs e)
{
var f3 = new Form3();
// and the constructor can auto-set for itself so IT can notify as well
if (passThroughForMessage != null)
f3.SendMessageToConsole += passThroughForMessage;
if (passThroughForTextBox != null)
f3.SetPlaceHolder += passThroughForTextBox;
f3.ShowDialog();
}
}
}
Remember, parameters can be practically anything, and you can have a variable stored in a property just like anything else... as long as it matches the respective type.
Then, from form3, either instance will invoke back to whatever the root instance method may be.

Why is my C# Singleton not working?

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!

datagrid access from another form

I have datagridview in form1. How can I access datagridview from form2.
private void button1_Click(object sender, EventArgs e)
{
string sql1 = "insert into Car (plate, color, [year], model) values ('"+tplate.Text+"','"+tcolor.Text+"',"+tyear.Text+",'"+tmodel.Text+"')";
string sql2 = "select * from Car";
try
{
int res = CarDatabase.executeOthers(sql1);
if(res >0){
DataTable dt = CarDatabase.executeSelect(sql2);
mainframe.Dgv.DataSource = dt;
MessageBox.Show("New Car is added");
}
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString());
}
}
here mainframe.Dgv is in the first form
but I cannot access like that Form1.dataGridView why :S
In Form2:
public DataGridView Dgv { get; set; }
In Form1:
Form2 f = new Form2();
f.Dgv = mainframe.Dgv;
In Form2 access its own Dgv propety.
You need a reference to the actual Form in order to access its members. (And those members will need to be public.)
Just calling something like this:
Form1.dataGridView
won't work because Form1 is just a type, it's not a reference to an instantiated object in memory. That's how you'd reference static members, which isn't the case here. The DataGridView is an instance member. So you need a reference to the instance of Form1. Something more like:
firstForm.dgv
where firstForm is a variable on Form2 (or passed into the method as an argument from Form1, where the argument would just be this, etc.) and dgv is the public member on Form1 which represents the DataGridView.
Something like this:
public class Form1
{
public DataGridView DGV { get; set; }
private void DoSomething()
{
var anotherForm = new Form2();
anotherForm.DoSomethingElse(this);
}
}
public class Form2
{
public void DoSomethingElse(Form1 firstForm)
{
var data = firstForm.DGV.DataSource;
}
}
Note that I left out a lot of WinForms stuff here. That's intentional. This is just to demonstrate the concept at the code level. What the forms inherit from, how they're instantiated, how they're held in memory, that's all another concern.
How you set this up is up to you. I'm not well versed in WinForms development, but I imagine there are better ways to accomplish this. In order to determine that, though, we'd need to know why Form2 needs to access Form1's DataGridView. It's likely that, instead, they should both access a shared back-end resource. Maybe something more like this:
public class Form1
{
private DataGridView dgv { get; set; }
private void LoadMyData()
{
dgv.DataSource = GlobalDataSources.SomeDataSource;
}
private void DoSomething()
{
var anotherForm = new Form2();
anotherForm.DoSomethingElse();
}
}
public class Form2
{
public void DoSomethingElse()
{
var data = GlobalDataSources.SomeDataSource;
}
}
public class GlobalDataSources
{
private static SomeDataSourceType _someDataSource;
public static SomeDataSourceType SomeDataSource
{
get
{
if (_someDataSource == null)
{
// populate the data source
}
return _someDataSource;
}
}
}
As always, there are many ways to do it. But the basic idea is that, instead of accessing each other and creating all kinds of cross-dependencies, your front-end forms access shared back-end resources and the dependency chain just flows in that one direction.
You need to make the dataGridView field/property "public" or "internal". Choose public if you're a beginner like it sounds.

How to avoid multiple instances of windows form in c#

How to avoid multiple instances of windows form in c# ?? i want only one instance of the form running. Because there are chances of opening the same form from many pages of my application.
implement the Singleton pattern
an example: CodeProject: Simple Singleton Forms (ok, it's in VB.NET, but just to give you a clue)
Yes, it has singleton pattern,
Code to create a singleton object,
public partial class Form2 : Form
{
.....
private static Form2 inst;
public static Form2 GetForm
{
get
{
if (inst == null || inst.IsDisposed)
inst = new Form2();
return inst;
}
}
....
}
Invoke/Show this form,
Form2.GetForm.Show();
When you display the dialog simply use .ShowDialog(); instead of .Show();
One solution I applied to my project in order to bring this form again in the foreground is:
private bool checkWindowOpen(string windowName)
{
for (int i = 0; i < Application.OpenForms.Count; i++)
{
if (Application.OpenForms[i].Name.Equals(windowName))
{
Application.OpenForms[i].BringToFront();
return false;
}
}
return true;
}
windowName is essentially the class name of your Windows Form and
return value can be used for not creating a new form instance.
If your system has the possibility of showing the same type of form for different instance data then you could create a checking system that iterates all existing open forms, looking for a unique instance data identifier and then re-display any found form.
e.g. having a form class 'CustomerDetails' which contains a public property 'CustomerUniqueID':
foreach(Form f in CurrentlyDisplayedForms)
{
CustomerDetails details = f as CustomerDetails;
if((details != null) && (details.CustomerUniqueUD == myCustomerID))
{
details.BringToFront();
}
else
{
CustomerDetails newDetail = new CustomerDetails(myCustomerID);
}
}
We also use the same mechanism to automatically force refreshes of data binding where a customer's data has been edited and saved.
Here is my solution in ShowForm() :
private void ShowForm(Type typeofForm, string sCaption)
{
Form fOpen = GetOpenForm(typeofForm);
Form fNew = fOpen;
if (fNew == null)
fNew = (Form)CreateNewInstanceOfType(typeofForm);
else
if (fNew.IsDisposed)
fNew = (Form)CreateNewInstanceOfType(typeofForm);
if (fOpen == null)
{
fNew.Text = sCaption;
fNew.ControlBox = true;
fNew.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle;
fNew.MaximizeBox = false;
fNew.MinimizeBox = false;
// for MdiParent
//if (f1.MdiParent == null)
// f1.MdiParent = CProject.mFMain;
fNew.StartPosition = FormStartPosition.Manual;
fNew.Left = 0;
fNew.Top = 0;
ShowMsg("Ready");
}
fNew.Show();
fNew.Focus();
}
private void aboutToolStripMenuItem_Click(object sender, EventArgs e)
{
ShowForm(typeof(FAboutBox), "About");
}
private Form GetOpenForm(Type typeofForm)
{
FormCollection fc = Application.OpenForms;
foreach (Form f1 in fc)
if (f1.GetType() == typeofForm)
return f1;
return null;
}
private object CreateNewInstanceOfType(Type typeofAny)
{
return Activator.CreateInstance(typeofAny);
}
public void ShowMsg(string sMsg)
{
lblStatus.Text = sMsg;
if (lblStatus.ForeColor != SystemColors.ControlText)
lblStatus.ForeColor = SystemColors.ControlText;
}
check this link :
using System;
public sealed class Singleton
{
private static volatile Singleton instance;
private static object syncRoot = new Object();
private Singleton() {}
public static Singleton Instance
{
get
{
if (instance == null)
{
lock (syncRoot)
{
if (instance == null)
instance = new Singleton();
}
}
return instance;
}
}
}
Try this code
Public class MyClass
{
//Create a variable named
public static int count = 0;
//Then increment count variable in constructor
MyClass()
{
count++;
}
}
While creating the object for the above class 'MyClass' check the count value greater than 1
class AnotherClass
{
public void Event()
{
if(ClassName.Count <= 1)
{
ClassName classname=new ClassName();
}
}
}
Here's a simple way to do it.
Check if the form is null, or has been disposed. If that's true we create a new instance of the form.
Otherwise we just show the already running form.
Form form;
private void btnDesktop_Click(object sender, EventArgs e)
{
if (form == null || desktop.IsDisposed)
{
form = new Form();
form.Show();
}
else
{
form.WindowState = FormWindowState.Normal;
}
}
private static MyForm _myForm;
internal static MyForm form
{
get
{
if (_myForm == null)
{
_myForm = new MyForm();
}
return _myForm;
}
}
public MyForm()
{
InitializeComponent();
_myForm = this;
}
private void MyForm_FormClosed(object sender, FormClosedEventArgs e)
{
_myForm = null;
}
Singletons are not object-oriented. They are simply the object version of global variables. What you can do is to make the constructor of the Form class private, so nobody can accidentally create one of these. Then call in reflection, convert the ctor to public and make sure you create one and only one instance of it.
You can check the existing processes prior to opening the form:
using System.Diagnostics;
bool ApplicationAlreadyStarted()
{
return Process.GetProcessesByName(Process.GetCurrentProcess.ProcessName).Length == 0;
}
I don't know if the GetProcessesByName method is affected by UAC or other security measures.

Categories

Resources