【问题标题】:WPF window from a Console project?来自控制台项目的 WPF 窗口?
【发布时间】:2010-10-03 12:02:59
【问题描述】:

我最近启动了一个 C# 项目 (VS 2008) 作为“控制台”项目,我在其中编写了一些库、测试程序等。现在我想添加几个 WPF 窗口,但它看起来像控制台项目不会让我那样做的。我来自 Java,所以这有点奇怪。如何添加 WPF 表单(我将从“主”类中实例化自己?

【问题讨论】:

    标签: c# wpf console


    【解决方案1】:

    我有同样的问题,正在寻找类似的答案。我到处都找到了信息,所以我把我找到的东西放在一个地方。我还需要一种隐藏和显示控制台窗口的方法,所以我发现这很有效(适用于 VS 2013+):

    1. 创建一个新的控制台项目(一定要选择你需要使用的 .NET 框架版本——我需要自己使用 .Net 4.0)。确保有以下参考资料:

      • 演示框架
      • PresentationCore
      • WindowsBase
      • System.xaml
    2. 在解决方案资源管理器中右键单击项目,选择 “属性”,并将项目输出类型更改为 Windows 应用程序。 这可以防止控制台窗口在启动时显示(如果您 想要那个,跳过这一步)。

    3. 虽然添加 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(); 将始终返回一个句柄以供使用。

    4. 正如另一个答案中所述,您需要在控制台的Main 方法之前的一行中添加[STAThread]。这是必需的,因为 WPF 需要在 Single Threaded Apartment 环境中运行。

        [STAThread]
        static void Main(string[] args)
        {
        }
      
    5. 添加窗口: 为此,只需将用户控件添加到您的项目并将其命名为“MainWindow”(或任何您喜欢的名称)。只需在解决方案资源管理器中右键单击项目节点并选择Add->User Control...。打开后面的MainWindow.xaml.cs代码,把MainWindow : UserControl改成MainWindow : Window。接下来,打开 MainWindow.xaml 文件并将第一个标签 <UserControl 更改为 <Window(并确保结束标签也被重命名,如果使用 Visual Studio,这应该是自动的)。关闭所有“MainWindow”编辑器选项卡并重新打开(只是为了确定,可能没有必要)。您应该会看到 MainWindow.xaml 现在在设计窗格中显示一个窗口。

    6. 显示 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...");
      }
      

    希望这有助于节省某人的时间,干杯! ;)

    提示:就我而言,我发现在新线程中调用InitializeWindows() 很有帮助;但是,这意味着您必须在创建 Application 对象的同一线程中创建 UI 对象(除其他外)。为了与新线程通信,我只使用了 Dispatcher 类 (WinApp.Dispatcher.BeginInvoke())在 WPF 线程上下文中运行请求。

    对于 Windows 8/10:如果您正在调试并且在输出窗口中看不到任何文本,请查看此处:https://stackoverflow.com/a/49145317/1236397

    【讨论】:

    • 哇,这值得更多的支持。它不仅教你如何做,还教你一些额外的小技巧,看看你为什么需要这样做。谢谢!
    • 我还有一个问题。现在,我将如何从 wpf 窗口单击按钮调用控制台类方法?提前致谢。
    • 您只需调用它。控制台类方法是线程安全的:“使用这些流的 I/O 操作是同步的,这意味着多个线程可以读取或写入流。” docs.microsoft.com/en-us/dotnet/api/…
    【解决方案2】:

    恐怕接受的答案并不完全正确,只需在您的 mainmethod 之前添加 [STAThread] 属性并引用正确的库(如 System.Windows),您就可以添加 wpf 窗口了。

    编辑:在 cmets @JamesWilkins 为我提供了这个有用的链接:http://code-phix.blogspot.be/2013/11/creating-wpf-project-from-scratch.html

    【讨论】:

    • 接受的答案在理论上是正确的。他所问的只是他是否确定他真的需要一个控制台应用程序。但我必须同意,我更喜欢你的回答作为对这个确切问题的回答。
    • @JamesWilkins, tx,删除了它。然而,答案仍然有用,所以我对减号感到遗憾。
    • 你可以试试这个:code-phix.blogspot.com/2013/11/… ;)
    【解决方案3】:

    感谢 aku 和 Dmitriy,我创建了另一个项目 (WPF),它将引用我基于控制台的代码。

    【讨论】:

      【解决方案4】:

      您应该将您的库代码移动到其他一些“类库”项目并从您的控制台项目中使用它。您的 WPF 窗口应位于另一个“WPF 应用程序”项目中,该项目也将引用您的“类库”。

      【讨论】:

        【解决方案5】:

        您确定需要控制台项目吗?您可以创建“WPF 应用程序”项目并添加对库的引用等。如果尝试从控制台应用程序显示 WPF 窗口,由于控制台和 WPF 应用程序之间的线程模型不同,您将产生异常。

        【讨论】:

          猜你喜欢
          • 2011-03-18
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2023-04-08
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多