Start WPF Application in Console Application - c#

Is it possible to start WPF Application in Console mode?
public partial class App : Application
{
public App()
{
InitializeComponent();
}
}
<Application x:Class="WPF.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
</Application>
[STAThread]
static void Main(string[] args)
{
if (args.Length > 0)
{
switch (args[0].ToLower())
{
case "/g": RunApplication(); break;
}
}
}
private static void RunApplication()
{
var application = new System.Windows.Application();
application.Run(new App());
}
It will show Argument type 'WPF.app' is not assignable to parameter type 'System.Windows.Window'.
Any solution to work around it??
Any different between
1.public partial class App : Application
2.public partial class App : Window

You could declare a Window and then start your app this way:
var application = new System.Windows.Application();
application.Run(new Window());
EDIT:
You seem a bit confused, so let me explain:
Say you have a program:
using System;
namespace ConsoleApplication
{
class Program
{
[STAThread]
static void Main(string[] args)
{
RunApplication();
}
private static void RunApplication()
{
var application = new System.Windows.Application();
application.Run();
}
}
}
This will run a WPF application with no Window.
If, on the other hand, you pass a Window into application.Run(), you will get a WPF window. App should not derive from Window, since it should derive from Application.
Application.Run method either takes no arguments or a Window. It does not take Application. Therefore, if you want to start a previously created Application, as you have over there, you should do something like this:
private static void RunApplication()
{
var application = new App();
application.Run(); // add Window if you want a window.
}
Lastly, if you want to just use application.Run() and not have to pass a specific Window, just declare a starting Window in your Application XAML using StartupUri:
<Application x:Class="WPF.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
StartupUri="SomeWindow.xaml">
</Application>

Related

c#, Open a specific windows form from a parameter outside the executable

I am new to c# and .net app development. Currently I built small windows form project. This project has multiple '.cs' forms. I complied the project to an executable and call it from a .net application with the command below. Everything works fine.
System.Diagnostics.Process.Start("C:\Users\WEI\Desktop\Release\DepartmentManagement.exe");
I have a new requirement to open a specific form dynamically when the executable is run. I hard coded the form I want to open by default inside "Program.cs" like below. In this example below I hard coded it to open "ProductionSystem" form by default. I want to make that dynamic.
namespace TestWinform
{
static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new ProductionSystem());
}
}
}
I want to pass a value to the executable while executing the app. If for example I want to open the form "ProductionDowntime.cs" by default not the "ProductionSystem" then I would like to pass 'ProductionDowntime' as parameter basically making it dynamic.
System.Diagnostics.Process.Start("C:\Users\WEIRepService\Desktop\Release\DepartmentDowntime.exe 'ProductionDowntime' ");
I want to control this from outside the executable(not from within). Please help. Thanks in advance.
Try it with a factory method that would encapsulate form instantiating logic
static class Program
{
static Form CreateFormToOpen(string formName)
{
switch (formName)
{
case "ProductionDowntime":
return new ProductionDowntime();
// insert here as many case clauses as many different forms you need to open on startup
default:
return new ProductionSystem(); // ProductionSystem is a default form to open
}
}
[STAThread]
static void Main(string[] args)
{
string formName = args.Length > 0 ? args[0] : null; // extract form name from command line parameter
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(CreateFormToOpen(formName)); // use factory method to instantiate form you need to open
}
}
}
In program.cs you can change
static void Main()
to
static void Main(string[] args)
then use whatever is in args to trigger the right form.
You'd call your program like this
System.Diagnostics.Process.Start("C:\Users\WEI\Desktop\Release\DepartmentManagement.exe TriggerForm1");
where TriggerForm1 is basically the string that would be available in args
using System;
using System.Windows.Forms;
namespace CommandLineParameters_47230955
{
static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main(string[] args)
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
//Application.Run(new Form1());
if (args.Length > 0)
{
switch (args[0].ToLower())
{
case "triggerform1":
Application.Run(new Form1());
break;
case "triggerform2":
Application.Run(new Form2());
break;
default:
break;
}
}
}
}
}
a piece of cake with using System.Reflection :) I did a small test based on an answer I found here which Kay Programmer has explained incredibly well
Basically you are calling the from from the form's name through its String value. That way you can assign pragmatically any value you like to it.
The "query" part is searching for the specific name of the Form by applying the String argument that we are passing into it and thus at the end using the result in order to initialize the Form for us without using its specific Class name :)
to adapt your example with it try this:
using System.Reflection; // add this ;)
namespace TestWinform
{
static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main(string[] args) // change this ;)
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
if (args.Length > 0) // check here ;)
{
var _formName = (from t in System.Reflection.Assembly.GetExecutingAssembly().GetTypes()
where t.Name.Equals(args[0])
select t.FullName).Single();
var _form = (Form) Activator.CreateInstance(Type.GetType(_formName)); // get result and cast to Form object in order to run below
if (_form != null)
_form.Show();
}
else
{
//no argument passed, no form to open ;)
}
}
}
}
Like #blaze_125 mentioned in his answer you can SWITCH / CASE if you need to send multiple form names and apply a function logic to this.
For example
static void Main(string[] args)
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
//Application.Run(new Form1());
if (args.Length > 0)
{
OpenForm(args[0]);
}
}
public static void OpenForm(string FormName)
{
var _formName = (from t in System.Reflection.Assembly.GetExecutingAssembly().GetTypes()
where t.Name.Equals(FormName)
select t.FullName).Single();
var _form = (Form)Activator.CreateInstance(Type.GetType(_formName));
if (_form != null)
_form.Show();
}

Changing a picture box visibility from C# code

