Custom Installer in .Net showing Form behind installer - c#

[RunInstaller(true)]
public partial class Installer1 : Installer
{
public Installer1()
{
InitializeComponent();
}
public override void Install(System.Collections.IDictionary stateSaver)
{
base.Install(stateSaver);
}
private void Installer1_AfterInstall(object sender, InstallEventArgs e)
{
Form1 topmostForm = new Form1();
topmostForm.BringToFront();
topmostForm.TopMost = true;
topmostForm.ShowDialog();
} }
I need to display the topmostForm in front of the default Windows Installer UI. The above is sample code inside my CustomAction that I am using to create a Form. Setting the TopMost property or using ShowDialog is not helping. Is there any other solution to make my form the top most and focussed?

If you want to show your own UI in the installer, you won't be able to use a setup and deployment project, because it lacks the features necessary to implement that. Consider using an installer toolkit like WiX or Inno Setup instead.
Concerning the first part of your question, are you passing the custom dialog box in the owner argument to MessageBox.Show()?

You can use form option TopMost and Focus method. But there much better way. You can get installer process, then get it window handler and then use it as parameter in ShowDialog method::
var proc = Process.GetProcessesByName("msiexec").FirstOrDefault(p => p.MainWindowTitle == "Name of product");
var formResult = proc != null
? form.ShowDialog(new WindowWrapper(proc.MainWindowHandle))
: form.ShowDialog();
WindowWrapper is something like this:
public class WindowWrapper : IWin32Window
{
private readonly IntPtr hwnd;
public IntPtr Handle {
get { return hwnd; }
}
public WindowWrapper(IntPtr handle) {
hwnd = handle;
}
}

although i'm not wuite sure what exactly you're asking for, using WiX for building windows installers is the prefered way to go. There you can build your forms and custom actions and pretty much anything else.

If you want to have complete control over installer user interface for branding or custom dialogs and don't want to use installer builder software like InstallShield then you can create a C++ application to serve as shell for Windows Installer - there is no need to implement installer actions such as copying files by yourself.
Windows Installer has API for such purpose. With function MsiSetExternalUIRecord you can provide a callback to capture installer notifications such as messages and progress updates.

Dialogs created by custom actions are always displayed behind the installation dialogs on newer Windows versions (Vista and Windows 7). This is because Windows prevents applications to move a window on top of all other windows. Think how virus popups would fill up the screen on older Windows versions.
Instead, a newly created dialog is displayed in the background and it's title bar button (if it has one) flashes.
The correct solution for what you want is creating a dialog in your MSI package and using it instead of the custom action.

Top most won't work. Simply make the form to be displayed in the custom action larger than the MSI installer form.

Try the link below,
http://social.msdn.microsoft.com/Forums/en-US/winformssetup/thread/158ad5bd-d3f7-4a21-8ebe-341e9741810a

I tried the same and I can see the form. The only different I can see is you are missing base.OnAfterInstall(savedState); in your code.
And if it still doesn't show up the try putting just MessageBox to see if your installer is hooked or not with setup project
protected override void OnAfterInstall(IDictionary savedState)
{
// message box to test
MessageBox.Show("test");
Verify topmostForm = new Verify();
topmostForm.BringToFront();
topmostForm.TopMost = true;
topmostForm.ShowDialog();
//this line is missing in your code
base.OnAfterInstall(savedState);
}

Call this.focus() in your form.OnLoad method.
That makes it show up in front of the installer. Simple fix.

Call Minimize and Restore/show methods of the form, this fix your problem.

Related

How to close app after 3 wrong login using sqlite tries in xamarin? [duplicate]

