Нет вывода на консоль из приложения WPF?


113

Я использую 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) и проверить его возвращаемое значение для подключения к консоли родительского процесса; если он возвращает false, вызовите AllocConsole. Однако приложение по-прежнему сначала «возвращается», а только потом выводит на консоль, я опубликую еще, если найду решение. Кроме того, если вы установите тип приложения WPF на Консольное приложение, проблема исчезнет, ​​но вы не сможете отсоединить консоль, пока она не будет на короткое время отображаться на экране при запуске программы, поэтому это выглядит неуклюже (но если вы можете жить с этим , отлично работает).
Alex Paven

2
Эх, на самом деле нет, я не думаю, что возможно и то, и другое; Консольное приложение помечается как CUI в своем PE-заголовке и, таким образом, автоматически хорошо взаимодействует с CMD. С другой стороны, приложение с графическим интерфейсом пользователя немедленно возвращает управление CMD, и даже если оно может повторно подключиться к консоли, чтение и запись будут смешиваться со следующими выходами в конвейере, что, очевидно, очень плохо. Если, с другой стороны, вы помечаете приложение как консольное, вам нужно только жить с CMD, кратко отображаемым при запуске приложения; затем вы можете использовать FreeConsole для отсоединения и присоединения / выделения позже и т. д.
Alex Paven

1
Зачем это делать, если ответ Брайана тоже работает и намного проще.
Wouter Janssens

2
Возможно, это очевидно, но я обнаружил, что Console.WriteLine по-прежнему не работает с использованием этого метода, когда был подключен отладчик Visual Studio. Когда я запустил приложение за пределами VS, оно сработало. Спасибо.
aboy021

2
@Mark Да, но это не работает ... Есть SetConsoleCtrlHandlerфункция, которая позволяет получать уведомления, когда CTRL_CLOSE_EVENTсобытие происходит, но вы ничего не можете с этим сделать, нет ничего, что позволяло бы вашему приложению продолжать работу. Вы будете отключены. Если вы хотите взломать, вы, вероятно, можете поменять обработчик сообщений Windows на консольный процесс и просто сбросить сообщение WM_CLOSE, я никогда не пробовал этого, но это может сработать. Это просто еще одно окно, но с учетом сказанного, если вы не хотите поддерживать эту идею, ваши усилия, вероятно, лучше потратить на что-то другое.
Джон Лейдегрен,

131

Ты можешь использовать

Trace.WriteLine("text");

Это будет выводиться в окно «Вывод» в Visual Studio (при отладке).

убедитесь, что в комплект входит диагностическая сборка:

using System.Diagnostics;

9
это лучший ответ, но не самый высокий рейтинг
kiltek

Согласен - это именно то, о чем просит op. Отличная альтернатива Console.WriteLine () - решение, помеченное как ответ, является изящным упражнением, но его неразумно включать в производственное приложение.
nocarrier

4
PS для приложений Магазина Windows (среда выполнения Windows) эквивалентом Trace.WriteLine является Debug.WriteLine ()
nocarrier

Это простое и понятное решение, но мне оно не подошло. Не работал в методе seed framework entity framework во время обновления базы данных. В остальном работает везде!
Charles W

Это лучшее решение. Было бы лучше, если бы в ответе также говорилось, что он Console.WriteLineвообще не предназначен для приложений WPF и предназначен только для приложений командной строки.
Эндрю Костер,

129

Щелкните правой кнопкой мыши проект, «Свойства», вкладку «Приложение», измените «Тип вывода» на «Консольное приложение», и тогда у него также будет консоль.


3
Единственная проблема в том, что у вас будет 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
Не правильный ответ. Скрывает основные окна. Подходит только консоль.
Yash

не работает с wpf, нет главного окна
alp

12

Хотя Джон Лейдегрен продолжает опровергать эту идею, Брайан прав. Я только что начал работать в Visual Studio.

Для ясности, приложение WPF по умолчанию не создает окно консоли.

Вы должны создать приложение WPF, а затем изменить OutputType на «Консольное приложение». Когда вы запустите проект, вы увидите окно консоли с окном WPF перед ним.

Это выглядит не очень красиво, но я нашел его полезным, так как я хотел, чтобы мое приложение запускалось из командной строки с обратной связью, а затем для определенных параметров команды я отображал окно WPF.


1
Отлично. Делает работу.
Frostymarvelous


9

Старый пост, но я столкнулся с этим, поэтому, если вы пытаетесь вывести что-то в Output в проекте WPF в Visual Studio, современный метод:

Включите это:

using System.Diagnostics;

А потом:

Debug.WriteLine("something");

4

Я использую Console.WriteLine () для использования в окне вывода ...


4
Это вопрос четырехлетней давности, который сильно отредактировали с тех пор, как я впервые его увидел. Теперь, конечно, вопрос был сформулирован лучше, и мой ответ стал неуместным.
erodewald

1

Я создал решение, смешав информацию о посте varius.

Это форма, которая содержит метку и одно текстовое поле. Вывод консоли перенаправляется в текстовое поле.

Также существует класс 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
}

Надеюсь, этот результат окажется полезным.



-17

Насколько мне известно, Console.WriteLine () предназначена только для консольных приложений. Думаю, это твоя проблема.


1
Я не знаю о WPF, но это определенно не относится к WinForms. Console.WriteLine там отлично работает, но, конечно, вы не увидите консоль, вы увидите ее в окне вывода отладчика и если вы слушаете стандартный вывод.
Джефф Йейтс

2
вы можете настроить проект как консольное приложение, и он по-прежнему будет работать как приложение для Windows, но у него также будет видимая консоль
Марк Сидаде,

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