Немає виводу для консолі з програми WPF?


112

Я використовую Console.WriteLine () з дуже простого тестового додатка WPF, але коли я виконую програму з командного рядка, я не бачу, щоб нічого не записувалося на консоль. Хтось знає, що тут може статися?

Я можу відтворити його, створивши додаток WPF у VS 2008 та просто додавши Console.WriteLine ("текст") у будь-який момент, де виконується виконання. Якісь ідеї?

Зараз мені потрібно лише щось просто, як Console.WriteLine (). Я усвідомлюю, що можу використовувати log4net чи дещо інше рішення для ведення журналів, але мені справді не потрібно стільки функціональних можливостей для цього додатка.

Редагувати: я мав би пам’ятати, що Console.WriteLine () призначений для консольних програм. Ну ну ніяких дурних питань, правда? :-) Зараз я просто використовувати System.Diagnostics.Trace.WriteLine () і DebugView.


Можливі дублікати тут і тут (новіші, але з цікавими відповідями, використовуючи AttachConsole від Kernel32.dll )
Макс

1
@Max, ці питання - це можливі копії цього питання. Це запитання було задано за 2–4 роки до того, як було задано жодне з тих запитань, які ви розмістили.
Роб

Відповіді:


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) і перевірити його повернене значення для приєднання до консолі батьківського процесу; якщо він поверне помилковий, дзвоніть AllocConsole. Однак додаток все ще 'повертається' спочатку і лише потім виводиться на консоль, я розміщую більше, якщо знайду рішення. Крім того, якщо ви встановите тип додатка WPF у програмі Console Application, проблема зникає, але ви не можете від'єднати консоль, не відображаючи її на екрані, коли програма запущена, тому вона виглядає незручно (але якщо ви можете жити з нею , це чудово працює).
Олексій Павен

2
Е, насправді ні, я не думаю, що це можливо обома способами; додаток консолі в заголовку PE позначено як CUI і, таким чином, добре співпрацює з CMD. Програма GUI з іншого боку негайно повертає контроль до CMD, і навіть якщо він може знову приєднатися до консолі, читання та запис буде змішане з наступними виходами в конвеєрі, що, очевидно, дуже погано. Якщо, з іншого боку, ви позначаєте програму як консольну програму, вам залишається жити лише з CMD, який коротко відображається при запуску програми; ви можете використовувати FreeConsole для від'єднання та приєднання / Alloc пізніше тощо
Alex Paven

1
Навіщо це робити, коли відповідь Брайана працює так само і набагато простіше.
Wouter Janssens

2
Це може бути очевидним, але я виявив, що Console.WriteLine все ще не працював за допомогою цієї методики, коли було додано налагоджувач Visual Studio. Коли я запустив додаток поза VS, він працював у пригоді. Дякую.
aboy021

2
@ Марк Так, але це не працює ... Існує SetConsoleCtrlHandlerфункція, яка дозволяє отримувати сповіщення, коли CTRL_CLOSE_EVENTподія трапляється, але ви нічого не можете з цим зробити, немає нічого, що дозволяє вашій програмі продовжувати роботу. Вас закриють. Якщо ви хочете зламати, ви, ймовірно, можете поміняти обробник повідомлень Windows на процес консолі та просто скинути повідомлення WM_CLOSE, я ніколи цього не пробував, але це може працювати. Це просто інше вікно, але з цим сказаним, якщо ви не хочете розважитись цією ідеєю, ви, мабуть, краще витратити зусилля на щось інше.
Джон Лейдегрен

129

Клацніть правою кнопкою миші на проект, "Властивості", на вкладці "Додаток", змініть "Тип виводу" на "Консольний додаток", і тоді він також матиме консоль.


2
Єдине питання з цим - у вас буде відкритий cmd на задньому плані, але він працює :).
ykatchou