How to terminate a Xamarin application from any of the activities?
I have tried both System.Environment.Exit(0) and System.Environment.Exit(1) as well as Finish() and killing all the activities.
It still opens one blank page with default activity name and a black screen.
Is there any specific solution for this?
If you are using Xamarin.Forms create a Dependency Service.
Interface
public interface ICloseApplication
{
void closeApplication();
}
Android : Using FinishAffinity() won't restart your activity. It will simply close the application.
public class CloseApplication : ICloseApplication
{
public void closeApplication()
{
var activity = (Activity)Forms.Context;
activity.FinishAffinity();
}
}
IOS : As already suggested above.
public class CloseApplication : ICloseApplication
{
public void closeApplication()
{
Thread.CurrentThread.Abort();
}
}
UWP
public class CloseApplication : ICloseApplication
{
public void closeApplication()
{
Application.Current.Exit();
}
}
Usage in Xamarin Forms
var closer = DependencyService.Get<ICloseApplication>();
closer?.closeApplication();
A simple way to make it work cross platform is by this command:
System.Diagnostics.Process.GetCurrentProcess().CloseMainWindow();
Got it from this link.
EDIT: After using it for a while, I discovered that .CloseMainWindow() don't kill the application, only Closes it (well, thats obvious). If you want to terminate the app (kill), you shoud use the following:
System.Diagnostics.Process.GetCurrentProcess().Kill();
For Android, you can do
Android.OS.Process.KillProcess(Android.OS.Process.MyPid());
iOS explicitly does not provide any API for existing an App. Only the OS can close an App.
For iOS, you can use this code:
Thread.CurrentThread.Abort();
For Android, as #Jason mentioned here:
Android.OS.Process.KillProcess(Android.OS.Process.MyPid());
System.Environment.Exit(0);
Works for me.
In your activity, use this code
this.FinishAffinity();
I tried this code
protected override bool OnBackButtonPressed()
{
Device.BeginInvokeOnMainThread(async () =>
{
var result = await DisplayAlert("", "Would you like to exit from application?", "Yes", "No");
if (result)
{
if (Device.OS == TargetPlatform.Android)
{
Android.OS.Process.KillProcess(Android.OS.Process.MyPid());
}
else if (Device.OS == TargetPlatform.iOS)
{
Thread.CurrentThread.Abort();
}
}
});
return true;
}
In this, iOS and Android application close when a user chooses to terminate the application. Maybe it helps you.
A simple all-in-one combination of the previous answers, instead of the interface/dependency:
protected override bool OnBackButtonPressed()
{
Device.BeginInvokeOnMainThread(async () =>
{
var result = await this.DisplayAlert("Alert!", "want to exit?", "Yes", "No");
if (result)
{
#if __ANDROID__
var activity = (Android.App.Activity)Forms.Context;
activity.FinishAffinity();
#endif
#if __IOS__
Thread.CurrentThread.Abort();
#endif
}
});
return true;
}
System.Diagnostics.Process.GetCurrentProcess().CloseMainWindow();
System.Diagnostics.Process.GetCurrentProcess().Kill();
None of the methods above helped my Xamarin Android app to completely shut down. I tried to close it from Activity B, having Activity A also open under it.
A clever guy left a trick here.
First call FinishAffinity() in Activity B (closes both activities,
however, the app is still alive in the background)
Then call JavaSystem.Exit(0) to kill the background app (I think it can be replaced with Android.OS.Process.KillProcess(Android.OS.Process.MyPid()); or System.Diagnostics.Process.GetCurrentProcess().Kill();)
My method to close the app:
private void CloseBtn_Click(object sender, EventArgs e){
FinishAffinity();
JavaSystem.Exit(0);
}
As your original question mentions activities, your question is specifically for Android, you should probably update the question title with that in mind to avoid people looking for a cross-platform solution coming here.
For iOS and Android (say in Xamarin Forms) you can just throw an exception, which while being the "heavy handed" approach, will do the job:
throw new Exception();
As this isn't the best user experience and you may only want to use this for iOS because on Android, you are likely to get a system popup telling you the app crashed. However, unlike other iOS methods like calling exit(0) or calling private iOS methods like "terminateWithSuccess" via a selector, it shouldn't fail app store validation purely based on how you do it. They may still fail you because your app tries to terminate itself.
You may want to implement something different specifically for Android, in which case Jason's answer is sufficient, again if not a little on the nose i.e. using this approach may not allow your app to clean itself up:
Android.OS.Process.KillProcess(Android.OS.Process.MyPid());
Either way, you should really question why you need to provide this option. Unlike desktop applications where closing an application is needed because apps reside inside windows which by design allow multi-tasking and are not task orientated, mobile platforms are primarily designed for users to focus on one task at a time. Once the user is finished the task, they should decide to exit this task by clicking the home button, back button or change app (task) button. This really applies to all platforms.
None of these work with Android 8. They all left the app in the background.
I can prove this by pressing the close all button and the app is still there.
For my testing I used a brand new simple Android app and tried all of your answers.
Application.Quit();
I'm assuming you are using C#
Call
public void Quit ();
This will quit the application the correct way without it "crashing".

