我最近开始了一个C#项目(VS 2008),类型为“控制台(console)”项目,在其中编写了一些库、测试程序等。现在我想添加几个 WPF 窗口,但好像控制台项目不允许这样做。对我来说这有点奇怪,因为我之前用 Java 开发时并没有这个问题。那么,我应该如何添加一个 WPF 窗体(我会从我的“主”类中进行实例化)?
接受的答案并不完全正确,抱歉,只需在你的 main 方法前加上 [STAThread] 属性,并引用正确的库(如 System.Windows),就可以添加 WPF 窗口了。
编辑: 在评论中 @JamesWilkins 向我提供了这个有用的链接:http://code-phix.blogspot.be/2013/11/creating-wpf-project-from-scratch.html
我曾经有同样的问题并寻找类似的答案。我在各个地方找到了信息,所以我把我找到的整理在一个地方。我还需要一种隐藏和显示控制台窗口的方法,所以我发现这个方法行得通(适用于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:
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...");
}
InitializeWindows()
很有帮助;但是,这意味着您必须在创建Application
对象的同一线程中创建UI对象(以及其他事物)。要与新线程通信,我只需使用Dispatcher
类(WinApp.Dispatcher.BeginInvoke()
)在WPF线程上下文中运行请求。