So I tried to create a new form and reference it...the compiler didn't mind this but it clearly wasn't changing the visibility of my picturebox. this is how I was calling my method found in my form, FROM my c# script.
Form1 updateForm = new Form1();
updateForm.setLights();
It called the method, and seemed like it worked! Until I read a post about instancing forms, and how by creating a "new" instance of Form1, that anything referenced by my updateForm would not change what I would see on my Form1.
So what I need to do is to call the function in setLights() which is in my Form1, and get it to change the visibility of my image on that form, from my C# code. Please see below (i understand the issue of the instancing problem mentioned above, but I left it in so that hopefully it will give better insight into what I am "trying" to do :) ALSO, please keep in mind that setLightCall() is running in a separate thread. Thanks in advance!
This code is also in my main c# script, and is the main function that I use to call my threads
static void Main(string[] args)
{
Thread FormThread = new Thread(FormCall);
FormThread.Start();
Thread setLightThread = new Thread(setLightCall);
setLightThread.Start();
log4net.Config.XmlConfigurator.Configure();
StartModbusSerialRtuSlave();
}
This code is in my main C# script
public void setLightCall(Form1 parent)
{
Form1 updateForm = new Form1();
while(true)
{
updateForm.setLights();
}
}
The below code is in my form1
public void setLights()
{
Input1GreenLight.Visible = false;
}
Here is an example of what I think you are wanting to try. Note the use of Invoking and delegates to be able to access the PictureBox's Visible method. I had to add the System.Windows.Forms Namespace to the Console Application to be able to access the instance of the Form that was created in the FormThread Method, this is assuming that you only have 1 Form in your FormCollection.
Program.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Diagnostics;
using System.Windows.Forms;
namespace ConsoleApplication59
{
class Program
{
static void Main(string[] args)
{
Thread FormThread = new Thread(FormCall);
FormThread.Start();
Thread.Sleep(2000); //Sleep to allow form to be created
Thread setLightThread = new Thread(setLightCall);
setLightThread.Start(Application.OpenForms[0]); //We can get by with this because just one form
Console.ReadLine();
}
public static void setLightCall(object parent)
{
Form1 updateForm = (Form1)parent;
while (true)
{
updateForm.Invoke(updateForm.setLights, new object[] { false });
}
}
public static void FormCall()
{
Application.Run(new Form1());
}
}
}
Form1
public partial class Form1 : Form
{
public delegate void Lights(bool state);
public Lights setLights;
public Form1()
{
InitializeComponent();
setLights = new Lights(setLightsDelegate);
}
public void setLightsDelegate(bool state)
{
Input1GreenLight.Visible = state;
}
}

WPF - partial class (xaml) instantiation does not seems to occurs as expected

I have a class (code included below) that I used as my Startup class.
This class instanciate my regular partial class app.cs (app.xaml).
I thought that it was the compiler which instantiate my partial class and set parameters (defined in xaml). But it should be something else because my assertion defined in SingleInstanceApp.cs is false.
Why my assertion is false, why StartupUri is null ????????
Thanks,
Eric
Startup class:
namespace MonitorMe
{
public class SingleInstanceApp
{
[STAThread]
public static void Main(string[] args)
{
Mutex _mutexSingleInstance = new Mutex(true, "MonitorMeSingleInstance");
if (_mutexSingleInstance.WaitOne(TimeSpan.Zero, true))
{
try
{
var app = new App();
// ASSERTION HERE is FALSE ... WHY
Debug.Assert(app.StartupUri != null);
app.Run(new MainWindow());
}
finally
{
_mutexSingleInstance.ReleaseMutex();
_mutexSingleInstance.Close();
}
}
else
{
MessageBox.Show("One instance is already running.");
var processes = Process.GetProcessesByName(Assembly.GetEntryAssembly().GetName().Name);
{
if (processes.Length > 1)
{
foreach (var process in processes)
{
if (process.Id != Process.GetCurrentProcess().Id)
{
WindowHelper.SetForegroundWindow(process.MainWindowHandle);
}
}
}
}
}
}
}
}
My regular App class xaml (.cs has nothing in it):
<Application x:Class="MonitorMe.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
StartupUri="MainWindow.xaml">
<Application.Resources>
</Application.Resources>
</Application>
If you have ever looked at generated code (*.g.cs) located in obj folder for any WPF project, there will be a call to InitializeComponent - which loads the corrresponding XAML by calling LoadComponent.
Quoting a sample from the MSDN page Application Management Overview
// Create new instance of application subclass
App app = new App();
// Code to register events and set properties that were
// defined in XAML in the application definition
app.InitializeComponent();
// Start running the application
app.Run();
So, you need call InitializeComponent on app object after instantiate.
I am also adding InitializeComponent code fro app.g.cs for one of my sample apps:
[System.Diagnostics.DebuggerNonUserCodeAttribute()]
public void InitializeComponent() {
#line 4 "..\..\..\App.xaml"
this.StartupUri = new System.Uri("MainWindow.xaml", System.UriKind.Relative);
#line default
#line hidden
}

getting string from c# command line and passing it to wpf window

Very newbie question.
I want to overwrite the Main in my WPF app so if I double-click on a file, it will be loaded. My main function is:
[STAThread]
static void Main(string[] args)
{
FileConvert.App app = new FileConvert.App();
app.InitializeComponent();
if (args.Length > 0)
{
Window1 wnd1 = (Window1)(app.MainWindow);
wnd1.SetProjectFile(args[0]);
}
app.Run();
My problem is that wnd1 is null. How do I get access to this window so I can pass it the filename to load?
Thanks!
Instead of overwriting the Main method, try overriding the OnStartup method in App.xaml.cs:
public partial class App : Application
{
protected override void OnStartup(StartupEventArgs e)
{
if (e.Args.Length > 0)
((Window1) MainWindow).SetProjectFile(e.Args[0]);
}
}

Passing data to a non-static listBox, by calling function from another class

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

Categories