C# Add custom Windows context menu for just this program

My question is: How do I add a windows context menu item for a specific application, not globally?
Quick Brief:
We use Access (groan) for our CRM system. We use a basic 'copy to local' process for multi-access. I have written a C# 'launcher' of which handles this much better than a .bat file (they click the launcher, the launcher downloads the db, launches the db and quits). I also currently use a C# console application to handle development, automating stuff like incrementing version number, moving files around etc.
My Question/Goal:
I want to combine the two programs into one but I don't want to hinder the launcher from it's main purpose by jarring the user asking if they want to develop or not. I use this launcher too as I am primarily an estimator, hence wanting to combine the two. I have read that you can add context menu items to Windows as a whole, but I want to be able to add a launch option into the context menu just for this application. i.e. right click on program, normal menu options but with the addition of "Development Mode", this opens the program with arguments that I can use to open the development window/console instead.
Things to note:
I have played around with holding a key on start but it can be vague when to press the key. Too early - you will end up typing "r" several times into the active window, too late - and it will miss the capture point.
I have also looked at having a button on the launcher that gives you the option to go into dev mode, but the launcher is only open for around a second so its really easy to miss.
Thanks in advance
EDIT: The launcher is made and run as a click-once app.
I dont really know about whether its possible to have a custom context for a specific program, as far as i know the context works with the extension. That being said, i think there are better ways to handle your problem. Have a look at this
static void Main(string[] args)
{
/* here normal flow of the launcher*/
if (args[0] == "-dev")
{
/*here de developer mode*/
Console.WriteLine("Developer mode activated");
}
}
The way to use it is simple, you make a shorcut, and where it says the shorcut target you will have something like this "C:\Users****\Documents\visual studio 2017\Projects\Test\Test\bin\Debug\Test.exe" and you should change it to something like this "C:\Users****\Documents\visual studio 2017\Projects\Test\Test\bin\Debug\Test.exe" -dev
Further to this I stumbled upon some code to make this work. Hopefully this will help someone in the future. I am doing this in WPF, but I am sure you could probably adapt this code to work elsewhere.
1) App.xaml - Adding the JumpList action
After (not inside) the Application.Resources property add the following and change to your liking (There are a lot of properties I haven't used for development sake, check out the link to learn more):
<Application.Resources>
...
</Application.Resources>
<JumpList.JumpList>
<JumpList ShowRecentCategory="False"
ShowFrequentCategory="False">
<JumpTask Title="Open Dev Mode"
Description="Use this to enter dev mode (admins only)"
Arguments="DevMode:true"/>
</JumpList>
</JumpList.JumpList>
This will create a "Task" in the jump list:
2) Create Global static class - this will allow you to store the variable for later use in other forms.
public static class Global
{
public static Boolean DevMode = false;
}
3) App.xaml.cs - Adding OnStartup handler
Inside the App class create an override method for OnStartup
public partial class App : Application
{
protected override void OnStartup(StartupEventArgs e)
{
Global.DevMode = Boolean.Parse(e.Args.FirstOrDefault().ToString().Split(':')[1]);
}
}
4) Read the variable in your form using Global.DevMode
private void Window_ContentRendered(object sender, EventArgs e)
{
if (Global.DevMode) RunYourDevScript();
}
As per a suggestion in a comment, that has gone for some reason. I am going to revert to keypress but use shift instead or "R".
Failing this, or if it causes problems it will look at creating a global context menu item for all programs, and just won't click it when I don't need to

