WPF 应用程序没有输出到控制台?

Posted

技术标签:

【中文标题】WPF 应用程序没有输出到控制台?【英文标题】:No output to console from a WPF application? 【发布时间】:2010-09-14 16:56:42 【问题描述】:

我在一个非常简单的 WPF 测试应用程序中使用Console.WriteLine(),但是当我从命令行执行应用程序时,我没有看到任何内容写入控制台。有谁知道这里可能发生了什么?

我可以通过在 VS 2008 中创建一个 WPF 应用程序来重现它,并在它执行的任何地方简单地添加 Console.WriteLine("text")。有什么想法吗?

我现在只需要像Console.WriteLine() 这样简单的东西。我意识到我可以使用 log4net 或其他一些日志记录解决方案,但我真的不需要这个应用程序的那么多功能。

编辑:我应该记得Console.WriteLine() 用于控制台应用程序。哦,好吧,没有愚蠢的问题,对吧? :-) 我现在只使用System.Diagnostics.Trace.WriteLine() 和 DebugView。

【问题讨论】:

可能重复 here 和 here(较新,但使用 AttachConsole from Kernel32.dll 有一些有趣的答案) @Max,这些问题可能与 this 问题重复。这个问题是在您发布这些问题之前 2-4 年提出的。 【参考方案1】:

你可以使用

Trace.WriteLine("text");

这将输出到 Visual Studio 中的“输出”窗口(调试时)。

确保包含诊断程序集:

using System.Diagnostics;

【讨论】:

这是最好的答案,但没有最高评分 我同意 - 这正是 op 所要求的。 Console.WriteLine() 的绝佳替代方案 - 标记为答案的解决方案是一个巧妙的练习,但包含在生产应用程序中是不合理的。 PS for Windows Store 应用程序(Windows 运行时)相当于 Trace.WriteLine 是 Debug.WriteLine() 这是一个简单、干净的解决方案,但对我不起作用。在更新数据库期间无法在实体框架的种子方法中工作。否则,在其他任何地方都可以使用! 这是最好的解决方案。如果答案还解释说Console.WriteLine 根本不适用于 WPF 应用程序,而仅用于命令行应用程序,那就更好了。【参考方案2】:

右击项目,“属性”,“应用程序”选项卡,将“输出类型”改为“控制台应用程序”,然后它也会有一个控制台。

【讨论】:

唯一的问题是你会在后台打开一个 cmd,但它可以工作:)。 很好,但是当应用程序不是从 cmd.exe 执行时会创建命令行窗口(为一个应用程序创建两个窗口)。但为此也有解决方案:您可以通过 ShowWindow(hWnd, 0) 隐藏 cmd 窗口。 ***.com/a/10416180/1457197 。使用此解决方案,只有在从命令行执行 WPF 应用程序时,您才会在控制台中看到文本。 请注意,在 Blend 中工作时,您必须将其切换回“窗口应用程序”,因为它仅显示“控制台应用程序”类型的 XAML(无法访问设计视图)。 (截至 2013 年的 Blend) 答案不正确。隐藏主窗口。只是控制台出现了。 谢谢!当您执行上述答案中@John Leidegren 显示的操作时,必须使用此解决方案【参考方案3】:

在实际调用任何 Console.Write 方法之前,您必须手动创建一个控制台窗口。这将使控制台在不更改项目类型的情况下正常工作(对于 WPF 应用程序将不起作用)。

这是一个完整的源代码示例,说明 ConsoleManager 类的外观,以及如何使用它来启用/禁用控制台,与项目类型无关。

使用以下课程,您只需在调用Console.Write之前在某处写ConsoleManager.Show()...

