Bir WPF uygulamasından konsola çıktı yok mu?


113

Çok basit bir WPF test uygulamasından Console.WriteLine () kullanıyorum, ancak uygulamayı komut satırından çalıştırdığımda konsola hiçbir şey yazılmadığını görüyorum. Burada neler olabileceğini bilen var mı?

Bunu, VS 2008'de bir WPF uygulaması oluşturarak ve çalıştırılan her yere Console.WriteLine ("metin") ekleyerek yeniden oluşturabilirim. Herhangi bir fikir?

Şu anda ihtiyacım olan tek şey Console.WriteLine () kadar basit bir şey. Log4net'i veya başka bir günlükleme çözümünü kullanabileceğimin farkındayım, ancak bu uygulama için gerçekten o kadar fazla işlevselliğe ihtiyacım yok.

Düzenleme: Console.WriteLine () 'ın konsol uygulamaları için olduğunu hatırlamalıydım. Oh pekala, aptalca sorular yok, değil mi? :-) Şimdilik sadece System.Diagnostics.Trace.WriteLine () ve DebugView kullanacağım.


Olası çiftleri burada ve burada (daha yeni, fakat kullanarak bazı ilginç cevapları ile Kernel32.dll AttachConsole )
Maksimum

1
@Max, o sorular olası aynısı olan bu soruya. Bu soru, gönderdiğiniz sorulardan 2-4 yıl önce soruldu.
Rob

Yanıtlar:


91

Herhangi bir Console.Write yöntemini gerçekten çağırmadan önce manuel olarak bir Konsol penceresi oluşturmanız gerekir. Bu, Konsolu proje türünü değiştirmeden düzgün çalışmasını sağlar (WPF uygulaması için çalışmaz).

Burada bir ConsoleManager sınıfının nasıl görünebileceğine ve proje türünden bağımsız olarak Konsolu etkinleştirmek / devre dışı bırakmak için nasıl kullanılabileceğine dair eksiksiz bir kaynak kodu örneği verilmiştir.

Aşağıdaki sınıfla, ConsoleManager.Show()herhangi bir çağrı yapmadan önce bir yere yazmanız yeterlidir 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
Önce AttachConsole (-1) 'i çağırmayı denemek ve ana sürecin konsoluna eklemek için dönüş değerini kontrol etmek mümkündür; yanlış dönerse, AllocConsole'u çağırın. Ancak, uygulama yine de önce 'geri dönüyor' ve ancak daha sonra konsola çıktı veriyor, bir çözüm bulursam daha fazlasını göndereceğim. Ayrıca, WPF uygulama türünü Konsol Uygulaması olarak ayarlarsanız, sorun ortadan kalkar, ancak program başladığında ekranda kısa bir süre gösterilmeden konsolu ayıramazsınız, bu nedenle biraz garip görünür (ancak onunla yaşayabilirseniz) harika çalışıyor).
Alex Paven

2
Eh, aslında hayır, ikisine birden sahip olmanın mümkün olduğunu sanmıyorum; Konsol uygulaması, PE başlığında CUI olarak işaretlenir ve bu nedenle CMD ile otomatik olarak iyi işbirliği yapar. Öte yandan bir GUI uygulaması, kontrolü CMD'ye hemen döndürür ve konsola yeniden bağlanabilse bile, okuma ve yazma işlemi, açık bir şekilde çok kötü olan, ardışık düzenteki sonraki çıktılarla karışacaktır. Öte yandan uygulamayı Konsol uygulaması olarak işaretlerseniz, CMD'nin uygulama başlangıcında kısaca gösterilmesi yeterlidir; daha sonra ayırmak ve daha sonra Eklemek / Tahsis etmek için FreeConsole'u kullanabilirsiniz
Alex Paven

1
Brian'ın cevabı işe yaradığında ve çok daha kolayken bunu neden yapalım?
Wouter Janssens

2
Açık olabilir, ancak Visual Studio hata ayıklayıcı eklendiğinde Console.WriteLine'ın hala bu tekniği kullanarak çalışmadığını buldum. Uygulamayı VS'nin dışında çalıştırdığımda bir tedavi işe yaradı. Teşekkürler.
aboy021

2
@Mark Evet, ama işe yaramıyor ... Olay gerçekleştiğinde SetConsoleCtrlHandlerbildirim CTRL_CLOSE_EVENTalmanıza izin veren bir işlev var ancak onunla hiçbir şey yapamazsınız, uygulamanızın devam etmesine izin veren hiçbir şey yok. Kapatılacaksın. Bilgisayar korsanlığı yapmak gibi hissediyorsanız, muhtemelen konsol işlemi için Windows ileti işleyicisini değiştirebilir ve yalnızca WM_CLOSE mesajını bırakabilirsiniz, bunu hiç denemedim ama işe yarayabilir. Bu sadece başka bir pencere ama bununla birlikte, bu fikri eğlendirmek istemiyorsanız, çabalamanız muhtemelen başka bir şey yapmak için daha iyi harcanır.
John Leidegren

131

Kullanabilirsiniz

Trace.WriteLine("text");

Bu, Visual Studio'daki "Çıktı" penceresine çıktı verir (hata ayıklama sırasında).

Teşhis tertibatının dahil olduğundan emin olun:

using System.Diagnostics;

9
bu en iyi cevap, ancak en yüksek reytinge sahip değil
kiltek

Katılıyorum - bu tam olarak operasyonun istediği şey. Console.WriteLine () 'e harika bir alternatif - yanıt olarak işaretlenen çözüm düzgün bir egzersizdir, ancak bir üretim uygulamasına dahil edilmesi mantıksızdır.
nocarrier

