Why Window.ShowDialog runs the application? - c#

I try to open dialog window before the runnig wpf application:
public class Program
{
[STAThread]
public static void Main(string[] args)
{
var app = new App();
var win = new MainWindow();
if (win.ShowDialog().GetValueOrDefault())
{
app.Run();
}
}
}
class App : Application
{
protected override void OnStartup(StartupEventArgs e)
{
base.OnStartup(e);
var win = new Window1();
win.Show();
}
}
Why does win.ShowDialog() run the app (app.OnStartup is executed)?
But, win.Show() doesn't run the app
[STAThread]
public static void Main(string[] args)
{
var app = new App();
var win = new MainWindow();
win.Show();
app.Run();
}
Why is this behavior???
Thanks

ShowDialog starts its own message loop. It does almost the same thing as Application.Run, and since you already created an instance of the application, the startup message (well, dispatch) has already been sent, and will be interpreted by the message loop (dispatcher) in ShowDialog. Show basically only sends a message to the queue, so it doesn't do anything unless there's a message loop processing the messages.
If you want to show a dialog before the startup is registered, don't create the application instance before showing the dialog.

Related

Launching a WPF window from a Console application

I'm trying to use a WPF window as a message popup that will close once a task has been performed. All the documentation I've seen says that this can't be done with a messageBox, that's why I'm going with the WPF. I found one code snip that allowed me to open the WPF window but it wouldn't progress the application to the next process. Below is the last code example I found that I thought showed promise but the window isn't opening -
[STAThread]
static void Main(string[] args)
{
try
{
string filePath = "my new directory";
var popup = new PopupTest();
popup.Dispatcher.BeginInvoke
(System.Windows.Threading.DispatcherPriority.Normal,
(Action)(() =>
{
popup.Show();
}));
// Do some console application stuff
do
{
Directory.CreateDirectory(filePath);
} while (!Directory.Exists(filePath));
popup.Close();
}
catch (Exception e)
{
Console.WriteLine(e.Message);
Console.WriteLine(e.StackTrace);
}
}
}
The cs.xaml file is just the default
/// Interaction logic for PopupTest.xaml
/// </summary>
public partial class PopupTest : Window
{
public PopupTest()
{
InitializeComponent();
}
}
I feel like this should be simpler than I'm making it. Anything that can point me in the right direction is appreciated.
You need to reference the WPF assemblies and create and run a System.Windows.Application on the STA thread:
[STAThread]
static void Main(string[] args)
{
var app = new System.Windows.Application();
app.Run(new PopupTest());
}
The Run method blocks and doesn't return until the app is shut down.
If you want to do some stuff while the app is running, you need to do this on another thread:
[STAThread]
static async Task Main(string[] args)
{
Task t = Task.Run(() =>
{
string filePath = "my new directory";
do
{
Directory.CreateDirectory(filePath);
} while (!Directory.Exists(filePath));
});
var app = new System.Windows.Application();
app.Run(new MainWindow());
await t;
}

My custom Windows Service not working with Windows Message Queue