[SuppressUnmanagedCodeSecurity]
public static class ConsoleManager

    private const string Kernel32_DllName = "kernel32.dll";

    [DllImport(Kernel32_DllName)]
    private static extern bool AllocConsole();

    [DllImport(Kernel32_DllName)]
    private static extern bool FreeConsole();

    [DllImport(Kernel32_DllName)]
    private static extern IntPtr GetConsoleWindow();

    [DllImport(Kernel32_DllName)]
    private static extern int GetConsoleOutputCP();

    public static bool HasConsole
    
        get  return GetConsoleWindow() != IntPtr.Zero; 
    

    /// <summary>
    /// Creates a new console instance if the process is not attached to a console already.
    /// </summary>
    public static void Show()
    
        //#if DEBUG
        if (!HasConsole)
        
            AllocConsole();
            InvalidateOutAndError();
        
        //#endif
    

    /// <summary>
    /// If the process has a console attached to it, it will be detached and no longer visible. Writing to the System.Console is still possible, but no output will be shown.
    /// </summary>
    public static void Hide()
    
        //#if DEBUG
        if (HasConsole)
        
            SetOutAndErrorNull();
            FreeConsole();
        
        //#endif
    

    public static void Toggle()
    
        if (HasConsole)
        
            Hide();
        
        else
        
            Show();
        
    

    static void InvalidateOutAndError()
    
        Type type = typeof(System.Console);

        System.Reflection.FieldInfo _out = type.GetField("_out",
            System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.NonPublic);

        System.Reflection.FieldInfo _error = type.GetField("_error",
            System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.NonPublic);

        System.Reflection.MethodInfo _InitializeStdOutError = type.GetMethod("InitializeStdOutError",
            System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.NonPublic);

        Debug.Assert(_out != null);
        Debug.Assert(_error != null);

        Debug.Assert(_InitializeStdOutError != null);

        _out.SetValue(null, null);
        _error.SetValue(null, null);

        _InitializeStdOutError.Invoke(null, new object[]  true );
    

    static void SetOutAndErrorNull()
    
        Console.SetOut(TextWriter.Null);
        Console.SetError(TextWriter.Null);
    
 

【讨论】:

可以先尝试调用 AttachConsole(-1) 并检查其返回值以附加到父进程的控制台;如果返回 false,则调用 AllocConsole。但是,应用程序仍然首先“返回”,然后才输出到控制台,如果我找到解决方案,我会发布更多信息。此外,如果您将 WPF 应用程序类型设置为控制台应用程序,问题就会消失,但您无法在程序启动时在屏幕上短暂显示的情况下分离控制台,所以它看起来有点尴尬(但如果你能忍受它,效果很好)。 嗯,实际上不,我认为不可能同时拥有它;控制台应用程序在其 PE 标头中标记为 CUI,因此可以很好地与 CMD 自动配合。另一方面,GUI 应用程序立即将控制权返回给 CMD,即使它可以重新连接到控制台,读取和写入也会与管道中的下一个输出混合在一起,这显然是非常糟糕的。另一方面,如果您将应用程序标记为控制台应用程序,则只需在应用程序启动时短暂显示 CMD;然后,您可以使用 FreeConsole 分离并稍后附加/分配等 当 Brian 的回答也有效且容易得多时,为什么要这样做。 可能很明显,但我发现当附加了 Visual Studio 调试器时,Console.WriteLine 仍然无法使用这种技术。当我在 VS 之外运行该应用程序时,它很有效。谢谢。 @Mark 是的,但它不起作用...有一个 SetConsoleCtrlHandler 函数允许在 CTRL_CLOSE_EVENT 事件发生时得到通知,但你不能用它做任何事情,有没有任何东西可以让您的应用程序继续进行。你将被关闭。如果您想破解,您可以将 Windows 消息处理程序换成控制台进程,然后删除 WM_CLOSE 消息,我从未尝试过,但它可以工作。这只是另一个窗口,但话虽如此,除非你想接受这个想法,否则你最好把精力花在做其他事情上。【参考方案4】:

旧帖子,但我遇到了这个问题,所以如果您尝试在 Visual Studio 的 WPF 项目中将某些内容输出到 Output,现代方法是:

包括这个:

using System.Diagnostics;

然后:

Debug.WriteLine("something");

【讨论】:

【参考方案5】:

尽管 John Leidegren 不断否定这个想法,但 Brian 是正确的。我刚刚让它在 Visual Studio 中运行。

需要明确的是,WPF 应用程序默认情况下不会创建控制台窗口。

