Passing arguments to run application - c#

Looking for help on this project, I am new and might not know all terms so please bare with me.
Project contains multiple winforms panels. Start one is my dashboard then I have others that do specific functions/features. What I need to be able to do is call up the separate winforms from an outside bat file that comes from a third party software (I have no control over them).
So what I would like to do is this programname.exe runs the dashboard programname.exe -a runs a different winform with in my program. I am not sure what this is called to do this.
Any help would be great even if a place to go and look it up.
namespace Versi_Send_Email
{
public partial class DashBoard : Form
{
public DashBoard()
{
InitializeComponent();
}
private void DashBoard_Load(object sender, EventArgs e)
{
INIFile inif = new INIFile(#"c:\test\mailsettings.ini");
sitetxtbox.Text = inif.Read("Properties", "site");
emailtotxtbox.Text = inif.Read("Properties", "personto");
cctotxtbox.Text = inif.Read("Properties", "ccto");
bcctextbox.Text = inif.Read("Properties", "bcto");
}

This could be a switch statement or a simple if-else statement. In WinForms application and in the main form loaded event, you can read the command line arguments like this
string[] args = Environment.GetCommandLineArgs();
foreach(string arg in args){
if (arg=="EmployeeForm")
{
EmployeeForm.ShowDialog()
else if (arg=="Department")
Department.ShowDialog()
}
//after all arguments are read, you can simply kill the application and main window will never appear
Application.Current.Shutdown();
return;

Related

Display my forms in another class

I recently developped an application for a student project, and everything works fine. However, if I'm asking something here, you can certainly assume that the whole thing isn't so functional...and you'd be right hohoho. Let's get started. Basically the functional version of my project uses an UI console.
It runs, but from an user point of view, working with something like this isn't the most amazing stuff in the world. So I decided to replace my old console by some Windows Forms.
Project global render with console
Project global render with form
This is where things become wrong. I have "3" classes :
Program.cs (the main program with all the serious stuff)
formOne.cs (the first form with a button for each options)
form/Two to Five/.cs (each options open the corresponding form)
At some point, Program.cs will launch formOne.cs, and from there the user should be able to navigate between the various options and so the various forms...but nope. formOne.cs opens, and then we can't click on anything (well we can but nothing happens). I did a mistake somewhere, I would like to know where and how to fix it. Here's how I proceeded :
(this is the basic algorithm, not the whole code)
Program.cs :
class Program {
formOne winRecep = new formOne();
formTwo winCrea = new formTwo();
formThree winSearch = new formThree();
formFour winDel = new formFour();
formFive winView = new formFive();
winRecep.ShowDialog();
string userChoice = winRecep.getUserChoice();
switch(userChoice){
case "create new task" :
winCrea.ShowDialog();
break;
case "search a task" :
winSearch.ShowDialog();
break;
case "delete a task" :
winDel.ShowDialog();
break;
case "view my tasks" :
winView.ShowDialog();
break;
}
}
formOne.cs :
class formOne {
string userChoice;
public formOne()
{
InitializeComponent();
}
public string getUserChoice()
{
return userChoice;
}
private void formOne_Load(object sender, EventArgs e)
{
//blabla update current date, current hour...
}
private void buttonOptionOne_Click(object sender, EventArgs e)
{
userChoice = "create new task";
}
private void buttonOptionTwo_Click(object sender, EventArgs e)
{
userChoice = "search a task";
}
private void buttonOptionThree_Click(object sender, EventArgs e)
{
userChoice = "delete a task";
}
private void buttonOptionFour_Click(object sender, EventArgs e)
{
userChoice = "view my tasks";
}
}
It seems pretty clear to me, but I did a mistake somewhere. I would like to work in Program.cs instead of formOne.cs because, well, everything is in Program.cs so the most logical way to proceed is certainly to work here instead of bring informations and variables everywhere accross the classes.
Could someone help me and explain why it's wrong ?
EDIT : Program.cs using Application doesn't solve the thing :
class Program {
var winRecep = new formOne();
var createtask = new formTwo();
var viewTask = new formThree();
var searchTask = new formFour();
var deleteTask = new formFive();
Application.Run(winRecep);
string userChoice = winRecep.getUserChoice();
switch(userChoice){
case "create new task" :
Application.Run(createtask);
break;
case "search a task" :
Application.Run(searchTask);
break;
case "delete a task" :
Application.Run(deleteTask);
break;
case "view my tasks" :
Application.Run(viewTask);
break;
}
}
You need to start your main form like this:
var mainForm = new formOne();
Application.Run(mainForm);
This starts the windows message loop. Without a message loop, your application can't respond to any events (such as mouse clicks or keypresses).
The first thing you should do, is opening the main form using Application.Run, as already suggested. This starts the message loop which is essential for the rest of the execution:
var mainForm = new formOne();
Application.Run(mainForm);
Then use that form to open all others. Closing the form started with Application.Run will close the application since the message loop will end too. So on any action, like a button click or a command written, open the form you need. You can call Show to open the other form and make it possible to still access the main form, or ShowDialog which will block further actions until the child form was closed.

C# Add Windows Form Application To A Console Application

I have a console application doing some things in the background, and I want to make it so that the user can change some things that the console application is doing.
I want to add a Windows Form Application to just get the user input and send it to the console application to use. I have looked and couldn't find what I'm looking for
I found this question - Add GUI to Existing Code in Visual Studio - but this didn't help me much.
I have this:
bool OnOrOff = true;
but I want to check if a check box from the windows form is checked instead of seting it to true like this:
on Windows Form the checkbox is named CheckOnOrOff and it is checked.
bool OnOrOff = CheckOnOrOff.Checked();
I assume that the user can change the settings while the console application is running and the effect should be taken immediately. Adding your winforms application as reference in console will not help since it's will be a different application. So this is what I suggest:
Make a new winforms application and change the output type from 'Windows Application' to 'Console Application' so we can see the console. Port your console logic proccess to the winforms project
Add a new static class which will hold flag between winforms and console. Example:
namespace FormWithConsole {
public static class SharedData {
public static bool Feature01 { get; set; }
}
}
Add a checkbox your Windows Form and add code bellow to the checkbox changed event:
private void checkBox1_CheckedChanged(object sender, EventArgs e) {
SharedData.Feature01 = checkBox1.Checked;
}
Add a button to start your console process, and use thread to start your console process as follow:
Thread thread;
private void button1_Click(object sender, EventArgs e) {
if (thread != null) {
try {
Console.WriteLine("Aborting current process");
thread.Abort();
thread = null
}
catch (ThreadAbortException) { }
}
ConsoleProcess process = new ConsoleProcess();
thread = new Thread(process.StartProcess);
thread.IsBackground = true;
thread.Start();
}
This is ConsoleProcess class, which hold your console logic
class ConsoleProcess {
public void StartProcess() {
while (true) {
if (SharedData.Feature01) {
// Do something here
}
Console.WriteLine("Regular process here...");
}
}
}
If you want the form minimized to system tray refer to minimize app to system tray
I think you should design a database to store the user input. Your console project and window project will run and manage by this database.
You can take input from windows form (by User) and then pass it to Console application by using parameter argument in Console Application.
The parameter of the Main method is a String array that represents the command-line arguments
So, if I had a console program (MyCApp.exe) like this:
class Program
{
static void Main(string[] args)
{
foreach (var arg in args)
{
Console.WriteLine(arg);
}
}
}
That I started at the command line like this:
MyCApp.exe Arg1 Arg2 Arg3 The Main method would be passed an array
that contained three strings: "Arg1", "Arg2", "Arg3".
If you need to pass an argument that contains a space then wrap it in quotes. For example:
MyCApp.exe "Arg 1" "Arg 2" "Arg 3"
Command line arguments commonly get used when you need to pass information to your application at runtime. For example if you were writing a program that pass basic information to copies a file from one location to another you would probably pass the two locations as command line arguments. For example:
MyCApp.exe C:\file1.txt C:\file2.txt Copyit
Here 'C:\file1.txt' is first Argument, 'C:\file2.txt' is first Argument, 'Copyit' is third Argument

How to start WPF based on Arguments

I'm currently developing an application that does some file manipulation and I want to be able to do the manipulation through the console or via an UI (I chose WPF).
I pretty much want to say: (psuedo)
if ( Environment.GetCommandLineArgs().Length > 0 )
{
//Do not Open WPF UI, Instead do manipulate based
//on the arguments passed in
}
else
{
//Open the WPF UI
}
I've read about a few different ways of starting the WPF Window/application programmatically like:
Application app = new Application ();
app.Run(new Window1());
But I'm not entirely sure I want to just plug this into a Console Application.
Does anyone have best practices or recommendations on how I can achieve this? The main processing functionality is in a Helper class I created. So basically I either want a static start method (like standard Console Application creates) or the UI to access the Helper class depending on the arguments passed in.
In Application class there is an event "StartUp" you can use it . It provide you the args you provide through command prompt. Here is an example from MSDN:
App.xaml
<Application x:Class="WpfApplication99.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Startup="App_Startup">
</Application>
App.xaml.cs
public partial class App : Application
{
void App_Startup(object sender, StartupEventArgs e)
{
// Application is running
// Process command line args
bool startMinimized = false;
for (int i = 0; i != e.Args.Length; ++i)
{
if (e.Args[i] == "/StartMinimized")
{
startMinimized = true;
}
}
// Create main application window, starting minimized if specified
MainWindow mainWindow = new MainWindow();
if (startMinimized)
{
mainWindow.WindowState = WindowState.Minimized;
}
mainWindow.Show();
}
}
I hope this will help.
There are 2 options to get the command line arguments
1) If you want to read the arguments OnStartup. This is good for global access of the args.
Override OnStartup in App.xaml.cs and look at the Args property of the StartupEventArgs class.
public partial class App : Application
{
protected override void OnStartup(StartupEventArgs e)
{
foreach (string arg in e.Args)
{
// TODO: whatever
}
base.OnStartup(e);
}
}
2) Another easy way is to read the arguments from the Environment Object.
Environment.GetCommandLineArgs();
This can be used from anywhere in the application like from the Form / Page also.
I Prefer override OnStartup because the Startup event is usually registered in "App.xaml" and I sometimes don't want to modify it. And OnStartup function can provide a way to do some preprocess before Startup event is invoked. This is why we can override OnStartup!

How do I handle Command Line Arguments in Winforms if I don't want to load Main form?

I want to create an app that behaves as follows:
On no argument it displays the main form
On argument "a" does a job but the main form isn't loaded.
On argument "b" the form loads using the argument passed (load that document)
For the 1 and 3 I can handle the arguments in the form's constructor as follows:
public ConfigurationActionManagerForm()
{
InitializeComponent();
Environment.GetCommandLineArgs();
// do stuff with that argument
}
But this approach doesn't allow me to apply the behavior of 2. in the list.
In program.cs I can edit it to handle the arguments before the form is even created, but what is the correct approach on using Application.Run() if I don't want to pass a form? How am I going to inform Program class instance that I need to terminate or show a message that something went wrong or even show a little taskbar icon that the process is doing stuff (Think of it like the unzipping process).
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new ConfigurationActionManagerForm());
}
Would this approach from MSDN be correct to my application?
Do you mean in the same way that Visual Studio works?
If so then you can't do this in a normal Windows application - Visual Studio cheats.
The problem is that a Windows application can either be a Windows Forms application or a Console application, but it can't be both - its decided at compile time (for .Net applications this is in the project properties window). Your options are:
Make your application a Windows Forms application
In this case #1 and #3 will work perfecty, but for #2 you will find that you can't read from / write to the console (because there isn't one!). If your appliction doesn't need to give any feedback then this might be fine - do your work as you normally would and just don't display a form:
[STAThread]
static void Main(string[] args)
{
if (args.Length > 0)
{
// Handle #2 here
}
else
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new ConfigurationActionManagerForm());
}
}
Make your application a console application
In this case #2 will work perfectly, however although #1 and #3 will work fine you will always have console window open in the background - if you close the console window your application will end.
Again this might be fine, but personally I find this to be a hack.
Cheat (do what Visual Studio Does)
Visual Studio cheats by having 2 separate applications - one is a Console Application and the other is a Windows Forms application. The easy solution is to leave it at that and require that users start a different executable when running the command line version (e.g. myprogram_g.exe and myprogram_w.exe).
Visual Studio goes one step further however and has a single entry point, devenv. It does this by using the fact that for compatability reasons the Windows shell will always run a .com file instead of a .exe if there is any ambiguity. Wheras all shortcuts etc.. point to the executable, if you run devenv on the command line the devenv.com application will run instead which uses magic to sort out whether or not it runs as a console or windows application.
My advice would be to create two different applications and leave it at that.
See How do I write a program that can be run either as a console or a GUI application? for more detail (make sure to read the comments which have additional useful suggestions).
Also see How to make an application as both GUI and Console application? for how ildasm does this.
You can call Application.Run() without a form instance.
That way, it will start the message loop without opening a form.
You can call MessageBox.Show() before calling .Run(), too.
You can even create and open a form, and then call Run() without specifying an argument - it just means that closing the form doesn't automatically exit the application.
E.g.
MessageBox.Show("Messaage!");
Form1 f = new Form1();
f.Show();
Application.Run();
As stated above, this way of doing Run() means that closing the forms doesn't automatically close the application. You need to handle this in the form's Close event handler. (Application.Exit())
MSDN online can help you out with this - check the help entry for Application.Run().
Basically you want a console applcation with a few changes.
Here's an example of how to get started, using a default aboutbox class:
using System;
using System.Windows.Forms;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
if (args.Length == 0)
{
Console.WriteLine("No Arguments");
}
else
{
if (args[0] == "a")
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new AboutBox1());
}
}
}
}
}
And AboutBox1 class:
using System.Reflection;
using System.Windows.Forms;
namespace ConsoleApplication1
{
partial class AboutBox1 : Form
{
public AboutBox1()
{
InitializeComponent();
this.Text = String.Format("About {0} {0}", AssemblyTitle);
this.labelProductName.Text = AssemblyProduct;
this.labelVersion.Text = String.Format("Version {0} {0}", AssemblyVersion);
this.labelCopyright.Text = AssemblyCopyright;
this.labelCompanyName.Text = AssemblyCompany;
this.textBoxDescription.Text = AssemblyDescription;
}
#region Assembly Attribute Accessors
public string AssemblyTitle
{
get
{
object[] attributes = Assembly.GetExecutingAssembly().GetCustomAttributes(typeof(AssemblyTitleAttribute), false);
if (attributes.Length > 0)
{
AssemblyTitleAttribute titleAttribute = (AssemblyTitleAttribute)attributes[0];
if (titleAttribute.Title != "")
{
return titleAttribute.Title;
}
}
return System.IO.Path.GetFileNameWithoutExtension(Assembly.GetExecutingAssembly().CodeBase);
}
}
public string AssemblyVersion
{
get
{
return Assembly.GetExecutingAssembly().GetName().Version.ToString();
}
}
public string AssemblyDescription
{
get
{
object[] attributes = Assembly.GetExecutingAssembly().GetCustomAttributes(typeof(AssemblyDescriptionAttribute), false);
if (attributes.Length == 0)
{
return "";
}
return ((AssemblyDescriptionAttribute)attributes[0]).Description;
}
}
public string AssemblyProduct
{
get
{
object[] attributes = Assembly.GetExecutingAssembly().GetCustomAttributes(typeof(AssemblyProductAttribute), false);
if (attributes.Length == 0)
{
return "";
}
return ((AssemblyProductAttribute)attributes[0]).Product;
}
}
public string AssemblyCopyright
{
get
{
object[] attributes = Assembly.GetExecutingAssembly().GetCustomAttributes(typeof(AssemblyCopyrightAttribute), false);
if (attributes.Length == 0)
{
return "";
}
return ((AssemblyCopyrightAttribute)attributes[0]).Copyright;
}
}
public string AssemblyCompany
{
get
{
object[] attributes = Assembly.GetExecutingAssembly().GetCustomAttributes(typeof(AssemblyCompanyAttribute), false);
if (attributes.Length == 0)
{
return "";
}
return ((AssemblyCompanyAttribute)attributes[0]).Company;
}
}
#endregion
private void okButton_Click(object sender, EventArgs e)
{
Close();
}
}
}
I found a neat and simple to implement solution using the example in my question provided by microsoft.
I created this application context class that is responsible for everything in the application and I use this instead of a form in the Application.Run() as shown below.
To achieve the behavior in the question, I am using a second form that is hidden and only the taskbar icon is shown. If the user wants to see how the process is doing, they can click the taskbar icon and see the logging window, which is actually the ConfigurationApplierForm in the example bellow.
class AnApplicationContext: ApplicationContext
{
private Form _currentForm;
Note the constructor is private, the main is inside this class and declared static.
private AnApplicationContext()
{
Application.ApplicationExit += new EventHandler(this.OnApplicationExit);
// choose which form to show based on arguments
if(Environment.GetCommandLineArgs().Contains("-apply"))
{
_currentForm = new ConfigurationApplierForm();
}
else
{
_currentForm = new ConfigurationActionManagerForm();
}
// initialize the form and attach event handlers
_currentForm.FormClosed += new FormClosedEventHandler(this.OnCurrentFormClosed);
_currentForm.ShowDialog();
}
Main is here, a little bit different from the original. Notice the argument in the Run method
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
// context is passed instead of a form
Application.Run(new AnApplicationContext());
}
private void OnCurrentFormClosed(object sender, EventArgs e)
{
ExitThread();
}
private void OnApplicationExit(object sender, EventArgs e)
{
/* is there anything to do when all forms are closed
and the application is going to die?*/
}
}
Also, we need to tell the project that this is the startup project.
Project Properties -> Application -> Startup Project

