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)
Related
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();
Program.cs
namespace PerformanceMonitor
{
static class Program
{
private static int NumberOfCores;
private static List<int> CPULoadVals;
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new MonitorGUI());
NumberOfCores = getNumberOfCores();
CPULoadVals = getCoreLoadVals();
}
private static int getNumberOfCores()
{
int coreCount = 0;
foreach (var core in new ManagementObjectSearcher("SELECT * FROM Win32_Processor").Get())
{
coreCount += int.Parse(core["NumberOfCores"].ToString());
}
return coreCount;
}
...
MonitorGUI.cs
namespace PerformanceMonitor
{
public partial class MonitorGUI : Form
{
public static List<Label> labels;
private static List<int> CPULoadVals;
public MonitorGUI()
{
InitializeComponent();
}
public void Form1_Load(object sender, EventArgs e)
{
...
}
Debugging the app I can see that InitializeComponent() is invoked causing a new form to be created (Application.Run(new MonitorGUI());) but trying to step through after that and nothing is called. The method on form load is not even called even though I can visually see that it's loaded
Application.Run()
Begins running a standard application message loop on the current thread, and makes the specified form visible.
This method blocks and only returns when you close the Form passed as argument. So all calls after that are executed when you close your main window.
You might want to change the order:
[STAThread]
static void Main()
{
NumberOfCores = getNumberOfCores();
CPULoadVals = getCoreLoadVals();
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new MonitorGUI());
}
And Form1_Load() is only called if you subscribed to the Load event of the Form:
public MonitorGUI()
{
InitializeComponent();
Load += Form1_Load; // <--- subscribe to the event
}
But this can also be done in designer. Check if you have set this event correctly.
The problem is that i have some kind of splash screen which shows loading animation.
I have special manager that show and hide it.
class Manager
{
private Form CurForm;
Thread curt;
private Manager()
{
curt= new Thread(start);
curt.ApartmentState = ApartmentState.STA;
curt.IsBackground = true;
curt.Start();
}
void start()
{
CurForm = new Animation();
Application.Run(CurForm);
}
public static readonly Manager Active = new Manager();
public static void Show()
{
if (Active.CurForm != null)
{
Active.CurForm.Invoke(new Action(() => { Active.CurForm.Show(); }));
}
}
public static void Hide()
{
if (Active.CurForm != null)
{
Active.CurForm.Invoke(new Action(() => { Active.CurForm.Hide(); }));
}
}
}
I open some modal form (ShowDialog). This modal form doesn't show in taskbar.
I easily can minimise it and after clicking on main form on task bar it show that modal form on top.
But when I show this loading animation while it's loading all necessary data.
some kind like that (of course it is just a sample to test it work, and in real app it tooks much time to load all data and form with lots of controls)
public modal()
{
Manager.Show();
InitializeComponent();
Thread.Sleep(5000);
Manager.Hide();
}
And when i'm trying to minimise and restore it like i said above it doesn't restore my modal form and just show my main not available form. And more than that it works in some cases but in some not.
Does anybody know why it is happens or how to fix it?
it is strange but when i modify like this, everything seems to work normal.
I just kill separate ui thread.
public class MyApplicationContext:ApplicationContext
{
public Form CurForm;
ManualResetEvent ready = new ManualResetEvent(false);
public MyApplicationContext()
{
CurForm=new Animation();
CurForm.Show();
}
}
class Manager
{
private MyApplicationContext CurContext;
Thread curt;
void start()
{
try
{
CurContext = new MyApplicationContext();
Application.Run(CurContext);
}
catch
{
CurContext.CurForm.Close();
}
}
private void Init()
{
curt = new Thread(start);
curt.SetApartmentState(ApartmentState.STA);
curt.IsBackground = true;
curt.Start();
}
public static Manager Active
{
get
{
if (active == null)
{
active = new Manager();
}
return active;
}
}
private static Manager active;
public static void Show()
{
Active.Init();
}
public static void Hide()
{
Active.curt.Abort();
}
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()) { }?
I have a simple forms program that I have been fighting with for a while now. I simply want to be able to call a method from a different class file (when a certain step is triggered in the code in that class file) in order to insert a string in the listBox.
Here is my main method, pretty standard:
class Program
{
[STAThread]
static void Main(string[] args)
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new MainForm());
}
}
Here is the function which resides in my MainForm.cs file, which I can call just fine from that class file (via 'TextToBox(myString);'):
public partial class MainForm : Form
{
...
// Function to output results to main Listbox window
public void TextToBox(string aString)
{
// Place messages in Main Display list box window
this.listBox1.Items.Insert(0, aString);
}
...
}
But my problem is when I am in another class and I want to call 'TextToBox(myString);'. If I create another object reference of the MainForm, the code compiles fine but nothing will show up in the listBox. How do I do this? I cannot simply make TextToBox() static. I know I must create the object reference but I can't figure out how to reference the ORIGINAL MainForm, the one that was created in the Main method. Thanks in advance...
This will work, but only when you have one instans of MainForm.
public class MainForm : Form
{
public MainForm()
{
Instance = this;
}
public static MainForm Instance { get; private set; }
// Function to output results to main Listbox window
public void TextToBox(string aString)
{
// Place messages in Main Display list box window
this.listBox1.Items.Insert(0, aString);
}
}
public class Other
{
public void AddTextToListBox()
{
MainForm.Instance.TextToBox("Test");
}
}
...Edit...
Alternative:
class Program
{
public static MainForm MainFormInstance;
[STAThread]
static void Main(string[] args)
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
MainFormInstance = new MainForm();
Application.Run(MainFormInstance);
}
}
public class Other
{
public void AddTextToListBox()
{
Program.MainFormInstance.TextToBox("Test");
}
}
I would just pass a delegate to the other class.
/* this runs (previous code was not guaranteed to run) */
class OtherClass
{
public delegate void TextToBox(string s);
TextToBox textToBox;
int next = 0;
public OtherClass(TextToBox ttb)
{
textToBox = ttb;
}
public void SendSomeText()
{
textToBox(next.ToString());
next++;
}
}
I'm assuming you'll be instantiating OtherClass from MainForm. Is this how you're calling "OtherClass"?
public partial class MainForm : Form
{
OtherClass otherClass;
public MainForm()
{
/* just two controls -- listBox1 and button1 */
InitializeComponent();
otherClass = new OtherClass(this.TextToBox);
}
public void TextToBox(string aString)
{
listBox1.Items.Add(aString);
}
private void button1_Click(object sender, EventArgs e)
{
otherClass.SendSomeText();
}
}
On a button click the next numeric value is added at the beginning of the ListBox. You'll have to post some of your code if you need further help.
alternatively you could use a singleton pattern, or static methods and make sure you include the class in a 'using' statement at the top of your program