C#WPF应用程序捕获python脚本控制台输出

时间:2018-03-13 03:55:25

标签: c# python wpf

我已经尝试了几个小时来弄清楚如何做到这一点,但我有一个python脚本,它被制作成一个exe,所以它作为一个控制台应用程序我试图用WPF编写一个GUI包装器我将它设置为使用命令参数执行exe的位置,但我想从控制台捕获输出并将其显示在文本框中,我无法弄明白。我已经尝试了多个代码片段,但它不执行任何操作,在python exe完成后输出,或者锁定GUI直到python exe完成,然后将完成的输出转储到文本框。

有人能够看一看,看看他们是否可以帮助我吗?

public partial class MainWindow : Window


{

    //string output = string.Empty;
    private static StringBuilder output = new StringBuilder();
    private object syncGate = new object();
    private Process process;
    private bool outputChanged;


    public MainWindow()
    {
        InitializeComponent();
    }

    private void RB_Mii_Checked(object sender, RoutedEventArgs e)
    {   
    }

    //If we click the button we copy the bin file to the work directory
    private void btn_SelMiiQR_Click(object sender, RoutedEventArgs e)
    {
        //Copy the encrypted.bin file to the working directory
        OpenFileDialog openFileDialog = new OpenFileDialog();
        openFileDialog.Filter = "Input.bin (*.bin)|*.bin|All files (*.*)|*.*";
        openFileDialog.InitialDirectory = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
        if (openFileDialog.ShowDialog() == true)
        {
            var fileName = openFileDialog.FileName;
            String exePath = System.Reflection.Assembly.GetExecutingAssembly().GetModules()[0].FullyQualifiedName;
            //If the file exists delete the existing file and copy the newone.
            if (System.IO.File.Exists(System.IO.Path.GetDirectoryName(exePath) + "\\App\\" + System.IO.Path.GetFileName(fileName)))
            {
                System.IO.File.Delete(System.IO.Path.GetDirectoryName(exePath) + "\\App\\" + System.IO.Path.GetFileName(fileName));
            }
                System.IO.File.Copy(fileName, System.IO.Path.GetDirectoryName(exePath) + "\\App\\" + System.IO.Path.GetFileName(fileName));
        }

    }

    //If the button was clicked use the input.bin file and attempt to brute force the movable_sedpart1.bin
    private void BTN_MIIBF_Click(object sender, RoutedEventArgs e)
    {
        //If the mfg has input year or no input use it
        if (TB_MFGYR.Text.Length == 0 || TB_MFGYR.Text.Length == 4)
        {
            string DStype = null;
            string MFGYR = null;
            //Grab the Year if it has value
            if (TB_MFGYR.Text.Length == 4)
            {
                 MFGYR = TB_MFGYR.Text;
            }
            else
            {
                MFGYR = null;
            }

            if (RB_N3ds.IsChecked == true)
            {
                DStype = "new";
            }

            else if (RB_O3DS.IsChecked == true)
            {
                DStype = "old";
            }


            //Execute Command with Arguments
            String exePath = System.Reflection.Assembly.GetExecutingAssembly().GetModules()[0].FullyQualifiedName;
            string dir = System.IO.Path.GetDirectoryName(exePath)+"\\App\\";

            //Start the process and export thr console output to the textbox
            CreateProcess(dir + "seedminer_launcher.exe", "Mii " + DStype + " " + MFGYR, dir);


        }
        //Else display Error Message WIP
        else
        {
            tb_outputtext.Text = null;
            tb_outputtext.Text = "MFG Year must have 4 characters or none";
        }
    }

    //Execute a new process
    private void CreateProcess(string fileName, string arguments, string workdir)
    {
        // Process process = new Process();
        process = new Process();
        process.StartInfo.FileName = fileName;
        process.StartInfo.Arguments = arguments;
        process.StartInfo.UseShellExecute = false;
        process.StartInfo.CreateNoWindow = true;
        process.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
        process.StartInfo.RedirectStandardOutput = true;
        process.StartInfo.RedirectStandardError = true;
        process.StartInfo.WorkingDirectory = workdir;
        process.OutputDataReceived += proc_OutputDataReceived;


        process.Start();
        process.BeginOutputReadLine();

    }

    void proc_OutputDataReceived(object sender, DataReceivedEventArgs e)
    {
        this.Dispatcher.Invoke((Action)(() =>
        {
            tb_outputtext.Text = tb_outputtext.Text + "\n" + e.Data;
            tb_outputtext.ScrollToEnd();
        }));

    }


    private void ReadData()
    {
        var input = process.StandardOutput;
        int nextChar;
        while ((nextChar = input.Read()) >= 0)
        {
            lock (syncGate)
            {
                output.Append((char)nextChar);
                if (!outputChanged)
                {
                    outputChanged = true;
                    var dispatcher = Application.Current.MainWindow.Dispatcher;
                    Dispatcher.BeginInvoke(new Action(OnOutputChanged));
                }
            }
        }
        lock (syncGate)
        {
            process.Dispose();
            process = null;
        }
    }

    private void OnOutputChanged()
    {
        lock (syncGate)
        {
            tb_outputtext.AppendText(output.ToString());
            outputChanged = false;
        }
    }


}

1 个答案:

答案 0 :(得分:0)

如果我理解正确,那么你希望你的WPF应用程序在python可执行文件运行时不断更新TextBox的内容吗?

我已经删除了你的代码并使用了Windows命令ping -t 127.0.0.1 -w 10000,它每秒生成一个新行来测试你的代码。在我的机器上,您的代码按预期工作:WPF文本框中的输出每秒更新一次。

如果在下面的代码中将ping命令替换为python可执行文件,会发生什么?你的python脚本是否在每一行之后输出换行符(如Process.OutputDataReceived Event中所述)?

<强> MainWindow.xaml.cs

using System;
using System.Diagnostics;
using System.Windows;

namespace SO_Continous_Process_Output
{
    public partial class MainWindow : Window
    {
        private Process process;

        public MainWindow()
        {
            InitializeComponent();

            CreateProcess("ping", "-t 127.0.0.1 -w 1000", "");
        }

        //Execute a new process
        private void CreateProcess(string fileName, string arguments, string workdir)
        {
            // Process process = new Process();
            process = new Process();
            process.StartInfo.FileName = fileName;
            process.StartInfo.Arguments = arguments;
            process.StartInfo.UseShellExecute = false;
            process.StartInfo.CreateNoWindow = true;
            process.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
            process.StartInfo.RedirectStandardOutput = true;
            process.StartInfo.RedirectStandardError = true;
            process.StartInfo.WorkingDirectory = workdir;
            process.OutputDataReceived += proc_OutputDataReceived;

            process.Start();
            process.BeginOutputReadLine();
        }

        void proc_OutputDataReceived(object sender, DataReceivedEventArgs e)
        {
            this.Dispatcher.Invoke((Action)(() =>
            {
                tb_outputtext.Text = tb_outputtext.Text + "\n" + e.Data;
                tb_outputtext.ScrollToEnd();
            }));
        }
    }
}

<强> MainWindow.xaml

<Window x:Class="SO_Continous_Process_Output.MainWindow"
        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"
        mc:Ignorable="d"
        Title="MainWindow" Height="350" Width="525">
    <Grid>
        <TextBox Name="tb_outputtext" Text="{Binding ProcessOutput}"></TextBox>
    </Grid>
</Window>

更新

Python脚本

我编写了一个python脚本来测试输出是否有效,我必须设置flush=True才能使其正常工作。

import time

while True:
    print('hi!', flush=True)
    time.sleep(1)