5
Відмінне, але вікно командного рядка буде створено, коли додаток не виконується з cmd.exe (два вікна створені для однієї програми). Але для цього є також рішення: ви можете приховати вікно cmd за ShowWindow (hWnd, 0). stackoverflow.com/a/10416180/1457197 . Використовуючи це рішення, ви побачите текст у консолі лише тоді, коли додаток WPF виконується з командного рядка.
CoperNick

Зауважте, що вам доведеться переключити його на "Window Application" під час роботи в Blend, оскільки він показує лише XAML (без доступу до дизайнерського перегляду) для типів "Console Application". (станом на Blend 2013)

2
Неправильні анс. Приховує основні Windows. Просто підходить консоль.
Яш

не працює з wpf, немає головного вікна, марно
alp

129

Можна використовувати

Trace.WriteLine("text");

Це виведе у вікно "Вихід" у Visual Studio (при налагодженні).

переконайтеся, що включено діагностичну збірку:

using System.Diagnostics;

9
це найкраща відповідь, але не має найвищої оцінки
kiltek

Я згоден - саме про це і просять. Відмінна альтернатива Console.WriteLine () - рішення, позначене як відповідь, є акуратною вправою, але нерозумною для включення у виробничу програму.
nocarrier

4
PS для додатків Windows Store (Windows Runtime) еквівалент Trace.WriteLine - Debug.WriteLine ()
nocarrier

Це просте, чисте рішення, однак для мене не вийшло. Не працював у насіннєвому методі фреймворку під час оновлення-бази даних. В іншому випадку працює скрізь!
Charles W

Це найкраще рішення. Було б краще, якби у відповіді було пояснено, що він Console.WriteLineвзагалі не призначений для програм WPF і що він призначений лише для програм командного рядка.
Андрій Костер

12

Хоча Джон Лейдегрен продовжує збивати цю ідею, Брайан прав. Щойно я працював у Visual Studio.

Щоб зрозуміти, програма WPF не створює вікно консолі за замовчуванням.

Вам потрібно створити додаток WPF, а потім змінити OutputType на "Консольний додаток". Під час запуску проекту ви побачите вікно консолі з вікном WPF перед ним.

Це виглядає не дуже красиво, але я вважаю, що це корисно, оскільки я хотів, щоб мій додаток запускався з командного рядка зі зворотним зв'язком, і тоді для певних параметрів команди я б відображав вікно WPF.


1
Ідеально. Робить роботу.
frostymarvelous


9

Стара публікація, але я зіткнувся з цим, тому якщо ви намагаєтесь вивести щось на результат у проекті WPF у Visual Studio, сучасний метод:

Включіть це:

using System.Diagnostics;

І потім:

Debug.WriteLine("something");

4

Я використовую Console.WriteLine () для використання у вікні виводу ...


4
Це 4-річне запитання, яке було сильно відредаговане з моменту його першого побачення. Тепер, звичайно, питання було чіткіше сформульоване, і моя відповідь стала невідповідною.
erodewald

1

Я створив рішення, змішав інформацію про розміщення публікацій.

Його форма, яка містить мітку та одне текстове поле. Вихід консолі перенаправляється до текстового поля.

Існує занадто клас під назвою ConsoleView, який реалізує три методи publics: 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
}

Я сподіваюся, що цей результат корисний.



-17

Наскільки мені відомо, Console.WriteLine () призначений лише для консольних програм. Я думаю, це ваша проблема.


1
Я не знаю про WPF, але це, звичайно, не так для WinForms. Console.WriteLine там прекрасно працює, але, звичайно, консолі ви не побачите, ви побачите її у вікні виводу налагоджувача і, якщо прослухаєте стандартний вихід.
Джефф Йейтс

2
ви можете встановити проект на додаток Console, і він як і раніше працюватиме як додаток для Windows, але він також матиме видиму консоль
Mark Cidade

Це неправильно, процес збирання програми без консолі не додає консоль за замовчуванням. Це можна зробити вручну, зателефонувавши до API AllocConsole () Win32 API перед будь-яким викликом до Console.Write, клас Консолі буде ініціалізований для роботи з цим вікном Консолі.
Джон Лейдегрен
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.