The windows service i coded is not working:
Intended funcionality: The service is supposed to receive messages from Windows Message Queue (MSMQ) and write the messages on .txt files.
It works when I run it not-as-a-service (directly from visual studio)
When I installed it as a service i can start it, but it doesn't do anything, not creating/writing .txt files anywhere
(I know it isn't writing the files elsewhere because when I run the program from VS the messages are still in the queue, so they weren't taken out by the service)
The difference between running it as a service and running it from visual studio is the next:
namespace ComponentAtrapador
{
static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
static void Main()
{
#if DEBUG
Service1 myService = new Service1();
myService.startMethod();
System.Threading.Thread.Sleep(System.Threading.Timeout.Infinite);
#else
ServiceBase[] ServicesToRun;
ServicesToRun = new ServiceBase[]
{
new Service1()
};
ServiceBase.Run(ServicesToRun);
#endif
}
}
}
(so if i run it as DEBUG it will run without me having to install it as a service)
Here's the service's code:
namespace ComponentAtrapador
{
public partial class Service1 : ServiceBase
{
private System.Timers.Timer _timer;
private System.ComponentModel.IContainer components1;
private System.Diagnostics.EventLog eventLog1;
public void startMethod()
{
OnStart(null);
}
public Service1()
{
InitializeComponent();
eventLog1 = new System.Diagnostics.EventLog();
if (!System.Diagnostics.EventLog.SourceExists("MySource"))
{
System.Diagnostics.EventLog.CreateEventSource(
"MySource", "MyNewLog");
}
eventLog1.Source = "MySource";
eventLog1.Log = "MyNewLog";
}
protected override void OnStart(string[] args)
{
eventLog1.WriteEntry("In OnStart");
_timer = new System.Timers.Timer();
_timer.Interval = 5000; // 5 seconds
_timer.Elapsed += new System.Timers.ElapsedEventHandler(this.OnTimer);
_timer.Start();
}
protected override void OnStop()
{
_timer.Stop();
}
public void OnTimer(object sender, System.Timers.ElapsedEventArgs args)
{
string nombreArchivo = "archivoMensaje";
MessageQueue messageQueue = new MessageQueue(#".\Private$\SomeTestName");
System.Messaging.Message[] messages = messageQueue.GetAllMessages();
System.Messaging.Message m = new System.Messaging.Message();
foreach (System.Messaging.Message message in messages)
{
message.Formatter = new XmlMessageFormatter(new String[] { "System.String,mscorlib" });
string text = message.Body.ToString();
System.IO.File.WriteAllText(AppDomain.CurrentDomain.BaseDirectory + nombreArchivo + Properties.Settings.Default.SettingNumero + ".txt", text);
Properties.Settings.Default.SettingNumero++;
Properties.Settings.Default.Save();
//Do something with the message.
}
// after all processing, delete all the messages
messageQueue.Purge();
//}
}
}
}
That is where Logs are so helpful, put couple of eventLog1.WriteEntry() inside your OnTimer method and you will see where is it failing.
I would check
how many messages I am getting.
I will put one eventLog1.WriteEntry() inside loop to see what is happening with each message etc...
Turns out the service didn't have enough permissions, fixed it by setting the serviceProcessInstaller of the service on visual studio to User, so that when i installed it it'd ask for credentials. Just had to type "./[username]" when it asked for my username for it to work.
Another way of fixing it would be going into the task manager > services > right click service > properties > security. And change the permissions there.

Splash Screen with Login

I am trying to implement a splash screen similar to that which solved the issue
Splash Screen waiting until thread finishes.
In my case I do not need threads. I want a login prompt once the DefineAlternateFrm constructor completes. Without the login, it works fine: once the constructor in defineAlternateFrm is done, the form is shown.
Adding a login form, it behaves differently: the login form prompt appears before the constructor of defineAlternateFrm is done. Weird, since there are no threads so I was expecting the prompt once the call for instantiating defineAlternateFrm is done. Then if the login succeed, it will show defineAlternateFrm.
My Code:
static class Program
{
[STAThread]
static void Main(string[] args)
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
new MyApp().Run(args);
}
}
class MyApp : WindowsFormsApplicationBase
{
protected override void OnCreateSplashScreen()
{
this.SplashScreen = new SplashScreen();
}
protected override void OnCreateMainForm()
{
var defineAlternateFrm = new DefineAlternateFrm(); // some works done
var login = new LoginFrm();
login.ShowDialog();
// Then create the main form, the splash screen will close automatically
this.MainForm = defineAlternateFrm ;
}
}

WPF, how to make a single instance and shows the MainWindow when another instance is launched in c#

As the title state, I want to make a single instance program and show MainWindow when another instance is launched.
I have acheived showing message that only one instance is allowed.
public class MyApplication
{
static Mutex mutex = new Mutex(true, "FirstInstance");
[STAThread]
public static void Main(string[] args)
{
if (mutex.WaitOne(TimeSpan.Zero, true))
{
App app = new App();
app.InitializeComponent();
app.Run();
}
else
{
MessageBox.Show("only one instance at a time");
}
}
}
This works fine but I want to show MainWindow rather than a message, so I tried with
static Application app;//change app to static
if (mutex.WaitOne(TimeSpan.Zero, true))
{
app = new App();
app.InitializeComponent();
app.Run();
}
else
{
app.MainWindow.WindowState = WindowState.Normal;
}
I get "System.NullReferenceException: Object reference not set to an instance of an object". It seems MainWindow in app(which is static) is null which I don't get why.
So I tried this article http://sanity-free.org/143/csharp_dotnet_single_instance_application.html
But WndProc method doesn't exist in WPF.
I'd appreciate if you can help me.
Thanks!
I created a sample WPF app and only changed the App.xaml.cs file. If the single-instance window is already open, this code will find any process that matches the name of the current process, and if that process has a window, shows it:
public partial class App : Application
{
// signals to restore the window to its normal state
private const int SW_SHOWNORMAL = 1;
// create the mutex
private const string MUTEXNAME = "FirstInstance";
private readonly Mutex _mutex = new Mutex(true, MUTEXNAME);
public App()
{
if (!_mutex.WaitOne(TimeSpan.Zero))
{
ShowExistingWindow();
Shutdown();
}
}
[DllImport("User32.dll")]
private static extern bool SetForegroundWindow(IntPtr hWnd);
[DllImport("user32.dll")]
private static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);
// shows the window of the single-instance that is already open
private void ShowExistingWindow()
{
var currentProcess = Process.GetCurrentProcess();
var processes = Process.GetProcessesByName(currentProcess.ProcessName);
foreach (var process in processes)
{
// the single-instance already open should have a MainWindowHandle
if (process.MainWindowHandle != IntPtr.Zero)
{
// restores the window in case it was minimized
ShowWindow(process.MainWindowHandle, SW_SHOWNORMAL);
// brings the window to the foreground
SetForegroundWindow(process.MainWindowHandle);
return;
}
}
}
}
FYI, this does not work in debug mode because .vshost becomes part of the process name. If you need it to work in debug mode, you need to iterate through all processes instead of calling Process.GetProcessesByName.
If I havent misunderstood your question try something like this
[STAThread]
public static void Main(string[] args)
{
Task task = new Task(() => { Thread.Sleep(200); MessageBox.Show("what a marvelous engineering"); });
task.Start();
//If you want application not to run untill task is complete then just use wait
task.Wait();
App app = new App();
app.InitializeComponent();
app.Run();
}
But I am wondering if you want your C# work done before the your MainWindow instantiate why dont you just do your other wor just before App app=new App() and let the code run sequentially.

