如何从控制台应用程序中运行WinForm?

82

如何在控制台应用程序中创建、执行和控制WinForm窗体?

10个回答

108

最简单的方法是开始一个Windows Forms项目,然后将输出类型更改为控制台应用程序。或者,只需添加对System.Windows.Forms.dll的引用,然后开始编码:

using System.Windows.Forms;

[STAThread]
static void Main() {
    Application.EnableVisualStyles();
    Application.Run(new Form()); // or whatever
}

重要的是在你的 Main() 方法上标记为 [STAThread],这是为了完整支持 COM 所必需的。


8
根据 MSDN 的说法,它一直都是这样的。 - Marc Gravell
1
我使用的是vsCode(而不是Visual Studio),所以我必须在我的csproj文件中添加以下xml代码: Exe netcoreapp3.1 true true 请注意 Microsoft.NET.Sdk.WindowsDesktopUseWPF>true</UseWPF> 和 **UseWindowsForms>true</UseWindowsForms>**。 - Shaybc

42

我最近想做这件事情,但是发现这里的任何答案都让我不满意。

如果你按照Marc的建议设置输出类型为控制台应用程序,就会出现两个问题:

1) 如果你从资源管理器中启动该应用程序,会出现一个令人烦恼的控制台窗口,它会在你的窗体后面一直存在,直到你的程序退出。我们可以通过在显示GUI之前(Application.Run)调用FreeConsole来减轻这个问题。但是控制台窗口仍然会出现。它立即消失了,但是还是在那里存在了一会儿。

2) 如果你从控制台启动它,并显示GUI,则控制台会阻塞,直到GUI退出。这是因为控制台(cmd.exe)认为应该同步启动控制台应用程序和异步启动Windows应用程序(相当于Unix中的“myprocess &”)。


如果你将输出类型保留为Windows应用程序,但正确调用AttachConsole,从控制台调用时不会出现第二个控制台窗口,从资源管理器调用时也不会出现不必要的控制台。正确调用AttachConsole的方法是向它传递-1。这会使我们的进程附加到父进程的控制台(启动我们的控制台窗口)。

但是,这还有两个不同的问题:

1) 因为控制台在后台启动Windows应用程序,它会立即显示提示符并允许进一步输入。一方面这是好消息,控制台没有被你的GUI应用程序阻塞,但在你想要将输出转储到控制台而不显示GUI的情况下,你的程序的输出会出现在提示符之后,当你完成后不会显示新的提示符。这看起来有点混乱,而且你的“控制台应用程序”在后台运行,用户可以在其运行时自由执行其他命令。

2) 流重定向也会出现问题,例如,“myapp某些参数 > somefile”无法重定向。流重定向问题需要大量的P/Invoke来修复标准句柄,但是可以解决。

经过数小时的搜索和尝试,我得出结论:没有完美的方法来做到这一点。你无法在不产生任何副作用的情况下同时获得控制台和窗口的所有好处。问题在于要选择哪些副作用对于您的应用程序目的来说最不烦人。

我还要补充一点,为了在GNU/Linux中获得单色的终端输出,通常的窗口应用程序就足够了。也就是说,默认情况下Console.WriteLine总是有效的。 - Hi-Angel

27
这是我找到的最佳方法: 首先,将您的项目输出类型设置为“Windows应用程序”,然后使用P/Invoke AllocConsole创建控制台窗口。
internal static class NativeMethods
{
    [DllImport("kernel32.dll")]
    internal static extern Boolean AllocConsole();
}

static class Program
{

    static void Main(string[] args) {
        if (args.Length == 0) {
            // run as windows app
            Application.EnableVisualStyles();
            Application.Run(new Form1()); 
        } else {
            // run as console app
            NativeMethods.AllocConsole();
            Console.WriteLine("Hello World");
            Console.ReadLine();
        }
    }

}

