How to avoid multiple instances of windows form in c# - 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.

Related

C# delegate throwing an exception

I thought I had done my research and figured this out, but when I try to pass data from one form to another, the program throws an exception. I'm using a delegate to try to call a function in one form from another. Here's the code I have.
In the parent form:
private void viewListToolStripMenuItem_Click(object sender, EventArgs e)
{
frmDataView dataview = frmDataView.GetInstance();
if (dataview.Visible)
dataview.BringToFront();
else
{
dataview.GotoRecord += GotoRecord;
dataview.Show();
}
}
private void GotoRecord(int index)
{
Current.record = index;
loadRecord(index);
setNavButtons();
}
In the child form, I'm trying to call GotoRecord in the parent form with the following code:
public partial class frmDataView : Form
{
AdvancedList<ScoutingRecord> displayedData = new AdvancedList<ScoutingRecord>(Current.data);
// Set the form up so that only one instance will be available at a time.
private static frmDataView _instance;
public static frmDataView GetInstance()
{
if (_instance == null)
_instance = new frmDataView();
return _instance;
}
public delegate void GotoRecordHandler(int index);
public GotoRecordHandler GotoRecord;
private void dgvMain_CellDoubleClick(object sender, DataGridViewCellEventArgs e)
{
int row = e.RowIndex;
int teamnumber = (int)dgvMain.Rows[row].Cells["TeamNumber"].Value;
int matchnumber = (int)dgvMain.Rows[row].Cells["MatchNumber"].Value;
ScoutingRecord sr = Current.data.FirstOrDefault(x => x.TeamNumber == teamnumber && x.MatchNumber == matchnumber);
//int index = Current.data.IndexOf(sr);
GotoRecord(Current.data.IndexOf(sr));
}
Whenever I run the code, it throws the following exception:
GotoRecord was null
I feel like I'm missing something simple. Any suggestions on how to get this working?
As Eugène suggested:
GotoRecord?.Invoke(Current.data.IndexOf(sr));
or if on an older version and not using other threads:
if (GotoRecord != null)
{
GotoRecord(Current.data.IndexOf(sr));
}
EDIT: Corrected mistake in call.

Change value from in Parent Form from Child Form

I tried different solutions but had no luck... I don't know how to handle this. Following problem:
I have a main form (Form1) and a child form (splashScreen).
The code in my splashScreen:
public splashScreen()
{
InitializeComponent();
}
public splashScreen(Form1 frm1)
{
form1 = frm1;
InitializeComponent();
}
private static splashScreen m_instance = null;
private static object m_instanceLock = new object();
public static splashScreen GetInstance()
{
lock (m_instanceLock)
{
if (m_instance == null)
{
m_instance = new splashScreen();
}
}
return m_instance;
}
In my Form1 I'm creating a new thread and starting my splashScreen. The way I'm calling controls in my splashScreen is the following:
splashScreen splashObj = splashScreen.GetInstance();
if (splashObj.InvokeRequired)
{
splashObj.Invoke((MethodInvoker)delegate()
{
splashObj.Show();
}
);
}
else
{
splashObj.Show();
}
Now the splashScreen gets started when my Form1 is working and shows the current process. On the splashScreen I have a button "Cancel". When I click on that button I want to change a variable "killProc" - which is in my Form1- to "true" so that the work in Form1 can be stopped through a return statement when at some point "if(killProc)" returns true.
How do I change the variable in my Form1 through my splashScreen or is there even a better way?
In the GetInstance method use the splashScreen(Form1 frm1) constructor to constructs an instance. They you have the reference to your parent from SplashScreen, which you could use the set property.
public static splashScreen GetInstance(Form1 frm1)
{
lock (m_instanceLock)
{
if (m_instance == null)
{
m_instance = new splashScreen(frm1);
}
}
return m_instance;
}
So, from SplashScreen
form1.killProc = true;

How to update progress bar from another class C#?

I have my progressbar in form1. and i have another class called process.cs
In the main form I have these two functions...
public void SetProgressMax(int max)
{
uiProgressBar.Value = 0;
uiProgressBar.Minimum = 0;
uiProgressBar.Maximum = max;
}
public void IncrementProgress()
{
uiProgressBar.Increment(1);
}
How can I call these functions from my process.cs class?
You're creating a "tightly coupled" solution which requires the process class to have a reference to the Form (I'll use Form1 in this example).
So in your process class, you need to create a variable to store the reference to the form, and allow a way to pass that reference in. One way is to use the constructor of the class:
public class process
{
private Form1 f1 = null;
public process(Form1 f1)
{
this.f1 = f1;
}
public void Foo()
{
if (f1 != null && !f1.IsDisposed)
{
f1.SetProgressMax(10);
f1.IncrementProgress();
f1.IncrementProgress();
f1.IncrementProgress();
}
}
}
Here's an example of creating the process class from within Form1 and passing the reference in:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
process p = new process(this);
p.Foo();
}
public void SetProgressMax(int max)
{
uiProgressBar.Value = 0;
uiProgressBar.Minimum = 0;
uiProgressBar.Maximum = max;
}
public void IncrementProgress()
{
uiProgressBar.Increment(1);
}
}
--- EDIT ---
Here's a boiled down version of the "loosely coupled" events approach (ignoring multi-threading issues for simplicity):
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
process p = new process();
p.Progress += p_Progress;
p.Foo();
}
void p_Progress(int value)
{
uiProgressBar.Value = value;
}
}
public class process
{
public delegate void dlgProgress(int value);
public event dlgProgress Progress;
public void Foo()
{
// ... some code ...
// calcuate the current progress position somehow:
int i = (int)((double)3 / (double)10 * (double)100); // 30% complete
// raise the event if there are subscribers:
if (Progress != null)
{
Progress(i);
}
}
}
Note that in this approach the process class has no reference to the form and has no idea what is being done with the progress value. It simply reports the progress and the subscriber (the form in this case) decides what to do with that information.

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 do I access form properties with Invoke, but with object parameter in C#?