How can I make sure only one WPF Window is open at a time?

I have a WPF window that I am launching from inside of a winform app. I only want to allow once instance of that WPF window to be open at a time, and not warn that user if they try to open it again.
I am having a problem however trying to search for that WPF window being open because the window is being launched from a winform. What I normaly do is when searching for a winform, I search for any instances of that winform existing in the Application.Current.OpenForms, and when in WPF I search for Application.Current.Windows
The problem I have is that System.Windows.Application.Current is null when launched from inside of a winform, so I can't search for the WPF window that way. Is there any better way of searching for an existing instance of an open window?
My Code:
if (System.Windows.Application.Current != null)
{
foreach (System.Windows.Window win in System.Windows.Application.Current.Windows)
{
if (win is frmCaseWpf)
{
MessageBox.Show("You may have only one active case open at a time.", "Open Case",
MessageBoxButtons.OK,
MessageBoxIcon.Stop);
win.WindowState = System.Windows.WindowState.Normal;
win.Focus();
win.Activate();
return;
}
}
}
Instead of searching the static application objects, you could instead just track this within your window, with a single static variable. Just keep a variable in the window:
private static frmCaseWpf openWindow = null; // Assuming your class name is frmCaseWpf
When you create a window, either in the initialize routines, or OnLoaded, depending on how you want it to work..:
partial class frmCaseWpf {
public frmCaseWpf {
this.OnLoaded += frmCaseWpf_OnLoaded;
}
private void frmCaseWpf_OnLoaded(object sender, RoutedEventArgs e)
{
if (this.openWindow != null)
{
// Show message box, active this.openWindow, close this
}
this.openWindow = this;
}
}
If you want this window to be reusable, make sure to set this.openWindow = null; when you close the window, as well.
Here's something that's working for me.
private About aboutWin;
private void AboutOpenClicked(object sender, RoutedEventArgs e)
{
if(aboutWin == null)
{
aboutWin = new About();
aboutWin.Closed += (a, b) => aboutWin = null;
aboutWin.Show();
}
else
{
aboutWin.Show();
}
}
It would be better make the frmCaseWpf class a singleton. That way you can't create another instance
Rather than try to search for a Window instance, many people use a session- (or system-) wide "Mutex" or a Mutual Exclusion lock. I was going to rewrite one for you, but I found a good codeproject article demonstrating the technique. It's not complex and very simple.
http://www.codeproject.com/KB/cs/SingleInstanceAppMutex.aspx?msg=2908697
Sneak peek:
[STAThread]
static void Main()
{
bool onlyInstance = false;
Mutex mutex = new Mutex(true, "UniqueApplicationName", out onlyInstance);
if (!onlyInstance) {
return;
}
Application.Run(new MainForm);
GC.KeepAlive(mutex);
}
Hope this helps.
(edit: of course you'll have to modify this slightly for your particular use-case, but it demos the general idea)
I am not really a 'proper' programmer, however I have achieved this in a WPF application (not from a winforms one) by using the following:
Dim wdwDetails As New detailsNew()
Private Sub openNewDetails(ByVal recordID As String)
wdwDetails.Owner = Me
wdwDetails.recordID = recordID
wdwDetails.WindowStartupLocation = Windows.WindowStartupLocation.CenterOwner
wdwDetails.Show()
End Sub
Essentially because I am creating the window object outside of the sub that opens it, there will only be a single window. Any new call to the window open sub will use the same object. But I guess that is what Thomas is referring to also.
Like I said, not sure if this will help you or not though.
You can use XXXwindown.isLoad to check if window is loaded before you create a new window:
if ( !ChildWindow.IsLoaded)
{
childWindow= new ChildWindow();
childWindow.Show();
}

Categories

Resources