WPF 애플리케이션에서 콘솔로 출력되지 않습니까?


113

매우 간단한 WPF 테스트 응용 프로그램에서 Console.WriteLine ()을 사용하고 있지만 명령 줄에서 응용 프로그램을 실행하면 콘솔에 아무것도 기록되지 않습니다. 여기에서 무슨 일이 벌어 질지 아는 사람이 있습니까?

VS 2008에서 WPF 응용 프로그램을 만들고 실행되는 모든 곳에 Console.WriteLine ( "text")을 추가하여 재현 할 수 있습니다. 어떤 아이디어?

지금 필요한 것은 Console.WriteLine ()처럼 간단한 것입니다. 나는 log4net 또는 다른 로깅 솔루션을 사용할 수 있다는 것을 알고 있지만 실제로이 응용 프로그램에 그다지 많은 기능이 필요하지 않습니다.

편집 : Console.WriteLine ()이 콘솔 응용 프로그램 용이라는 것을 기억해야합니다. 오, 어리석은 질문은 없죠? :-) 지금은 System.Diagnostics.Trace.WriteLine ()과 DebugView를 사용하겠습니다.


여기여기에 중복 가능성이 있습니다 (최신이지만 Kernel32.dll의 AttachConsole을 사용하여 흥미로운 답변이 있음 )
Max

1
@Max, 그 질문은 질문의 중복 가능성 있습니다. 이 질문은 귀하가 게시 한 질문 중 하나보다 2-4 년 전에 질문되었습니다.
Rob

답변:


91

실제로 Console.Write 메서드를 호출하기 전에 콘솔 창을 수동으로 만들어야합니다. 그러면 프로젝트 유형을 변경하지 않고 콘솔이 제대로 작동하도록 초기화됩니다 (WPF 애플리케이션의 경우 작동하지 않음).

다음은 ConsoleManager 클래스의 모양과 프로젝트 유형에 관계없이 콘솔을 활성화 / 비활성화하는 데 사용할 수있는 방법에 대한 완전한 소스 코드 예제입니다.

다음 클래스를 사용하면 ...를 ConsoleManager.Show()호출하기 전에 어딘가에 쓰기 만하면 됩니다 Console.Write.

[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);
    }
} 

5
AttachConsole (-1)을 먼저 호출하고 반환 값을 확인하여 부모 프로세스의 콘솔에 연결할 수 있습니다. false를 반환하면 AllocConsole을 호출합니다. 그러나 응용 프로그램이 여전히 먼저 '반환'된 다음 콘솔에 출력됩니다. 해결책을 찾으면 더 게시하겠습니다. 또한 WPF 앱 유형을 Console Application으로 설정하면 문제는 사라지지만 프로그램이 시작될 때 화면에 잠깐 표시되지 않으면 콘솔을 분리 할 수 ​​없으므로 다소 어색해 보입니다 (하지만 함께 살 수 있다면 , 잘 작동합니다).
Alex Paven 2010

2
어, 사실 아니에요. 두 가지 방법이 모두 가능하다고 생각하지 않습니다. 콘솔 응용 프로그램은 PE 헤더에 CUI로 표시되므로 CMD와 자동으로 잘 협력합니다. 반면에 GUI 응용 프로그램은 CMD에 즉시 제어를 반환하고 콘솔에 다시 연결할 수 있더라도 읽기와 쓰기가 파이프 라인의 다음 출력과 섞여서 분명히 매우 나쁩니다. 반면에 응용 프로그램을 콘솔 응용 프로그램으로 표시하면 앱 시작시 잠시 동안 표시되는 CMD 만 있으면됩니다. 당신은 그 분리에 FreeConsole를 사용하고 / ALLOC 나중에 등을 첨부 할 수 있습니다
알렉스 Paven

1
Brian의 답변이 훨씬 쉽게 작동하는 이유는 무엇입니까?
Wouter Janssens 2012

2
분명 할 수도 있지만 Visual Studio 디버거가 연결되었을 때 Console.WriteLine이 여전히이 기술을 사용하여 작동하지 않는다는 것을 발견했습니다. VS 외부에서 앱을 실행했을 때 효과가있었습니다. 감사.
aboy021 2013 년

2
@Mark 예,하지만 작동하지 않습니다 ... 이벤트가 발생 SetConsoleCtrlHandler하면 알림을받을 수 있는 기능이 CTRL_CLOSE_EVENT있지만 아무것도 할 수 없습니다. 애플리케이션을 계속하도록 허용하는 것은 없습니다. 당신은 종료됩니다. 해킹을 원하신다면 콘솔 프로세스를 위해 Windows 메시지 처리기를 교체하고 WM_CLOSE 메시지를 삭제하면 될 것입니다. 저는 이것을 시도한 적이 없지만 작동 할 수 있습니다. 그것은 단지 또 다른 창일 뿐이지 만,이 아이디어를 받아들이고 싶지 않다면 다른 일을하는 데 노력을 기울이는 것이 더 낫습니다.
John Leidegren 2013-08-27

129

프로젝트, "속성", "응용 프로그램"탭을 마우스 오른쪽 버튼으로 클릭하고 "출력 유형"을 "콘솔 응용 프로그램"으로 변경하면 콘솔도 있습니다.


2
유일한 문제는 백그라운드에서 cmd가 열려 있지만 작동한다는 것입니다. :).
ykatchou