您必须创建一个 WPF 应用程序,然后将 OutputType 更改为“控制台应用程序”。运行项目时,您会看到一个控制台窗口,前面是您的 WPF 窗口。

它看起来不是很漂亮,但我发现它很有帮助,因为我希望我的应用程序可以从命令行运行并在其中提供反馈,然后对于某些命令选项,我会显示 WPF 窗口。

【讨论】:

完美。做这项工作。【参考方案6】:

使用command line redirection 可以查看用于控制台的输出。

例如:

C:\src\bin\Debug\Example.exe > output.txt

将所有内容写入output.txt文件。

【讨论】:

最佳答案,因为它很简单并且不需要更改源代码 ...当然,下一步是在notepad++中打开文件并选择'View -> Monitoring (tail -f)'来观看它的实时更新【参考方案7】:

我使用 Console.WriteLine() 在输出窗口中使用...

【讨论】:

这是一个 4 年前的问题,自从我第一次看到它以来,它已经被大量编辑。当然,现在这个问题措辞更好,我的回答变得无关紧要。【参考方案8】:

我已经创建了一个解决方案,混合了各种帖子的信息。

它是一个表单,包含一个标签和一个文本框。控制台输出被重定向到文本框。

还有一个名为 ConsoleView 的类实现了三个公共方法:Show()、Close() 和 Release()。最后一个是打开控制台并激活关闭按钮以查看结果。

这些表单称为 FrmConsole。这是 XAML 和 c# 代码。

使用很简单:

ConsoleView.Show("Title of the Console");

用于打开控制台。使用:

System.Console.WriteLine("The debug message");

用于向控制台输出文本。

用途:

ConsoleView.Close();

对于关闭控制台。

ConsoleView.Release();

打开控制台并启用关闭按钮

XAML

<Window x:Class="CustomControls.FrmConsole"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:local="clr-namespace:CustomControls"
    mc:Ignorable="d"
    Height="500" Width="600" WindowStyle="None" ResizeMode="NoResize" WindowStartupLocation="CenterScreen" Topmost="True" Icon="Images/icoConsole.png">
<Grid>
    <Grid.RowDefinitions>
        <RowDefinition Height="40"/>
        <RowDefinition Height="*"/>
        <RowDefinition Height="40"/>
    </Grid.RowDefinitions>
    <Label Grid.Row="0" Name="lblTitulo" HorizontalAlignment="Center" HorizontalContentAlignment="Center" VerticalAlignment="Center" VerticalContentAlignment="Center" FontFamily="Arial" FontSize="14" FontWeight="Bold" Content="Titulo"/>
    <Grid Grid.Row="1">
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="10"/>
            <ColumnDefinition Width="*"/>
            <ColumnDefinition Width="10"/>
        </Grid.ColumnDefinitions>
        <TextBox Grid.Column="1" Name="txtInner" FontFamily="Arial" FontSize="10" ScrollViewer.CanContentScroll="True" VerticalScrollBarVisibility="Visible" HorizontalScrollBarVisibility="Visible" TextWrapping="Wrap"/>
    </Grid>
    <Button Name="btnCerrar" Grid.Row="2" Content="Cerrar" Width="100" Height="30" HorizontalAlignment="Center" HorizontalContentAlignment="Center" VerticalAlignment="Center" VerticalContentAlignment="Center"/>
</Grid>

窗口的代码:

partial class FrmConsole : Window

    private class ControlWriter : TextWriter
    
        private TextBox textbox;
        public ControlWriter(TextBox textbox)
        
            this.textbox = textbox;
        

        public override void WriteLine(char value)
        
            textbox.Dispatcher.Invoke(new Action(() =>
            
                textbox.AppendText(value.ToString());
                textbox.AppendText(Environment.NewLine);
                textbox.ScrollToEnd();
            ));
        

        public override void WriteLine(string value)
        
            textbox.Dispatcher.Invoke(new Action(() =>
            
                textbox.AppendText(value);
                textbox.AppendText(Environment.NewLine);
                textbox.ScrollToEnd();
            ));
        

        public override void Write(char value)
        
            textbox.Dispatcher.Invoke(new Action(() =>
            
                textbox.AppendText(value.ToString());
                textbox.ScrollToEnd();
            ));
        

        public override void Write(string value)
        
            textbox.Dispatcher.Invoke(new Action(() =>
            
                textbox.AppendText(value);
                textbox.ScrollToEnd();
            ));
        

        public override Encoding Encoding
        
            get  return Encoding.UTF8; 

        
    

    //DEFINICIONES DE LA CLASE
    #region DEFINICIONES DE LA CLASE

    #endregion


    //CONSTRUCTORES DE LA CLASE
    #region CONSTRUCTORES DE LA CLASE

    public FrmConsole(string titulo)
    
        InitializeComponent();
        lblTitulo.Content = titulo;
        Clear();
        btnCerrar.Click += new RoutedEventHandler(BtnCerrar_Click);
        Console.SetOut(new ControlWriter(txtInner));
        DesactivarCerrar();
    

    #endregion


    //PROPIEDADES
    #region PROPIEDADES

    #endregion


    //DELEGADOS
    #region DELEGADOS

    private void BtnCerrar_Click(object sender, RoutedEventArgs e)
    
        Close();
    

    #endregion


    //METODOS Y FUNCIONES
    #region METODOS Y FUNCIONES

    public void ActivarCerrar()
    
        btnCerrar.IsEnabled = true;
    

    public void Clear()
    
        txtInner.Clear();
    

    public void DesactivarCerrar()
    
        btnCerrar.IsEnabled = false;
    

    #endregion  

ConsoleView类的代码

static public class ConsoleView

    //DEFINICIONES DE LA CLASE
    #region DEFINICIONES DE LA CLASE
    static FrmConsole console;
    static Thread StatusThread;
    static bool isActive = false;
    #endregion

    //CONSTRUCTORES DE LA CLASE
    #region CONSTRUCTORES DE LA CLASE

    #endregion

    //PROPIEDADES
    #region PROPIEDADES

    #endregion

    //DELEGADOS
    #region DELEGADOS

    #endregion

    //METODOS Y FUNCIONES
    #region METODOS Y FUNCIONES

    public static void Show(string label)
    
        if (isActive)
        
            return;
        

        isActive = true;
        //create the thread with its ThreadStart method
        StatusThread = new Thread(() =>
        
            try
            
                console = new FrmConsole(label);
                console.ShowDialog();
                //this call is needed so the thread remains open until the dispatcher is closed
                Dispatcher.Run();
            
            catch (Exception)
            
            
        );

        //run the thread in STA mode to make it work correctly
        StatusThread.SetApartmentState(ApartmentState.STA);
        StatusThread.Priority = ThreadPriority.Normal;
        StatusThread.Start();

    

    public static void Close()
    
        isActive = false;
        if (console != null)
        
            //need to use the dispatcher to call the Close method, because the window is created in another thread, and this method is called by the main thread
            console.Dispatcher.InvokeShutdown();
            console = null;
            StatusThread = null;
        

        console = null;
    

    public static void Release()
    
        isActive = false;
        if (console != null)
        
            console.Dispatcher.Invoke(console.ActivarCerrar);
        

    
    #endregion

我希望这个结果有用。

【讨论】:

【参考方案9】:

看看这篇文章,对我自己很有帮助。下载代码示例:

http://www.codeproject.com/Articles/335909/Embedding-a-Console-in-a-C-Application

【讨论】:

【参考方案10】:

我最近也遇到过这个问题。

如果 Brians 解决方案(在项目设置中更改为控制台应用程序)没有解决问题:尝试将目标框架从 .NET 5.0 更改为 .NET Core 3.1。

【讨论】:

以上是关于WPF 应用程序没有输出到控制台?的主要内容,如果未能解决你的问题,请参考以下文章

如何根据进程的控制台输出更新WPF控件?

是否可以看到 WPF 崩溃的错误消息? [复制]

从控制台应用程序启动 WPF 窗口

在 WPF 窗口中从 CMD 捕获输出

在 VS 2010 中将控制台应用程序转换为 WPF 应用程序时遇到问题

在Visual Studio 2017中为WPF应用程序创建MSI安装程序后,EXE不执行任何操作