Visual Basic 6.0 application won't shutdown when .NET form open. Instead it displays message "Cannot Quit"

I have a Visual Basic 6.0 application that uses several components written in .NET. The application must shutdown gracefully when windows is shut down. The problem is that if the .NET part of the code is displaying a window, the application displays the message "Cannot Quit" and fails to exit. (It is then terminated by the OS.)
I've managed to reproduce this in a simplified application.
The .NET code creates a WPF window and displays it using ShowDialog():
[Guid("5F3D0B23-2196-4082-B9DE-B208C61FE89F")]
[InterfaceType(ComInterfaceType.InterfaceIsIDispatch)]
public interface IComShutdownTest
{
[DispId(1)]
void RunTest();
}
[Guid("E6613EDD-D51B-42c0-AA5B-5961AB28D063")]
[ClassInterface(ClassInterfaceType.None)]
[ProgId("ShutdownTest")]
public class ShutdownTest : IComShutdownTest
{
public ShutdownTest()
{ }
public void RunTest()
{
TestWindow testWindow = new TestWindow();
bool? dialogResult = testWindow.ShowDialog();
}
}
As you can see the .NET call blocks (and is on the GUI thread), and I suspect this may be the root of the problem, but I can't go round making all my calls non-blocking. I would have assumed that when the OS shuts down, that all of the open application windows are terminated.
The Visual Basic 6.0 application loads and displays the .NET form from a button click.
Private Sub ButtonTest_Click()
LogEventToFile "Starting"
Dim dotNetTestObject As ShutdownTest
LogEventToFile "Creating"
Set dotNetTestObject = New ShutdownTest
LogEventToFile "Running"
dotNetTestObject.RunTest
LogEventToFile "Done"
End Sub
If you attempt to shutdown the PC while the .NET form is on the screen, it fails. The "Cannot quit" message box looks like this.
To recreate this you must mark the assembly as COM visible (in file assemblyinfo.cs):
[assembly: ComVisible(true)]
and you must set the Project->Properties>Build tab to "Register for COM interop"
I also registered the compiled assembly with:
regasm ShutdownTestLibrary.dll /tlb ShutdownTestLibrary.tlb
How can I fix this problem?
If you call ShowDialog() on any window, it blocks on that thread until the window closes (from the user or from code).
You will probably have to make a method on your COM interface to close the window in .NET, or somehow get the window's handle in Visual Basic to close the window.
One of the following should solve your issue:
Make sure your .NET window has the Text/Name properties set. I know this causes issues like this sometimes.
Set the owner of the .NET window to your Visual Basic window. Use the SetParent function in user32.dll.
Hook into Microsoft.Win32.SystemEvents.SessionEnding in your .NET library and close the window.
You could try to take the parent window as parameter to the .NET method, that way the .NET component gets notified when the parent tries to close.
public void RunTest(IWin32Window owner)
{
TestWindow testWindow = new TestWindow();
bool? dialogResult = testWindow.ShowDialog(owner);
}
And in your Visual Basic 6.0 code:
Call dotNetTestObject.RunTest(Me.hWnd)

How to show form in front in C#