c# register commandline argument don't start new instance

Application c:\pinkPanther.exe is running and it is application i wrote in c#.
Some other application starts c:\pinkPanther.exe purpleAligator greenGazelle OrangeOrangutan and i would like not to start new instance of c:\pinkPanther.exe with these arguments, but to currently running c:\pinkPanther.exe register it and react to it somehow.
How to do it?
EDIT!!!: i'm very sorry about pinkPanther.exe and ruzovyJeliman.exe that caused the confusion - i translated question from my native language and missed it :(
This is assuming your application is a WinForms app, as that will make it easier to keep it open. This is a very simple example, but it will show you the basics:
Add a reference to Microsoft.VisualBasic.
Create an Application class inheriting from WindowsFormsApplicationBase. This base class contains built-in mechanisms for creating a single-instance application and responding to repeated calls on the commandline with new arguments:
using Microsoft.VisualBasic.ApplicationServices;
//omitted namespace
public class MyApp : WindowsFormsApplicationBase {
private static MyApp _myapp;
public static void Run( Form startupform ) {
_myapp = new MyApp( startupform );
_myapp.StartupNextInstance += new Microsoft.VisualBasic.ApplicationServices.StartupNextInstanceEventHandler( _myapp_StartupNextInstance );
_myapp.Run( Environment.GetCommandLineArgs() );
}
static void _myapp_StartupNextInstance( object sender, Microsoft.VisualBasic.ApplicationServices.StartupNextInstanceEventArgs e ) {
//e.CommandLine contains the new commandline arguments
// this is where you do what you want with the new commandline arguments
// if you want it the window to come to the front:
e.BringToForeground = true;
}
private MyApp( Form mainform ) {
this.IsSingleInstance = true;
this.MainForm = mainform;
}
}
All you have to change in Main() is call Run() on your new class rather than Application.Run():
static class Program {
[STAThread]
static void Main() {
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault( false );
MyApp.Run( new MyMainForm() );
}
}
WindowsFormsApplicationBase has some other capabilities you can explore, as well.
To communicate with the other instance of the application, you need some sort of inter-process communication. Apparently, WCF is the recommended form of IPC in .Net. You can do that with code like this (using WPF, but WinForms would be similar):
[ServiceContract]
public interface ISingletonProgram
{
[OperationContract]
void CallWithArguments(string[] args);
}
class SingletonProgram : ISingletonProgram
{
public void CallWithArguments(string[] args)
{
// handle the arguments somehow
}
}
public partial class App : Application
{
private readonly Mutex m_mutex;
private ServiceHost m_serviceHost;
private static string EndpointUri =
"net.pipe://localhost/RuzovyJeliman/singletonProgram";
public App()
{
// find out whether other instance exists
bool createdNew;
m_mutex = new Mutex(true, "RůžovýJeliman", out createdNew);
if (!createdNew)
{
// other instance exists, call it and exit
CallService();
Shutdown();
return;
}
// other instance does not exist
// start the service to accept calls and show UI
StartService();
// show the main window here
// you can also process this instance's command line arguments
}
private static void CallService()
{
var factory = new ChannelFactory<ISingletonProgram>(
new NetNamedPipeBinding(NetNamedPipeSecurityMode.None), EndpointUri);
var singletonProgram = factory.CreateChannel();
singletonProgram.CallWithArguments(Environment.GetCommandLineArgs());
}
private void StartService()
{
m_serviceHost = new ServiceHost(typeof(SingletonProgram));
m_serviceHost.AddServiceEndpoint(
typeof(ISingletonProgram),
new NetNamedPipeBinding(NetNamedPipeSecurityMode.None),
EndpointUri);
m_serviceHost.Open();
}
protected override void OnExit(ExitEventArgs e)
{
if (m_serviceHost != null)
m_serviceHost.Close();
m_mutex.Dispose();
base.OnExit(e);
}
}

Categories

Resources