Show form again if password wrong - c#

I have the following code which check password/login and do other actions:
public virtual void run()
{
if (appInitializer!=null)
{
ISecurityManager securityManager = appInitializer.SecurityManager;
if (securityManager!=null)
{
if (securityManager.DoLogin())
{
RegisterDefaultActionsGroup();
InitializePlugins(appInitializer.Plugins);
ActionsManager.Inst.ApplySecurity(securityManager, securityManager.CurrentUser);
mainForm = new MainForm();
mainForm.Text = appInitializer.ApplicationTitle;
if (appInitializer.ApplicationIcon != null)
{
mainForm.Icon = appInitializer.ApplicationIcon;
}
CorrectFormSizes(mainForm);
Context[Constants.MainForm] = mainForm;
MenuManager.Inst.FillMenu(DefaultGroups.MAIN_MENU, mainForm.MainMenu, ActionClick);
if(appInitializer.IsHaveToCreatePanelInfo) PanelInfoManager.Inst.FillInfo(mainForm);
if (appInitializer.IsHaveToCreateToolBar)
{
MenuManager.Inst.FillToolbar(DefaultGroups.MAIN_TOOLBAR, mainForm.MainToolStrip, ActionClick);
}
mainForm.MainToolStrip.Visible = mainForm.MainToolStrip.Items.Count > 0;
NotifyPluginsAboutShowing(appInitializer.Plugins);
Application.Run(mainForm);
}
}
}
}
The main method is DoLogin. If it return true then run other actions(fill menu, create toolbar and other).
The problem is that if user enter wrong password then DoLogin returns false and application is closing.
I want that if user enter wrong password then DoLogin (inside of method is created form) run again.
How can I rewrite this code to acomplish this?
Thanks.
PS. The Run is member of my own Framework class. In the Program.cs file is the following code:
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Framework framework = new Framework(new EArchiveInitializer());
framework.run();
}

Why not just while (!securityManager.DoLogin()) { }?

Related

C# - How to reference my current instance of Form1 from another class in my winforms application?

Apologies if this doesn't make sense! Fairly new to WinForms and this is for a uni assessment. My main form is as below with the method I want to call in another class. I've renamed from Form1 to LoginPage.
public partial class LoginPage : Form
{
public LoginPage()
{
InitializeComponent();
Customer.LoadCustomerDB();
}
public string PinText
{
get { return PINNumTxt.Text; }
set { PINNumTxt.Text = value; }
}
}
My other class looks to verify the PinText which I've made accessible with the function above.
class BankCard
{
// Attributes
private Customer customer;
private int pinAttempts = 0;
private bool cardUnusable = false;
// Member functions
public void VerifyPIN()
{
LoginPage loginPage = new LoginPage();
foreach (Customer c in Customer.customers)
{
if (c.GetID().ToString() == loginPage.AccountNum())
{
customer = c;
}
}
if (cardUnusable == true)
{
MessageBox.Show("This card is currently blocked. Please contact your bank.");
Environment.Exit(0);
}
else if (loginPage.PinText == customer.GetPIN())
{
MessageBox.Show("Success!");
}
else if (pinAttempts < 2)
{
MessageBox.Show("Incorrect PIN attempt " + (pinAttempts + 1) + "/3");
loginPage.PinText = "";
pinAttempts += 1;
}
else
{
MessageBox.Show("3 failed PIN attempts. Please contact your bank.");
cardUnusable = true;
Environment.Exit(0);
}
}
}
My issue is that where I have the following:
LoginPage loginPage = new LoginPage();
This creates a new instance of the main page, doubles up the CustomerDB being loaded in and causes errors in my VerifyPin() function.
Is the issue that I need to somehow have LoginPage loginPage = current instance of LoginPage? And if so, how would I code that?
Thanks for any help
Wyck's comment got it to run without any errors. I had to do:
LoginPage loginPage = Application.OpenForms.OfType<LoginPage>().FirstOrDefault();
Thanks all
In most winforms projects, there is a Program class that has Application.Run(new Form1()); (or whatever your main form is called, LoginPage in your case). In the Program class you can create a static variable public static LoginPage loginPage;
then in the Main function:
static void Main()
{
loginPage = new LoginPage();
Application.Run(loginPage);
}
then when you want the reference to loginPage in any of your classes you can just use Program.loginPage

Call function in instance of class from a sub-form in C#

I'm sure this is really simple, but I just can't find the right phrase to google.
I have an application that is meant to be a tray application.
The Main() function initializes an instance of a class CustomApplicationContext:
private static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new CustomApplicationContext());
}
Within this class, I have a function:
public void DoRestart()
{
if (_DoRestartDialog == null)
{
using (_DoRestartDialog = new RestartDialog())
_DoRestartDialog.ShowDialog();
_DoRestartDialog = null;
}
else
_DoRestartDialog.Activate();
}
I also have a function in this class that opens a form:
protected override void OnTrayIconDoubleClick(MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
if (_InfoDialog == null)
{
using (_InfoDialog = new InfoDialog())
_InfoDialog.ShowDialog();
_InfoDialog = null;
}
else
_InfoDialog.Activate();
}
base.OnTrayIconDoubleClick(e);
}
Within the form is a button. When the button is clicked I want to call the DoRestart function in the primary class. How do I reference this function? I can't seem to get access to it from the form.
Instead of passing your instance directly to Run(), store it at class level first:
public static CustomApplicationContext App;
private static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
App = new CustomApplicationContext();
Application.Run(App);
}
Now you can access it with:
Program.App.DoRestart();