Folks,
Please does anyone know how to show a Form from an otherwise invisible application, and have it get the focus (i.e. appear on top of other windows)? I'm working in C# .NET 3.5.
I suspect I've taken "completely the wrong approach"... I do not Application.Run(new TheForm ()) instead I (new TheForm()).ShowModal()... The Form is basically a modal dialogue, with a few check-boxes; a text-box, and OK and Cancel Buttons. The user ticks a checkbox and types in a description (or whatever) then presses OK, the form disappears and the process reads the user-input from the Form, Disposes it, and continues processing.
This works, except when the form is show it doesn't get the focus, instead it appears behind the "host" application, until you click on it in the taskbar (or whatever). This is a most annoying behaviour, which I predict will cause many "support calls", and the existing VB6 version doesn't have this problem, so I'm going backwards in usability... and users won't accept that (and nor should they).
So... I'm starting to think I need to rethink the whole shebang... I should show the form up front, as a "normal application" and attach the remainer of the processing to the OK-button-click event. It should work, But that will take time which I don't have (I'm already over time/budget)... so first I really need to try to make the current approach work... even by quick-and-dirty methods.
So please does anyone know how to "force" a .NET 3.5 Form (by fair means or fowl) to get the focus? I'm thinking "magic" windows API calls (I know
Twilight Zone: This only appears to be an issue at work, we're I'm using Visual Studio 2008 on Windows XP SP3... I've just failed to reproduce the problem with an SSCCE (see below) at home on Visual C# 2008 on Vista Ulimate... This works fine. Huh? WTF?
Also, I'd swear that at work yesterday showed the form when I ran the EXE, but not when F5'ed (or Ctrl-F5'ed) straight from the IDE (which I just put up with)... At home the form shows fine either way. Totaly confusterpating!
It may or may not be relevant, but Visual Studio crashed-and-burned this morning when the project was running in debug mode and editing the code "on the fly"... it got stuck what I presumed was an endless loop of error messages. The error message was something about "can't debug this project because it is not the current project, or something... So I just killed it off with process explorer. It started up again fine, and even offered to recover the "lost" file, an offer which I accepted.
using System;
using System.Windows.Forms;
namespace ShowFormOnTop {
static class Program {
[STAThread]
static void Main() {
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
//Application.Run(new Form1());
Form1 frm = new Form1();
frm.ShowDialog();
}
}
}
Background: I'm porting an existing VB6 implementation to .NET... It's a "plugin" for a "client" GIS application called MapInfo. The existing client "worked invisibly" and my instructions are "to keep the new version as close as possible to the old version", which works well enough (after years of patching); it's just written in an unsupported language, so we need to port it.
About me: I'm pretty much a noob to C# and .NET generally, though I've got a bottoms wiping certificate, I have been a professional programmer for 10 years; So I sort of "know some stuff".
Any insights would be most welcome... and Thank you all for taking the time to read this far. Consiseness isn't (apparently) my forte.
Cheers. Keith.
Simply
yourForm.TopMost = true;
Form.Activate() worked in my case.
There's an overload of Form.ShowDialog() which takes an IWin32Window object. That IWin32Window is treated as the parent window for the form.
If you have the parent window as a System.Windows.Forms.Form, go ahead and just pass it. If not, get the HWND (maybe by P/Invoking to FindWindow()), and create a dummy IWin32Window implementation that just returns the HWND (More details).
You said that it works fine when you use Application.Run. Why don't you want to use Application.Run, then?
Have you tried calling BringToFront() from OnLoad or OnShown?
Activate() worked for me too.
BringToFront() did nothing in this case, I don't know why.
This is the final solution I wrote after 20 different attempts:
/* A workaround for showing a form on the foreground and with focus,
* even if it is run by a process other than the main one
*/
public static void ShowInForeground(this Form form, bool showDialog = false)
{
if (showDialog)
{
//it's an hack, thanks to http://stackoverflow.com/a/1463479/505893
form.WindowState = FormWindowState.Minimized;
form.Shown += delegate(Object sender, EventArgs e) {
((Form)sender).WindowState = FormWindowState.Normal;
};
form.ShowDialog();
}
else
{
//it's an hack, thanks to http://stackoverflow.com/a/11941579/505893
form.WindowState = FormWindowState.Minimized;
form.Show();
form.WindowState = FormWindowState.Normal;
//set focus on the first control
form.SelectNextControl(form.ActiveControl, true, true, true, true);
}
}
I've hacked this from an application I've been working on. We have a large application that loads a series of modules written by different teams. We have written one of these modules, and needed to have a login dialog open during this initialization. It was set to '.TopMost=true', but that didn't work.
It uses the WindowsFormsSynchronizationContext to open a dialog box, and then get the result of the dialog box back.
I rarely do GUI coding, and suspect this may be overkill, but it might help someone if they get stuck. I had problems with understanding how state is passed to the SendOrPostCallback, as all the examples I could find didn't use it.
Also this is taken from a working application, but I've removed several bits of code, and changed some of the details. Apologies if it doesn't compile.
public bool Dummy()
{
// create the login dialog
DummyDialogForm myDialog = new DummyDialogForm();
// How we show it depends on where we are. We might be in the main thread, or in a background thread
// (There may be better ways of doing this??)
if (SynchronizationContext.Current == null)
{
// We are in the main thread. Just display the dialog
DialogResult result = myDialog.ShowDialog();
return result == DialogResult.OK;
}
else
{
// Get the window handle of the main window of the calling process
IntPtr windowHandle = Process.GetCurrentProcess().MainWindowHandle;
if (windowHandle == IntPtr.Zero)
{
// No window displayed yet
DialogResult result = myDialog.ShowDialog();
return result == DialogResult.OK;
}
else
{
// Parent window exists on separate thread
// We want the dialog box to appear in front of the main window in the calling program
// We would like to be able to do 'myDialog.ShowDialog(windowHandleWrapper)', but that means doing something on the UI thread
object resultState = null;
WindowsFormsSynchronizationContext.Current.Send(
new SendOrPostCallback(delegate(object state) { resultState = myDialog.ShowDialog(); }), resultState);
if (resultState is DialogResult)
{
DialogResult result = (DialogResult) resultState;
return result == DialogResult.OK;
}
else
return false;
}
}
}
This did the job perfectly :
formxx.WindowState = FormWindowState.Normal;
formxx.BringToFront();
formxx.Topmost=true;
formxx.Focus();
It would appear that is behaviour is specific to XP... Hence I can't reproduce it on Vista.
http://www.gamedev.net/community/forums/topic.asp?topic_id=218484
EDIT: PS: It's past my bedtime (2 AM;-).
Thanx all for your responses... there's a "few things" I can try... I might even go into the office tomorrow to try them... Yeah, yeah... I had a life once, but I traded it for a haircut and a job ;-)
Cheers all. Keith.
I got a code in the project.
private static extern bool SetForegroundWindow(
IntPtr hWnd);
public static void ShowToFront(Form form)
{
FormWindowState oldState = form.WindowState;
form.WindowState = FormWindowState.Minimized;
form.Show();
form.Activate();
form.TopLevel = false;
form.TopLevel = true;
form.SelectNextControl(form.ActiveControl, true, true, true, true);
SetForegroundWindow(form.Handle);
form.Focus();
form.WindowState = oldState;
}
This is what I use to bring an open form that is part of my application to the front.
You can even use it with a button. But the form needs to be open or the application will break.
"YourOpenForm" has to be the name of your form from the properties window.
private void button1_Click(object sender, EventArgs e)
{
Application.OpenForms["YourOpenForm"].BringToFront();
}
Good Luck!

WPF window from a Console project?

I recently started a C# project (VS 2008) as a 'Console' project where I wrote a few libraries, test programs, etc. Now I'd like to add a couple of WPF windows, but it looks like console project won't let me do that. I'm coming from Java so this is a little strange. How can I add a WPF form (which I will instantiate my self from my "main" class?
The accepted answer is not entirely true, I'm afraid, just add the [STAThread] attribute before your mainmethod and make references to the right libraries (like System.Windows) and you're all set to add wpf windows.
EDIT : in the comments #JamesWilkins supplied me with this usefull link : http://code-phix.blogspot.be/2013/11/creating-wpf-project-from-scratch.html
I had the same question and was looking for a similar answer. I found info all over the place, so I'm putting what I found in one place. I also needed a way to hide and show the console window, so I found out this worked (for VS 2013+):
Create a new console project (be sure to select the .NET framework version you need to use - I needed to use .Net 4.0 myself). Make sure to have the following references:
PresentationFramework
PresentationCore
WindowsBase
System.xaml
Right-click on the project in the solution explorer, select
"Properties", and change the project Output Type to Windows Application.
This prevents the console window from showing on startup (if you
want that, skip this step).
While controlling the console window is not necessary in order to add WPF windows, it can be useful. If you don't need this, skip to #4. In the "Program" class for the console, add this in order to control the window:
public class Program
{
[DllImport("kernel32.dll", SetLastError = true)]
static extern bool AllocConsole(); // Create console window
[DllImport("kernel32.dll")]
static extern IntPtr GetConsoleWindow(); // Get console window handle
[DllImport("user32.dll")]
static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);
const int SW_HIDE = 0;
const int SW_SHOW = 5;
This allows to create, hide, and show the console window. I created these methods to do this:
static void ShowConsole()
{
var handle = GetConsoleWindow();
if (handle == IntPtr.Zero)
AllocConsole();
else
ShowWindow(handle, SW_SHOW);
}
static void HideConsole()
{
var handle = GetConsoleWindow();
if (handle != null)
ShowWindow(handle, SW_HIDE);
}
These are mostly self explanatory, but if the project is in window mode, GetConsoleWindow(); returns null, so here we test if the handle is null (zero in this case), and if so, a console window needs to be created (only once). After this, GetConsoleWindow(); will always return a handle to use.
As stated in another answer already, you need to add [STAThread] on a line before your console's Main method. This is required, as WPF needs to run in a Single Threaded Apartment environment.
[STAThread]
static void Main(string[] args)
{
}
Adding a window: To do this, just add a user control to your project and name it "MainWindow" (or whatever you like). Just right-click the project node in the solution explorer and select Add->User Control.... Open the MainWindow.xaml.cs code behind and change MainWindow : UserControl to MainWindow : Window. Next, open the MainWindow.xaml file and change the first tag <UserControl to <Window (and make sure the closing tag gets renamed also, which should be automatic if using Visual Studio). Close all "MainWindow" editor tabs and reopen (just to be sure, may not be necessary). You should see MainWindow.xaml now show a window in the design pane.
Showing the WPF window: To do this, we need to start the window message loop, which is really easy. To begin, I created some properties to store the objects. Just put this somewhere in the Program class.
public static Application WinApp { get; private set; }
public static Window MainWindow { get; private set; }
Next we have to create the message loop by creating a System.Windows.Application object, then pass it the main window. I created this method to perform this task:
static void InitializeWindows()
{
WinApp = new Application();
WinApp.Run(MainWindow = new MainWindow()); // note: blocking call
}
and that's it! To test this, put some content in your main window and do this:
[STAThread]
static void Main(string[] args)
{
ShowConsole(); // Show the console window (for Win App projects)
Console.WriteLine("Opening window...");
InitializeWindows(); // opens the WPF window and waits here
Console.WriteLine("Exiting main...");
}
Hope that helps saves someone time, cheers! ;)
TIP: I found it helpful, in my case, to call InitializeWindows() in a new thread; however, that means that you must create UI objects (among other things) in the the same thread that the Application object was created in. To communicate with the new thread, I just used the Dispatcher class (WinApp.Dispatcher.BeginInvoke()) to run requests in the WPF thread context.
For Windows 8/10: If you are debugging and you don't see any text in your output window, take a look here: https://stackoverflow.com/a/49145317/1236397
You should move your library code to some other "Class library" project and use it from your Console project. Your WPF windows should be in another "WPF application" project which will also reference your "Class library".
Thanks to aku and Dmitriy, I create another project (WPF) which will reference my console based code.
Are you sure you need Console project? You can create 'WPF application' project and add references to your libraries, etc. If try to show WPF window from console app you will gen an exception due to differences in threading model between Console & WPF apps.

Categories