6
-1,会创建第二个控制台窗口并在那里运行命令。这不是原帖作者想要的。 - tomfanning
8
实际上它并没有创建第二个控制台,因为你首先将项目的输出设置为“Windows应用程序”,这确实不是OP所要求的,但很可能是他想要的,因为这样当你不需要控制台窗口时就不会有它。 - DrCopyPaste
功能如广告所述,但我没有得到应用程序图标,也不认为“当前工作目录”是相同的——有什么想法吗? - drzaus
“当前工作目录”是一个单独的问题,因为我将一个文件拖放到exe上,这显然会改变cwd。此外,我还找到了一些更多的资源来解决这个问题:可能存在调试输出问题一种附加到现有控制台或创建控制台的方法 - drzaus
1
Plus1来撤销那个家伙在2011年的-1。好的解决方法。 - Gaspa79

6
添加以下属性和代码到您的Main方法中非常简单: ```java System.setProperty("file.encoding", "UTF-8"); ``` 请注意:不要删除原有的HTML标记。
[STAThread]
void Main(string[] args])
{
   Application.EnableVisualStyles();
   //Do some stuff...
   while(!Exit)
   {
       Application.DoEvents(); //Now if you call "form.Show()" your form won´t be frozen
       //Do your stuff
   }
}

现在你完全可以展示WinForms了 :)

1
运行正常!如果您需要检查按键,则必须在调用Console.ReadKey之前使用Console.KeyAvailable检查按键是否可用,否则您将阻塞事件循环(因此也会阻塞您的窗体)。 - wexman

5

您可以在VS2005/ VS2008中创建一个winform项目,然后将其属性更改为命令行应用程序。然后可以从命令行启动它,但仍会打开一个winform窗体。


4

以上所有回答都是很有帮助的,但我想为绝对初学者添加一些更多的提示。

所以,您想在控制台应用程序中使用 Windows Forms:

在解决方案资源管理器中,向您的控制台应用程序项目添加对 System.Windows.Forms.dll 的引用。 (右键单击解决方案名称- > 添加- > 引用...)

在代码中指定名称空间:using System.Windows.Forms;

在您的类中声明需要添加到表单中的控件的所需属性。

例如: int Left { get; set; } // 需要在表单上指定按钮的LEFT位置

然后在 Main() 中添加以下代码片段:

static void Main(string[] args)
{
Application.EnableVisualStyles();
        Form frm = new Form();  // create aForm object

        Button btn = new Button()
        {
            Left = 120,
            Width = 130,
            Height = 30,
            Top = 150,
            Text = "Biju Joseph, Redmond, WA"
        };
       //… more code 
       frm.Controls.Add(btn);  // add button to the Form
       //  …. add more code here as needed

       frm.ShowDialog(); // a modal dialog 
}

2

这对我的需求很有效...

Task mytask = Task.Run(() =>
{
    MyForm form = new MyForm();
    form.ShowDialog();
});

这将在新线程中启动表单,并且直到表单关闭后才释放该线程。 Task 是在 .Net 4 及更高版本中使用的。


1

你应该能够像使用Winform应用程序一样使用Application类。可能开始一个新项目最简单的方法是按照Marc的建议:创建一个新的Winform项目,然后在选项中将其更改为控制台应用程序。


0
如果您想要从表单冻结中逃脱并使用编辑(例如按钮文本),请使用以下代码。
Form form = new Form();
Form.Button.Text = "randomText";
System.Windows.Forms.Application.EnableVisualStyles();
System.Windows.Forms.Application.Run(form);

0

这完全取决于您的选择,取决于您如何实现。
a. 附加进程,例如:在表单上输入并在控制台上打印
b. 独立进程,例如:启动定时器,即使控制台退出也不要关闭。

对于a,

Application.Run(new Form1());
//or -------------
Form1 f = new Form1();
f.ShowDialog();

对于b, 使用线程或任务等, 如何独立打开win表单?


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接