Update a form after Application.Run()

Here is what i want to do
// pseudo code
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Form1 myForm = new Form1();
Application.Run(myForm);
while(true)
{
string a = readline();
}
form1.show(a)
In other words , I need the form always show the input. but the code above will stop after 'Application.Run(myForm);'. The reason I don't write such code in the form1 class is the main part of code is run on a machine learning engine written in F#, and because F# doesn't have a good visual designer. So I am trying to create a simple form1.dll, and use it to plot the result over time.
So my problem is I only can initialise the form, but I can't update it over time.
Any hints will be appreciated.
You're trying to do 2 things at the same time, so your application should reflect that by using 2 threads. Next, the Form's Show() method does not accept a string, so you need to implement your own method.
Here's a C# 2.0 WinForms solution. The program runs the thread and processes the console input:
static class Program
{
[STAThread]
private static void Main()
{
// Run form in separate thread
var runner = new FormRunner();
var thread = new Thread(runner.Start) {IsBackground = false};
thread.Start();
// Process console input
while (true)
{
string a = Console.ReadLine();
runner.Display(a);
if (a.Equals("exit")) break;
}
runner.Stop();
}
}
The FormRunner takes care about thread invocation:
internal class FormRunner
{
internal Form1 form = new Form1();
internal void Start()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(form);
}
private delegate void StopDelegate();
public void Stop()
{
if (form.InvokeRequired)
{
form.Invoke(new StopDelegate(Stop));
return;
}
form.Close();
}
private delegate void DisplayDelegate(string s);
public void Display(string s)
{
if (form.InvokeRequired)
{
form.Invoke(new DisplayDelegate(form.Display), new[] {s});
}
}
}
And Form1 just needs something to display:
public void Display(string s)
{
textBox1.Multiline = true;
textBox1.Text += s;
textBox1.Text += Environment.NewLine;
}

Preloading whole main form while users are filling login textbox

