C# 控制台项目中的 WPF 窗口?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/479014/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
WPF window from a Console project?
提问by Shahbaz
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?
我最近开始了一个 C# 项目(VS 2008)作为“控制台”项目,我在其中编写了一些库、测试程序等。现在我想添加几个 WPF 窗口,但看起来控制台项目不会让我这样做。我来自 Java,所以这有点奇怪。如何添加 WPF 表单(我将从我的“主”类中实例化我自己?
采纳答案by aku
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.
您确定需要控制台项目吗?您可以创建“WPF 应用程序”项目并添加对您的库的引用等。如果尝试从控制台应用程序显示 WPF 窗口,由于控制台和 WPF 应用程序之间的线程模型差异,您将生成异常。
回答by okutane
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".
您应该将您的库代码移动到其他一些“类库”项目中,并从您的控制台项目中使用它。您的 WPF 窗口应该在另一个“WPF 应用程序”项目中,该项目也将引用您的“类库”。
回答by Shahbaz
Thanks to aku and Dmitriy, I create another project (WPF) which will reference my console based code.
感谢 aku 和 Dmitriy,我创建了另一个项目 (WPF),它将引用我的基于控制台的代码。
回答by Peter
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.
接受的答案并不完全正确,恐怕,只需在 mainmethod 之前添加 [STAThread] 属性并引用正确的库(如 System.Windows),您就可以添加 wpf 窗口了。
EDIT : in the comments @JamesWilkins supplied me with this usefull link : http://code-phix.blogspot.be/2013/11/creating-wpf-project-from-scratch.html
编辑:@JamesWilkins 在评论中为我提供了这个有用的链接:http://code-phix.blogspot.be/2013/11/creating-wpf-project-from-scratch.html
回答by James Wilkins
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+):
我有同样的问题,正在寻找类似的答案。我到处都找到了信息,所以我把我找到的东西放在一个地方。我还需要一种隐藏和显示控制台窗口的方法,所以我发现这有效(对于 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();
returnsnull
, 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 needto add
[STAThread]
on a line before your console'sMain
method. This is required, as WPF needs to run in a Single Threaded Apartmentenvironment.[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 changeMainWindow : UserControl
toMainWindow : 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..."); }
创建一个新的控制台项目(请务必选择您需要使用的 .NET 框架版本 - 我需要自己使用 .Net 4.0)。确保有以下参考资料:
- 演示框架
- 演示核心
- 视窗基地
- 系统文件
右键单击解决方案资源管理器中的项目,选择“属性”,将项目输出类型更改为 Windows 应用程序。这可以防止控制台窗口在启动时显示(如果需要,请跳过此步骤)。
虽然控制控制台窗口不是添加 WPF 窗口所必需的,但它很有用。如果您不需要这个,请跳到#4。在控制台的“程序”类中,添加以下内容以控制窗口:
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;
这允许创建、隐藏和显示控制台窗口。我创建了这些方法来做到这一点:
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); }
这些大多是不言自明的,但是如果项目处于窗口模式,则
GetConsoleWindow();
返回null
,所以这里我们测试句柄是否为空(在这种情况下为零),如果是,则需要创建一个控制台窗口(仅一次)。在此之后,GetConsoleWindow();
将始终返回一个句柄以供使用。正如另一个答案中所述,您需要
[STAThread]
在控制台Main
方法之前添加一行。这是必需的,因为 WPF 需要在单线程单元环境中运行。[STAThread] static void Main(string[] args) { }
添加一个窗口:为此,只需向您的项目添加一个用户控件并将其命名为“MainWindow”(或您喜欢的任何名称)。只需右键单击解决方案资源管理器中的项目节点并选择
Add->User Control...
。打开后面的MainWindow.xaml.cs代码和变化MainWindow : UserControl
来MainWindow : Window
。接下来,打开 MainWindow.xaml 文件并将第一个标记更改<UserControl
为<Window
(并确保结束标记也被重命名,如果使用 Visual Studio,这应该是自动的)。关闭所有“MainWindow”编辑器选项卡并重新打开(只是为了确定,可能没有必要)。您应该会看到 MainWindow.xaml 现在在设计窗格中显示一个窗口。显示 WPF 窗口:为此,我们需要启动窗口消息循环,这非常简单。首先,我创建了一些属性来存储对象。把它放在
Program
课堂上的某个地方。public static Application WinApp { get; private set; } public static Window MainWindow { get; private set; }
接下来我们必须通过创建一个
System.Windows.Application
对象来创建消息循环,然后将它传递给主窗口。我创建了这个方法来执行这个任务:static void InitializeWindows() { WinApp = new Application(); WinApp.Run(MainWindow = new MainWindow()); // note: blocking call }
就是这样!要对此进行测试,请在主窗口中放置一些内容并执行以下操作:
[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.
提示:就我而言,我发现调用InitializeWindows()
新线程很有帮助;但是,这意味着您必须在创建对象的同一个线程中创建 UI 对象(除其他外)Application
。为了与新线程通信,我只是使用Dispatcher
类 ( WinApp.Dispatcher.BeginInvoke()
) 在 WPF 线程上下文中运行请求。
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
对于 Windows 8/10:如果您正在调试并且在输出窗口中没有看到任何文本,请查看此处:https: //stackoverflow.com/a/49145317/1236397