I couldn't describe the title of my question the best,I'm sorry.
Currently,I use Invoke to access the properties on my form,It works perfect,but I have a function for each property,which is quite not comfortable.
public static void EnableLogin(int enabled)
{
var form = Form.ActiveForm as FormMain;
if (form != null)
form.EnableLogin = enabled;
}
public static void EnableConfirm(int enabled)
{
var form = Form.ActiveForm as FormMain;
if (form != null)
form.EnableConfirm = enabled;
}
public static void EnableRetry(int enabled)
{
var form = Form.ActiveForm as FormMain;
if (form != null)
form.EnableRetry = enabled;
}
public static void EnableTABLogin(int enabled)
{
var form = Form.ActiveForm as FormMain;
if (form != null)
form.EnableTABLogin = enabled;
}
Each of these functions looks like that
public int EnableLogin
{
set
{
if (this.InvokeRequired)
{
this.Invoke((MethodInvoker)delegate
{
if (value == 0)
this.btnLogin.Enabled = false;
else
this.btnLogin.Enabled = true;
});
}
else
{
if (value == 0)
this.btnLogin.Enabled = false;
else
this.btnLogin.Enabled = true;
}
}
}
My question is,can't I do it like that
public static void EnableObject(object name)
{
var form = Form.ActiveForm as FormMain;
if (form != null)
form.Enable + name = enabled;
}
It's definitely not that way,I couldn't think of something more OO,but instead of writing tons of functions with same code,can't I use one by passing the object I'd like to change?
You could create a method that takes an delegate parameter describing the action to perform. Then you could get rid of the repeated code.
Here is an example: I create a public method called PerformAction on my form. It takes an Action<MainForm> delegate as argument; this delegate describes the action that should be taken.
The instance method should be used when possible, but for completeness I created a static version that gets the Form instance from Form.ActiveForm.
The code looks like this:
using System;
using System.Windows.Forms;
namespace WinFormTest
{
public partial class MainForm : Form
{
public void PerformAction(Action<MainForm> action)
{
if (InvokeRequired)
Invoke(action,this);
else
action(this);
}
public static void PerformActionOnMainForm(Action<MainForm> action)
{
var form = ActiveForm as MainForm;
if ( form!= null)
form.PerformAction(action);
}
}
}
And can then be used like this from another thread:
MainForm.PerformActionOnMainForm(form => form.Text = "My form");
// The action can also be a code block or a method:
MainForm.PerformActionOnMainForm(form =>
{
form.Width = 200;
form.Height = 300;
form.Left = 100;
form.Top = 200;
});
PerformAction could also be made generic so you can use it on any of your forms. Then the signature would be:
public void PerformAction<T>(Action<T> action)
where T : Form
{
...
}
It would make sense to declare it like this if you have a common base class that is shared amongst your forms. Alternatively, you could create a helper class containing the method.
I asked a similar question but for WPF, the principle is the same though. Modifying the answer that was provided to me by Jon skeet for your question you could use something like this:
public static void InvokeIfNecessary(Form form, MethodInvoker action)
{
if (form.InvokeRequired)
{
form.Invoke(DispatcherPriority.Normal, action);
}
else
{
action();
}
}
public static void EnableLogin(int enabled)
{
var form = Form.ActiveForm as FormMain;
if (form != null)
InvokeIfNecessary(form, delegate { form.btnLogin.Enabled = (enabled != 0) });
}
Edit: Changed from using form.Dispatcher.
You can move the reused functionality into two sperate static methods (one extension) which will greatly simplify what you have in the static helpers and properties.
public static class FormHelpers
{
public static void InvokeOnActive<TForm>(Action<TForm> action)
where TForm : Form
{
TForm activeForm = Form.ActiveForm as TForm;
if (activeForm != null)
activeForm.InvokeEx(f => { action(f); return f; });
}
}
public static class ControlExtensions
{
public static TResult InvokeEx<TControl, TResult>(this TControl control,
Func<TControl, TResult> func)
where TControl : Control
{
if (control.InvokeRequired)
return (TResult)control.Invoke(func, control);
else
return func(control);
}
}
And for your properties:
public int EnableLogin
{
set { this.InvokeEx(f => f.btnLogin.Enabled = value == 0); }
}
And for your static helpers:
public static void EnableLogin(int enabled)
{
FormHelpers.InvokeOnActive<FormMain>(f => f.EnableLogin = enabled);
}

Categories

Resources