My application has a restricted access. I have a user/password box in a small dialog, and when logged-in, I'm loading a very big form with a tons of controls and several big grids. The whole InitializeComponent() take almost 10 secs to load without any data.
The issue is : how I could pre-run the Form constructor() while users are filling the two login fields ? If user is very slow and need >10 secs to complete authentification, it will be as quick as a wink to show application.
I think it is possible because it is two seperates top level windows, but I have no idea how to implement it. BackgroundWorker, new Thread, ... ? Any clue ?
SOLUTION :
Following Eamonn McEvoy's example, I added some fixes about my prerequesites : I wanted to show only login dialog, and if logged successful, I show the big form.
[STAThread]
static void Main()
{
Launcher context = new Launcher();
Application.Run(context);
}
public class Launcher : ApplicationContext
{
private BigForm _bigForm;
private Thread _loginThread;
private SynchronizeLogin _sharedLogin;
public class SynchronizeLogin
{
private bool _waited = false;
public bool IsInitialized
{
get // loginform should wait before closing until return true
{
lock (this)
{
return _waited;
}
}
set // must be set when bigform is initialized
{
lock (this)
{
_waited = value;
}
}
}
private DialogResult _logged = DialogResult.None;
public DialogResult loginResult
{
get // wait until loginform close
{
lock (this)
{
if (_logged != DialogResult.None)
return _logged;
else
{
Monitor.Wait(this);
return _logged;
}
}
}
set // set from loginform when closing
{
lock (this)
{
_logged = value;
Monitor.Pulse(this);
}
}
}
}
public Launcher()
{
// sync obj between forms
_sharedLogin = new SynchronizeLogin();
_loginThread = new Thread(new ThreadStart(LaunchLogin));
_loginThread.Start();
// first form
_bigForm= new BigForm(_sharedLogin);
_bigForm.Closed += new EventHandler(OnFormClosed);
// notify login thread that the main one is ready
// from now, the login form should be near closing
_sharedLogin.IsInitialized = true;
WaitLogon();
}
private void WaitLogon()
{
if (_sharedLogin.loginResult == DialogResult.OK)
{
_bigForm.LoginSuccessful(); // read and use auth session
_bigForm.Show();
}
else
{
// escape on user login form
// (other exit calls are not working in ctor)
Environment.Exit(42);
}
}
private void LaunchLogin()
{
// ask user
LoginDialog _loginForm = new LoginDialog (_sharedLogin);
_sharedLogin.loginResult = _loginForm.ShowDialog();
// userlogin form closed
// end only current thread
Application.ExitThread();
}
private void OnFormClosed(object sender, EventArgs e)
{
// big form closed
// end ApplicationContext globally
base.ExitThread();
}
}
You could create your login window in a new thread from your main windows constructor
using System.Threading;
private AuthSession _authSession;
public MainWindowConstructor()
{
Thread loginThread = new Thread(new ThreadStart(Login());
loginThread.Start();
//Continue initializing
}
private void Login()
{
LoginWindow loginWindow = new LoginWindow();
_authSession = loginWindow.GetAuthSession();
loginWindow.Close();
}

Implementation to change current user in winforms app

I want to realize to change current user in my application. I have the following code:
public class Framework
{
private MainForm mainForm = null;
... // other fields
public virtual void run()
{
if (appInitializer!=null)
{
ISecurityManager securityManager = appInitializer.SecurityManager;
if (securityManager!=null)
{
if (securityManager.DoLogin())
{
RegisterDefaultActionsGroup();
InitializePlugins(appInitializer.Plugins);
// Apply rights for user
ActionsManager.Inst.ApplySecurity(securityManager, securityManager.CurrentUser);
mainForm = new MainForm();
mainForm.Text = appInitializer.ApplicationTitle;
if (appInitializer.ApplicationIcon != null)
{
mainForm.Icon = appInitializer.ApplicationIcon;
}
CorrectFormSizes(mainForm);
Context[Constants.MainForm] = mainForm;
MenuManager.Inst.FillMenu(DefaultGroups.MAIN_MENU, mainForm.MainMenu, ActionClick);
if(appInitializer.IsHaveToCreatePanelInfo) PanelInfoManager.Inst.FillInfo(mainForm);
if (appInitializer.IsHaveToCreateToolBar)
{
MenuManager.Inst.FillToolbar(DefaultGroups.MAIN_TOOLBAR, mainForm.MainToolStrip, ActionClick);
}
mainForm.MainToolStrip.Visible = mainForm.MainToolStrip.Items.Count > 0;
NotifyPluginsAboutShowing(appInitializer.Plugins);
Application.Run(mainForm);
}
}
}
}
...//other methods
}
static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Framework framework = new Framework(new EArchiveInitializer());
framework.run();
}
}
In the button for change user I have:
Framework.Instance.MainForm.MainMenuStrip.Items.Clear();
Framework.Instance.run();
But, I got error: Starting a second message loop on a single thread is not a valid operation. Use Form.ShowDialog instead.
I know that means this error, but I can't to rewrite my code.
Can you help me?
Thanks.
SOLUTION:
Rewrite the last line in run method:
if (!Application.MessageLoop)
Application.Run(mainForm);
else
mainForm.Show();
Thanks Jonathan.
The problem is actually quite easy, the issue is you are calling Application.Run twice (first on load, second on the button)
A quick work around for this, would be to have the Application.Run an ApplicationContext, instead of a form initially, and from your public virtual void run() method, load the required form.
public class Framework
{
private MainForm mainForm = null;
... // other fields
public virtual void run()
{
if (appInitializer!=null)
{
ISecurityManager securityManager = appInitializer.SecurityManager;
if (securityManager!=null)
{
if (securityManager.DoLogin())
{
RegisterDefaultActionsGroup();
InitializePlugins(appInitializer.Plugins);
// Apply rights for user
ActionsManager.Inst.ApplySecurity(securityManager, securityManager.CurrentUser);
mainForm = new MainForm();
mainForm.Text = appInitializer.ApplicationTitle;
if (appInitializer.ApplicationIcon != null)
{
mainForm.Icon = appInitializer.ApplicationIcon;
}
CorrectFormSizes(mainForm);
Context[Constants.MainForm] = mainForm;
MenuManager.Inst.FillMenu(DefaultGroups.MAIN_MENU, mainForm.MainMenu, ActionClick);
if(appInitializer.IsHaveToCreatePanelInfo) PanelInfoManager.Inst.FillInfo(mainForm);
if (appInitializer.IsHaveToCreateToolBar)
{
MenuManager.Inst.FillToolbar(DefaultGroups.MAIN_TOOLBAR, mainForm.MainToolStrip, ActionClick);
}
mainForm.MainToolStrip.Visible = mainForm.MainToolStrip.Items.Count > 0;
NotifyPluginsAboutShowing(appInitializer.Plugins);
mainForm.Show();
}
}
}
}
...//other methods
}
static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new MyHiddenContext());
}
}
public class MyHiddenContext
: ApplicationContext
{
private static Form activeFormInstance;
public MyHiddenContext()
{
this.RunFramework();
}
public void RunFramework()
{
Framework framework = new Framework(new EArchiveInitializer());
this.framework.run();
activeFormInstance = Framework.Instance.MainForm;
}
public static void ChangeUser()
{
activeFormInstance.Close();
activeFormInstance.Dispose();
Framework.Instance.MainForm.MainMenuStrip.Items.Clear();
Framework.Instance.run();
}
}
Don't quote me on the code actually working, but its more to give an idea on which way to go. The problem though is you can't call Application.Run more than once, so the principal is to have a containing instance or context (in any such sense, form, console etc)

Categories