I'm currently trying to use a WPF component that makes use of Application.Current from a WPF application, however due to several reasons I never call Application.Run (nor is that an option). The result is a NullReferenceException.
I'm basically trying to display multiple instances of the same WPF window from what would be a console application.
Any advice (and code samples in C#/F#) would be welcome!
Thanks in advance
Just to offer an alternative solution.
It is possible to keep an application running without any windows open. To me this feels less 'hackish'. :) http://msdn.microsoft.com/en-us/library/system.windows.application.shutdownmode.aspx
public class AppCode : Application
{
// Entry point method
[STAThread]
public static void Main()
{
AppCode app = new AppCode();
app.ShutdownMode = ShutdownMode.OnExplicitShutdown;
app.Run();
...
app.Shutdown();
}
}
EDIT:
Ok this got a bit cumbersome. Application.Run will block, so it needs to run in its own thread.
When it does run in its own thread, any interaction between your main thread and your ui thread had best be done by Application.Current.Dispatcher.Invoke. Here is some working code, that assumes you have a class that inherits from Application. I'm using a modified App.xaml/App.xaml.cs that a WPF project template creates for you, to get nice handling of ResourceDictionaries for free.
public class Program
{
// Entry point method
[STAThread]
public static void Main()
{
var thread = new System.Threading.Thread(CreateApp);
thread.SetApartmentState(System.Threading.ApartmentState.STA);
thread.Start();
// This is kinda shoddy, but the thread needs some time
// before we can invoke anything on the dispatcher
System.Threading.Thread.Sleep(100);
// In order to get input from the user, display a
// dialog and return the result on the dispatcher
var result = (int)Application.Current.Dispatcher.Invoke(new Func<int>(() =>
{
var win = new MainWindow();
win.ShowDialog();
return 10;
}), null);
// Show something to the user without waiting for a result
Application.Current.Dispatcher.Invoke(new Action(() =>
{
var win = new MainWindow();
win.ShowDialog();
}), null);
System.Console.WriteLine("result" + result);
System.Console.ReadLine();
// This doesn't really seem necessary
Application.Current.Dispatcher.InvokeShutdown();
}
private static void CreateApp()
{
App app = new App();
app.ShutdownMode = ShutdownMode.OnExplicitShutdown;
app.Run();
}
}
The following is the intended behavior of Application class:
The first open window is the MainWindow.
The only window in the list becomes the MainWindow (if others are to
be removed).
Application Class is designed to exit if no windows are present in
windows list.
Check this link.
So basically you cannot run an Application, without any window open. Keep a window open but hidden.
If I have misunderstood your problem, then perhaps the following similar cases might help:
Managing Application Resources when WPF is Hosted.
When running unit tests in Visual Studio 2008
Related
Before I start, I'd like to appologize for any... idiocy... that I may show when asking this question, I'm trying to learn C# after coming from Java, and just wanted to jump right into it!
I'm working on a project that is designed to take commands through the console, such as "play batman begins" and it'll start playing the movie Batman Begins. It also takes commands for music, etc. With this setup, my goal is to have it voice controlled, so I'm not really concerned with using a GUI instead of the console. When I have the program play a movie, it loads up a GUI window with no border, no content, and the constructor that it uses is:
public MainWindow(MediaPlayer player)
{
InitializeComponent();
VideoDrawing drawing = new VideoDrawing { Rect = new Rect(0, 0, 800, 600), Player = player };
DrawingBrush brush = new DrawingBrush(drawing);
Background = brush;
}
The MediaPlayer is controlled from the main function (for now). My code to load the video and run it is:
MediaPlayer mp = new MediaPlayer();
mp.Open(new Uri("C:\\test.mp4", UriKind.RelativeOrAbsolute));
VideoDrawing vidDrawing = new VideoDrawing();
vidDrawing.Rect = new Rect(0, 0, 100, 100);
vidDrawing.Player = mp;
DrawingBrush DBrush = new DrawingBrush(vidDrawing);
videoPanel = new MainWindow(mp); // GUI panel to play the video on, constructor is listed above
play();
new System.Windows.Application().Run(videoPanel);
As I'm new to C# and all, the way I got the GUI to work with this is by starting a new WPF project, creating the GUI and writing the code, then copy paste the xaml and cs files into my project (cause I'm a noob, I'm sorry). MAYBE this is causing the problem.
This code works (mostly) fine. When I run my program, it loads the video file, opens the Window, and plays the video on the screen while playing the sound too. However, when it starts the video, the GUI "hangs" and doesnt accept any input's OR outputs, but it's not frozen as the cursor is still flashing. I'm not sure why this is.
I've tried threading almost anything I can think of, but I get errors with that. I've tried localizing the loading to the GUI window itself, however it still hangs the console. I've been searching online for all sorts of things for the past few days and cant find a solution, so I turned here!
My program has a lot more classes and stuff going on, so I had to throw all this stuff together, and double check, so if I'm missing something or made a stupid please let me know and I can fix it. As I'm still kinda new to C# (but not new to programming) I may have missed something in my question details as well.
I'm wondering if the solution is to make it ALL GUI based, instead of hybrid console and GUI? Because of the information I've found online it looks like there can be some annoying... discrepancies... between the two types of threads?
Anyway, any help would be great, I've spent the past 3 days trying to debug this and haven't made any progress. If it helps, there's a link to the repo here! Thanks :)
EDIT: I made some changes while waiting for a response, primarily changing the way it draws to the GUI. Originally I had it painting to the background, but now have made it handle through a MediaElement. This is the whole class for my window now:
public partial class MainWindow : Window
{
public MainWindow(string dir)
{
InitializeComponent();
video.Source = new Uri(dir); //video is the name of my MediaElement
}
public void pause(){
video.Pause();
}
public void resume()
{
video.Play();
}
public void stop()
{
video.Stop();
this.Close();
}
public void volume(int i)
{
video.Volume = i;
}
}
This did NOT fix the console Hang, however this made everything much more centralized so as to make debugging easier. Hope this may help!
Consider converting this to a WPF-application, it will make things easier.
Anyway, you can still work with GUI without locking console, but you must execute GUI-related stuff on a separate dedicated STA thread. Since you are using WPF, this helper should be useful (this code is not production-quality, but works):
static class UIThread
{
private static Dispatcher _dispatcher;
public static void Start()
{
using(var wh = new ManualResetEvent(false))
{
var thread = new Thread(ThreadProc)
{
IsBackground = true,
};
thread.SetApartmentState(ApartmentState.STA);
thread.Start(wh);
wh.WaitOne();
}
}
private static void ThreadProc(object arg)
{
var wh = (EventWaitHandle)arg;
_dispatcher = Dispatcher.CurrentDispatcher;
wh.Set();
Dispatcher.Run();
}
public static Dispatcher Dispatcher
{
get { return _dispatcher; }
}
}
This helper provides you with a reference to a Dispatcher object, which is used to execute methods on UI thread.
All communication with UI thread should be done through Dispatcher.Invoke() or Dispatcher.BeginInvoke() methods. Note that since we now have several threads, MediaPlayer objects must be created on the UI thread. You can still hold it's reference on any thread you want, but any method calls to MediaPlayer object must go through Dispatcher.
Things to change:
add a UIThread.Start(); call before any attempts to use Dispatcher. Beginning of Main() method is a good place to do this.
MediaPlayer objects should be created like this: mediaPlayer = UIThread.Dispatcher.Invoke(() => new Media());
any UI-related code should go to Dispatcher.Invoke() or Dispatcher.BeginInvoke(): UIThread.Dispatcher.BeginInvoke(() => playVideo(#"C:\video.avi"));
Update
Also change new System.Windows.Application().Run(videoPanel); to simple videoPanel.Show(). Application.Run() blocks until the window is closed.
I've got a mono app written in c# and executed on a Mac using "mono myapp.exe"
The app itself is a "Windows Application" when viewed from the project properties, but it doesn't always show a window. In program.cs, there is a static Main:
static void Main(string[] args) {
UserClient client = new UserClient();
client.Start(args);
}
public class UserClient {
public void Start(string[] args) {
// Talk to server, listen for instructions, etc.
....
// Launch the "Stay Alive" thread
// Just a thread that Sleeps/Loops watching for an exit command; mainly used to keep the process alive
}
}
Inside the UserClient's Start method, there is a piece of code that continuously monitors a server which gives it instructions to do things. One of the things it does is optionally displays a message using a windows form.
When the server instructs the process to display a message, it instantiates a form, displays it using frm.ShowDialog() and then after 30 seconds, a timer on the form runs Close() and the frm then gets disposed. However, when this happens, on my Mac I see an application title bar saying "mono" and a new icon on my dock bar for the mono app. After about 2 minutes the mono process in Activity Monitor shows "Not Responding." This eventually will prevent the user from logging out, shutting down, etc. (because Mac OS can't kill mono gracefully).
ON THE OTHER HAND... if the server never tells the process to display that form, everything runs fine and dandy: a dock icon never shows up (which is good!), mono title bar never shows up and the mono process continues to run happily, not preventing the system from shutting down or rebooting.
Anyone experienced this or have ideas on what's causing it? My guess is that it's a new GUI thread being created by the form which isn't ever being shutdown and is somehow causing a lockup, though I'm unsure of how to handle it.
Thanks for any suggestions.
Update:
Here's some code to easily reproduce and see this happening. I realize that this seems kind of "non-standard." Having said that, the below works perfectly in a Windows environment and provides the desired result of not showing an icon in the task area except when showing a message. Currently, using Application.Run and simply doing frm.ShowDialog() produce exactly the same result.
In the end what we need is to be able to display the form, then destroy the form and any associated icon from the dock. I suspect the GUI is starting a thread which isn't ever being disposed, which is why the dock icon remains. Is there a way to make sure the GUI thread is taken care of?
static class Program {
static void Main() {
StartupClass s = new StartupClass();
s.start();
}
}
public class StartupClass {
Thread stayAliveThread;
public void start() {
// Stay alive thread
stayAliveThread = new Thread(stayAliveLoop);
stayAliveThread.Start();
// This shows a form and would normally be used to display temporary and brief messages to the user. Close the message and you'll see the undesired functionality.
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Form1());
Application.Exit();
Application.ExitThread();
}
/// <summary>
/// Keep the app alive.
/// </summary>
private void stayAliveLoop() {
while (true) {
Thread.Sleep(10000);
// In the real project this method monitors the server and performs other tasks, only sometimes displaying a message.
}
}
}
I feel I'm missing several things. Most notably
[STAThread]
static void Main(string[] args) { //....
Also see this answer: Windows Forms and ShowDialog problem
I can't see anything like initializing message loop for windowed application. I.e. in windows forms case something like Application.Run(). If you do not have it, no wonder application freezes. In any case, posting more code could be helpful, as stated in comment.
In the end, I couldn't resolve this. I created a process that launched another app which displayed the message form. Not really a true answer, but the solution I had to go with.
I have a console project, but now I need to put an user interface on. So I'm using the 3 tier model (presentation, business, access data).
In my method Main() I call to presentation layer (like app in Window form or Wpf), so, in the presentation layer is the interaction with user through CONSOLE.
Now I add a window called "UserInterface.xaml" in the presentation layer to use instead of console. Because should be with INTERFACE not console.
I have observed that in MainWindow the called is with MainWindow.Show();
But I don't know how to call my "UserInterface.xaml", because has no .Show() method.
This is my method Main:
public static void Main()
{
MainWindow.Show(); // THIS IS WITH MainWindow.xaml
UserInterface.??? // THIS IS MY CASE WITH UserInterface.xaml
}
So can somebody tell me how I can call my window from the Main method??
You definitely got started with the wrong project template. To make a WPF window visible and interactive, you have to follow the rules for a UI thread. Which includes marking the main thread of your app as an STA thread and pumping a message loop. Like this:
class Program {
[STAThread]
public static void Main() {
var app = new Application();
app.Run(new MainWindow());
}
}
Beware that Application.Run() is a blocking call, it will not return until the user closes the main window. This is a rather inevitable consequence of the way Windows works.
Assuming UserInterface is really a window, this should work:
var window = new UserInterface();
window.Show();
I want to show windows of another application if it is hidden. More specifically, I want to show the main window of already launched application if the user tries to launch it again. I've already implemented monitoring of duplicate application launches. Tried to do as in here but failed. Thinking of doing it using remoting, but I understand that this is not the best practice, although I won't need to bother with Windows API in that case.
That's a pretty hackish way of doing things. I'd advise using named pipes (System.IO.Pipes) to signal the first copy of your app. The first copy, upon receiving the signal, will activate the window itself. And no worries about any permissions either.
Another pretty easy way to do it is using a Windows Event, represented in .NET as the System.Threading.EventWaitHandle class.
Create a thread in the application, that all it does is wait on a named event. When the event is signalled, this thread will use Form.BeginInvoke to make the main window appear, and go back to wait on the event.
From the new instance of the application, you will only have to signal the event.
This requires a little less work than using pipes.
Note that either way (using pipes, windows, or events), you always have to deal with permissions.
For example, if UAC is enabled, and the existing application instance is running as admin, the new instance may not be able to send it the message to show the window, unless you made sure to set the proper permissions (e.g. on the pipe or the event, whatever your method is) in advance.
I've already implemented it using remoting, but I'll consider other ways of doing this when I have more free time. Here's how I did it:
In the form class we have:
public Main()
{
InitializeComponent();
this.ShowFromFormShower = new FormShower.ShowFromFormShowerDelegate(this.ShowFromFormShower1);
FormShower.Register(this);
}
private void ShowFromFormShower1()
{
this.Show();
this.WindowState = FormWindowState.Normal;
this.BringToFront();
}
public PKW.FormShower.ShowFromFormShowerDelegate ShowFromFormShower;
Also a remoting class needs to be created:
public class FormShower : MarshalByRefObject
{
/// <summary>
/// For remote calls.
/// </summary>
public void Show()
{
if (FormShower.m == null)
throw new ApplicationException("Could not use remoting to show Main form because the reference is not set in the FormShower class.");
else
FormShower.m.Invoke(FormShower.m.ShowFromFormShower);
}
private const int PortNumber = 12312;
private static Main m = null;
public delegate void ShowFromFormShowerDelegate();
internal static void Register(Main m)
{
if (m == null) throw new ArgumentNullException("m");
FormShower.m = m;
ChannelServices.RegisterChannel(new TcpChannel(FormShower.PortNumber), false);
RemotingConfiguration.RegisterActivatedServiceType(typeof(FormShower));
}
internal static void CallShow()
{
TcpClientChannel c = new TcpClientChannel();
ChannelServices.RegisterChannel(c, false);
RemotingConfiguration.RegisterActivatedClientType(typeof(FormShower), "tcp://localhost:"+PortNumber.ToString());
FormShower fs = new FormShower();
fs.Show();
}
}
So if the user tries to launch the application a second time the application launches FormShower.CallShow method.
We have a little C# startup appplication that users launch to run the latest version of our main C# WinForms application from a network share. It's kind of a simplified ClickOnce arrangement (our IT folks won't allow us to use ClickOnce).
The startup application exits after calling Process.Start("MainApplication.exe"), but the main application can take several seconds to display, leaving the user with a blank screen.
Is there a way that the starup application can poll the OS to find out if the main aplication is running before it exits? Or some other way to handle this?
You can use Process.WaitForInputIdle() to wait until your application enteres the Idle state.
Process appProcess = Process.Start("MainApplication.exe");
appProcess.WaitForInputIdle();
From MSDN:
...you have just started a process and
want to use its main window handle,
consider using the WaitForInputIdle
method to allow the process to finish
starting, ensuring that the main
window handle has been created
Remarks Section from Process.MainWindowHandle property.
You can call Process.GetProcessByName to see if the new process has been created. The other option would be to have your main application kill the startup application once it has finished loading.
Use Davids' suggestion or alternatively you can put a splash screen in your main application. It will be just a simple Form with an image running on a separate worker thread. Put this as the first item invoked on start up. Your app can continue initializing on the main thread & after some seconds or just before your Main app finishes initialization kill the worker thread.
One way to solve this easily is to use a global event to signal the startup application that the main app has reached a predetermined state. To do this create a named event handle in the startup application and wait for it to be signaled:
static void Main(string[] args)
{
const string globalName = "MyProgramName";//something unique
bool isNew = false;
ManualResetEvent mreExited = new ManualResetEvent(false);
EventWaitHandle mreStarted = new EventWaitHandle(false, EventResetMode.ManualReset, globalName, out isNew);
try
{
if (!isNew)//already running, just exit?
return;
//start and monitor for exit
Process pstarted = Process.Start("...");
pstarted.Exited += delegate(object o, EventArgs e) { mreExited.Set(); };
pstarted.EnableRaisingEvents = true;
int index = WaitHandle.WaitAny(new WaitHandle[] { mreExited, mreStarted });
if (index == 0)//mreExited signaled
throw new ApplicationException("Failed to start application.");
}
finally
{
mreExited.Close();
mreStarted.Close();
}
}
Then in the main program you signal the event once your ready for the startup application to quit:
static void Main(string[] args)
{
const string globalName = "MyProgramName";//same unique name
bool isNew = false;
EventWaitHandle mreStarted = new EventWaitHandle(false, EventResetMode.ManualReset, globalName, out isNew);
try
{
if (!isNew)
mreStarted.Set();
Application.Run(new Form());
}
finally
{
mreStarted.Close();
}
}
I think David's second option is the way to go here. The process may be running with no visible UI yet. So, once the main form is displayed in the second app, kill the first process. You could even, conceivably, pass the process id of the original process in via StartInfo when you start the new process.
There are many trade-offs involved in this, but you may be able to make start-up time fast enough to make this issue moot by using NGEN.
My suggestion is to put Splash Screen in your application it gives you a good feel rather than if you dont want to use Splash screen then kill the process when loading is finished. Or you can use Process.GetProcessByName()
For Splash Screen just make a Window Screen and in startup class just inherit the class from Microsoft.VisualBasic.ApplicationServices.WindowsFormsApplicationBase that gives you a method OnCreateSplashScreen() Override this method like this :-
protected override void OnCreateSplashScreen()
{
base.OnCreateSplashScreen();
//yourSplashScreen is the screen you made as a window form either it would be a image or form
SplashScreen = yourSplashScreen();
}
Thanks ...Saurabh Singh Happy To Code