4
Windows Mağazası uygulamaları için PS (Windows Runtime), Trace.WriteLine'ın eşdeğeri Debug.WriteLine ()
nocarrier

Bu basit, temiz bir çözüm, ancak benim için işe yaramadı. Güncelleme veritabanı sırasında varlık çerçevesinin çekirdek yönteminde çalışmadı. Aksi takdirde, her yerde çalışır!
Charles W

Bu en iyi çözüm. Cevabın ayrıca Console.WriteLineWPF uygulamaları için tasarlanmadığını ve yalnızca komut satırı uygulamaları için tasarlandığını da açıklaması daha iyi olur .
Andrew Koster

129

Projeye sağ tıklayın, "Özellikler", "Uygulama" sekmesi, "Çıktı Tipi" ni "Konsol Uygulaması" olarak değiştirin ve ardından bir konsolu da olacaktır.


3
Bununla ilgili tek sorun, arka planda açık bir cmd'ye sahip olmanız, ancak işe yarıyor :).
ykatchou

5
Harika, ancak komut satırı penceresi, uygulama cmd.exe'den çalıştırılmadığında oluşturulacak (bir uygulama için iki pencere oluşturuldu). Ancak bunun için bir çözüm de var: cmd penceresini ShowWindow (hWnd, 0) ile gizleyebilirsiniz. stackoverflow.com/a/10416180/1457197 . Bu çözümü kullandığınızda, konsolda metni yalnızca WPF uygulaması komut satırından yürütüldüğünde göreceksiniz.
CoperNick

"Konsol Uygulaması" türleri için yalnızca XAML'yi (Tasarım Görünümüne erişim olmadan) gösterdiğinden, Blend'de çalışırken onu "Pencere Uygulaması" na geri döndürmeniz gerekeceğini unutmayın. (Blend 2013 itibariyle)

2
Doğru değil ans. Ana pencereleri gizler. Sadece konsol çıkıyor.
Yash

wpf ile çalışmıyor, ana pencere yok
alp

12

John Leidegren bu fikri geri çevirmeye devam etse de Brian haklı. Bunu Visual Studio'da çalıştırdım.

Açık olmak gerekirse, bir WPF uygulaması varsayılan olarak bir Konsol penceresi oluşturmaz.

Bir WPF Uygulaması oluşturmanız ve ardından ÇıktıTipini "Konsol Uygulaması" olarak değiştirmeniz gerekir. Projeyi çalıştırdığınızda, önünde WPF pencerenizin olduğu bir konsol penceresi göreceksiniz.

Çok hoş görünmüyor, ancak uygulamamın komut satırından orada geri bildirimle çalıştırılmasını istediğim için yararlı buldum ve ardından belirli komut seçenekleri için WPF penceresini görüntüleyecektim.


1
Mükemmel. İş yapar.
soğuk harikulade

10

Komut satırı yeniden yönlendirmesini kullanarak konsol için amaçlanan çıktıyı görmek mümkündür .

Örneğin:

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

tüm içeriği output.txtdosyaya yazacak .


En iyi cevap basit olduğu ve kaynakta değişiklik gerektirmediği için
buckley

9

Eski gönderi, ancak bununla karşılaştım, bu nedenle Visual Studio'da bir WPF projesinde Çıktıya bir şey çıkarmaya çalışıyorsanız, çağdaş yöntem şudur:

Şunu dahil et:

using System.Diagnostics;

Ve sonra:

Debug.WriteLine("something");

4

Çıktı penceresinde kullanmak için Console.WriteLine () kullanıyorum ...


4
İlk gördüğümden beri yoğun bir şekilde düzenlenmiş 4 yıllık bir soru. Elbette soru daha iyi ifade edildi ve cevabım ilgisiz hale getirildi.
erodewald

1

Bir çözüm oluşturdum, varius yazısının bilgilerini karıştırdım.

Bir etiket ve bir metin kutusu içeren bir formdur. Konsol çıktısı metin kutusuna yeniden yönlendirilir.

Üç publics yöntemini uygulayan ConsoleView adlı bir sınıf da var: Show (), Close () ve Release (). Sonuncusu konsolu açık bırakmak ve sonuçları görüntülemek için Kapat düğmesini etkinleştirmektir.

Formlara FrmConsole adı verilir. İşte XAML ve c # kodu.

Kullanımı çok basit:

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

Konsolu açmak için. kullanın:

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

Konsola çıktı metni için.

kullanın:

ConsoleView.Close();

Konsolu kapatmak için.

ConsoleView.Release();

Konsolu açık bırakır ve Kapat düğmesini etkinleştirir

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>

Pencerenin kodu:

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 sınıfının kodu

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
}

Umarım bu sonuç işe yarar.



-17

Bildiğim kadarıyla Console.WriteLine () sadece konsol uygulamaları içindir. Sanırım bu senin sorunun.


1
WPF'yi bilmiyorum, ancak bu kesinlikle WinForms için geçerli değil. Console.WriteLine orada iyi çalışıyor, ancak tabii ki konsolu görmeyeceksiniz, Debugger çıktı penceresinde göreceksiniz ve standart çıktıyı dinlerseniz.
Jeff Yates

2
projeyi bir Konsol uygulamasına ayarlayabilirsiniz ve yine de bir Windows uygulaması olarak çalışacaktır, ancak aynı zamanda görünür bir konsolu da olacaktır
Mark Cidade

Bu doğru değil, konsol dışı bir uygulamanın derleme işlemi, deffault ile bir konsol eklemez. Bunu, Console.Write'a yapılan herhangi bir çağrıdan önce AllocConsole () Win32 API işlevini çağırarak manuel olarak yapabilirsiniz, Konsol sınıfı daha sonra bu Konsol penceresiyle çalışacak şekilde başlatılacaktır.
John Leidegren
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.