5
좋지만 cmd.exe에서 응용 프로그램을 실행하지 않으면 명령 줄 창이 생성됩니다 (한 응용 프로그램에 대해 두 개의 창이 생성됨). 그러나 이에 대한 해결책도 있습니다. ShowWindow (hWnd, 0)로 cmd 창을 숨길 수 있습니다. stackoverflow.com/a/10416180/1457197 . 이 솔루션을 사용하면 WPF 응용 프로그램이 명령 줄에서 실행될 때만 콘솔에 텍스트가 표시됩니다.
CoperNick

Blend에서 작업하는 동안 "콘솔 응용 프로그램"유형에 대해 XAML (디자인보기에 대한 액세스 권한 없음) 만 표시하므로 "창 응용 프로그램"으로 다시 전환해야합니다. (Blend 2013 기준)

2
ans를 수정하지 않습니다. 기본 창을 숨 깁니다. 콘솔이 나타납니다.
Yash

wpf로 작동하지 않음, 기본 창 없음
alp

129

당신이 사용할 수있는

Trace.WriteLine("text");

Visual Studio의 "출력"창에 출력됩니다 (디버깅 할 때).

진단 어셈블리가 포함되어 있는지 확인하십시오.

using System.Diagnostics;

9
이것은 가장 좋은 대답이지만, 가장 높은 평가되지 않았습니다
kiltek

동의합니다. 이것이 바로 op가 요구하는 것입니다. Console.WriteLine ()의 훌륭한 대안-답으로 표시된 솔루션은 깔끔한 연습이지만 프로덕션 응용 프로그램에 포함하기에는 비합리적입니다.
nocarrier

4
Windows 스토어 앱용 PS (Windows 런타임)는 Trace.WriteLine에 해당하는 Debug.WriteLine ()
nocarrier

이것은 간단하고 깨끗한 솔루션이지만 저에게는 효과가 없었습니다. 업데이트 데이터베이스 중에 엔티티 프레임 워크의 시드 메소드에서 작동하지 않았습니다. 그렇지 않으면 다른 곳에서 작동합니다!
Charles W

이것이 최상의 솔루션입니다. 대답 Console.WriteLine이 WPF 응용 프로그램 용이 아니며 명령 줄 앱 전용이라고 설명하면 더 좋을 것입니다.
Andrew Koster

12

John Leidegren이 계속해서 아이디어를 내 세우지 만 Brian이 맞습니다. Visual Studio에서 방금 작동했습니다.

WPF 응용 프로그램을 지우려면 기본적으로 콘솔 창을 만들지 않습니다.

WPF 응용 프로그램을 만든 다음 OutputType을 "콘솔 응용 프로그램"으로 변경해야합니다. 프로젝트를 실행하면 앞에 WPF 창이있는 콘솔 창이 표시됩니다.

그다지 예쁘지는 않지만 피드백이있는 명령 줄에서 앱을 실행하고 특정 명령 옵션에 대해 WPF 창을 표시하기를 원했기 때문에 유용하다는 것을 알았습니다.


1
완전한. 일을합니다.
frostymarvelous

10

명령 줄 리디렉션 을 사용하여 콘솔 용 출력을 볼 수 있습니다 .

예를 들면 :

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

모든 내용을 output.txt파일에 기록 합니다.


간단하고 소스를 변경할 필요가없는 최상의 답변
buckley

9

이전 게시물이지만 Visual Studio의 WPF 프로젝트에서 출력에 무언가를 출력하려는 ​​경우 최신 방법은 다음과 같습니다.

포함 :

using System.Diagnostics;

그리고:

Debug.WriteLine("something");

4

출력 창에서 사용하기 위해 Console.WriteLine ()을 사용합니다.


4
내가 처음 본 이후 심하게 편집 된 4 년 된 질문입니다. 물론 질문은 더 잘 표현되었고 내 응답은 무관하게 만들어졌습니다.
erodewald

1

솔루션을 만들고 다양한 게시물의 정보를 혼합했습니다.

레이블과 하나의 텍스트 상자를 포함하는 양식입니다. 콘솔 출력은 텍스트 상자로 리디렉션됩니다.

Show (), Close () 및 Release ()의 세 가지 공용 메서드를 구현하는 ConsoleView라는 클래스도 있습니다. 마지막은 콘솔을 열어두고 결과보기를 위해 닫기 버튼을 활성화하는 것입니다.

양식을 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
}

이 결과가 유용하기를 바랍니다.



-17

내가 아는 한 Console.WriteLine ()은 콘솔 응용 프로그램 전용입니다. 나는 이것이 당신의 문제라고 생각합니다.


1
WPF에 대해 잘 모르지만 WinForms에는 해당되지 않습니다. Console.WriteLine은 여기에서 잘 작동하지만 물론 콘솔이 표시되지 않고 디버거 출력 창에서 볼 수 있으며 표준 출력을 듣게됩니다.
Jeff Yates

2
프로젝트를 콘솔 애플리케이션으로 설정할 수 있으며 여전히 Windows 앱으로 실행되지만 콘솔도 표시됩니다
Mark Cidade

틀 렸습니다. 콘솔이 아닌 응용 프로그램의 빌드 프로세스는 기본적으로 콘솔을 연결하지 않습니다. Console.Write를 호출하기 전에 AllocConsole () Win32 API 함수를 호출하여 수동으로이 작업을 수행 할 수 있습니다. 그러면 Console 클래스가 해당 콘솔 창에서 작동하도록 초기화됩니다.
John Leidegren
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.