2017-01-13 2 views
0

だから私はC#を初めて使っています。私はPowerShellで私のツール(7年分のツール)をビルドしていましたが、Visual Studioライセンスを手に入れることはできませんでしたが、今は持っています...c#Powershell Consoleでリアルタイムにテキストボックスを更新する

私はsystem.componentmodel.backgroundworkerについて読んでいます私はそれを実装するのに問題があります。

Heres my code with Background worker and with。誰かが

using System; 
using System.Text; 
using System.Windows.Forms; 
using System.Collections.ObjectModel; 
using System.Management.Automation; 
using System.Management.Automation.Runspaces; 
using System.IO; 


namespace ServerStatusChecks 
{ 
    public partial class Form1 : Form 
    { 
     public Form1() 
     { 
      InitializeComponent(); 
     } 


    private void button1_Click(object sender, EventArgs e) 
     { 

      // run our script and put the result into our textbox 
      // NOTE: make sure to change the path to the correct location of your script 
      textBox1.Text = RunScript(LoadScript(@"c:\utils\Script.ps1")); 
     } 

     // helper method that takes your script path, loads up the script 
     // into a variable, and passes the variable to the RunScript method 
     // that will then execute the contents 
     private string LoadScript(string filename) 
     { 

      try 
      { 
       // Create an instance of StreamReader to read from our file. 
       // The using statement also closes the StreamReader. 
       using (StreamReader sr = new StreamReader(filename)) 
       { 


        // use a string builder to get all our lines from the file 
        StringBuilder fileContents = new StringBuilder(); 

        // string to hold the current line 
        string curLine; 

        // loop through our file and read each line into our 
        // stringbuilder as we go along 
        while ((curLine = sr.ReadLine()) != null) 
        { 
         // read each line and MAKE SURE YOU ADD BACK THE 
         // LINEFEED THAT IT THE ReadLine() METHOD STRIPS OFF 
         fileContents.Append(curLine + "\n"); 
        } 

        // call RunScript and pass in our file contents 
        // converted to a string 
        return fileContents.ToString(); 
       } 
      } 
      catch (Exception e) 
      { 
       // Let the user know what went wrong. 
       string errorText = "The file could not be read:"; 
       errorText += e.Message + "\n"; 
       return errorText; 
      } 



     } 


     // Takes script text as input and runs it, then converts 
     // the results to a string to return to the user 
     private string RunScript(string scriptText) 
     { 
      // create Powershell runspace 
      Runspace runspace = RunspaceFactory.CreateRunspace(); 

      // open it 
      runspace.Open(); 

      // create a pipeline and feed it the script text 
      Pipeline pipeline = runspace.CreatePipeline(); 
      pipeline.Commands.AddScript(scriptText); 

      // add an extra command to transform the script output objects into nicely formatted strings 
      // remove this line to get the actual objects that the script returns. For example, the script 
      // "Get-Process" returns a collection of System.Diagnostics.Process instances. 
      pipeline.Commands.Add("Out-String"); 

      // execute the script 
      Collection<PSObject> results = pipeline.Invoke(); 

      // close the runspace 
      pipeline.Dispose(); 
      runspace.Close(); 

      // convert the script result into a single string 
      StringBuilder stringBuilder = new StringBuilder(); 
      foreach (PSObject obj in results) 
      { 
       stringBuilder.AppendLine(obj.ToString()); 

      } 

      // return the results of the script that has 
      // now been converted to text 
      return stringBuilder.ToString(); 
     } 
     private void Form1_Load(object sender, EventArgs e) 
     { 

     } 
     private void textBox1_TextChanged(object sender, EventArgs e) 
     { 


     } 


    } 

} 

は今ここにあるテキストボックスに(多少)私はPowerShellのジョブをキックオフするとき、私のUIが応答しなく行かないと私は実際に得ることができるので、私はそれを実装することができますどのように実際の更新を見に私を助けることができます私と一緒にコードの問題はあなたが何を実行していないということであるBW(私はそれがいくつかの方法を動作するように取得しようとしました、それは今混乱だとしてそれはモンスターのビットです)

using System; 
using System.Text; 
using System.Windows.Forms; 
using System.Collections.ObjectModel; 
using System.Management.Automation; 
using System.Management.Automation.Runspaces; 
using System.ComponentModel; 
using System.Threading; 
using System.IO; 


namespace ServerStatusChecks 
{ 
    public partial class Form1 : Form 
    { 
     private BackgroundWorker bw = new BackgroundWorker(); 
     public Form1() 
     { 
      InitializeComponent(); 
      bw.WorkerReportsProgress = true; 
      bw.WorkerSupportsCancellation = true; 
      bw.DoWork += new DoWorkEventHandler(bw_DoWork); 
     } 


     private string LoadScript(string filename) 
     { 

      try 
      { 
       // Create an instance of StreamReader to read from our file. 
       // The using statement also closes the StreamReader. 
       using (StreamReader sr = new StreamReader(filename)) 
       { 


        // use a string builder to get all our lines from the file 
        StringBuilder fileContents = new StringBuilder(); 

        // string to hold the current line 
        string curLine; 

        // loop through our file and read each line into our 
        // stringbuilder as we go along 
        while ((curLine = sr.ReadLine()) != null) 
        { 
         // read each line and MAKE SURE YOU ADD BACK THE 
         // LINEFEED THAT IT THE ReadLine() METHOD STRIPS OFF 
         fileContents.Append(curLine + "\n"); 
        } 

        // call RunScript and pass in our file contents 
        // converted to a string 
        return fileContents.ToString(); 
       } 
      } 
      catch (Exception e) 
      { 
       // Let the user know what went wrong. 
       string errorText = "The file could not be read:"; 
       errorText += e.Message + "\n"; 
       return errorText; 

      } 
     } 

     private void button1_Click(object sender, EventArgs e) 
     { 
      if (bw.IsBusy != true) 
      { 
       bw.RunWorkerAsync(); 
      } 
      // run our script and put the result into our textbox 
      // NOTE: make sure to change the path to the correct location of your script 
      textBox1.Text = RunScript(LoadScript(@"c:\utils\Script.ps1")); 
     } 
     private void bw_DoWork(object sender, EventArgs e) 
     { 

     } 

     // Takes script text as input and runs it, then converts 
     // the results to a string to return to the user 
     private string RunScript(string scriptText) 
     { 
      // create Powershell runspace 
      Runspace runspace = RunspaceFactory.CreateRunspace(); 

      // open it 
      runspace.Open(); 

      // create a pipeline and feed it the script text 
      Pipeline pipeline = runspace.CreatePipeline(); 
      pipeline.Commands.AddScript(scriptText); 

      // add an extra command to transform the script output objects into nicely formatted strings 
      // remove this line to get the actual objects that the script returns. For example, the script 
      // "Get-Process" returns a collection of System.Diagnostics.Process instances. 
      pipeline.Commands.Add("Out-String"); 

      // execute the script 
      Collection<PSObject> results = pipeline.Invoke(); 

      // close the runspace 
      pipeline.Dispose(); 
      runspace.Close(); 

      // convert the script result into a single string 
      StringBuilder stringBuilder = new StringBuilder(); 
      foreach (PSObject obj in results) 
      { 
       stringBuilder.AppendLine(obj.ToString()); 

      } 

      // return the results of the script that has 
      // now been converted to text 
      return stringBuilder.ToString(); 
     } 

     // helper method that takes your script path, loads up the script 
     // into a variable, and passes the variable to the RunScript method 
     // that will then execute the contents 
     private void Form1_Load(object sender, EventArgs e) 
     { 
      Thread.Sleep(1000); 
     } 
     private void textBox1_TextChanged(object sender, EventArgs e) 
     { 
      Thread.Sleep(1000); 
     } 

    } 

} 

答えて

1

を実装しようbw_DoWorkイベントは、実際のバックグラウンド作業が実行される場所です。次のコードのこのセクションを変更する必要があります。

private void button1_Click(object sender, EventArgs e) 
    { 
     if (bw.IsBusy != true) 
     { 
      bw.RunWorkerAsync(); 
     } 
    } 
    private void bw_DoWork(object sender, EventArgs e) 
    { 
     // run our script and put the result into our textbox 
     // NOTE: make sure to change the path to the correct location of your script 
     textBox1.Text = RunScript(LoadScript(@"c:\utils\Script.ps1")); 
    } 

この作品の理由はbw_DoWork方法は、あなたがた、それはRunWorkerAsync()メソッドが呼び出されたときのために、「リッスン」を意味し、イベントリスナー、ということですボタンがクリックされたとき。 bw_DoWorkRunWorkerAsync()機能をリッスンするために知っているあなたは、プログラムの先頭に置く行ためです:

bw.DoWork += new DoWorkEventHandler(bw_DoWork); 

これは基本的に座るとオフ発射するイベントを待つDoWorkに指示します。これは一般に「イベントに加入する」と呼ばれます。このとき、UIを含む元のスレッド(一般的に 'UIスレッド'と呼ばれます)がトラックに保存されている間に、bwDoWorkイベントにあるものはすべて新しいスレッドが生成されます。イベントと非同期のスレッドは、あなたの頭を囲むトリッキーなテーマですが、一度それを行うと、.NETの素晴らしい部分です。

EDIT: さてさて、そう上記は限りbwが正常に実行するために取得することと正しいですが、それは、このエラーが発生します。

Error: {"Cross-thread operation not valid: Control 'textBox1' accessed from a thread other than the thread it was created on."}

私はメインスレッドは、「UIと呼ばれていると述べた上糸"。これは、UIがそのスレッドにロックされていることを意味します。したがって、BackgroundWorkerはUI要素に触れることができません。したがって、問題のある行はtextBox1.Text = RunScript(LoadScript(@"c:\utils\Script.ps1"));

RunScript()に公開値に値を渡し、bwの処理が完了した後に変数を代入するのが最も簡単な方法です。 BackgroundWorkerの別のビルトインイベントにご登録いただくと、RunWorkerCompletedと表示されます。Form1を変更することでbwに新しいリスナーを追加し、その後

static string RunScriptResult; 

まず、クラスの先頭に新しい静的な文字列を宣言

public Form1() 
    { 
     //... 
     bw.DoWork += new DoWorkEventHandler(bw_DoWork); 
     bw.RunWorkerCompleted += new bw_RunWorkerCompleted; //new listener event 
    } 

次に、割り当てることbw_DoWorkを変更します先に作成した文字列への出力:

private void bw_DoWork(object sender, EventArgs e) 
{ 
    RunScriptResult = RunScript(LoadScript(@"c:\utils\Script.ps1")); 
} 

次に、RunWorkerCompletedのための新しいイベントハンドラメソッドを追加します。bwが終了するまで

private void bw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) 
    { 
     textBox1.Text = RunScriptResult; 
    } 

上記のイベントは発生しません。また、UIスレッドで実行されます。これらの変更により、必要な場所に移動できます。

+0

おかげで次のステップに進んでくれました!ただし、呼び出しはスレッドセーフではなく、戻りデータがクラッシュしています。エラー:{"クロススレッド操作が有効でない:コントロール 'textBox1'が作成されたスレッド以外のスレッドからアクセスされました。}} – Ericrs

+0

回答を更新しました(2回、初めて不足していました!それは助ける! – 3burk

+0

@ king3vbo [クロススレッド操作が有効でない:作成されたスレッド以外のスレッドからアクセスされたコントロール](http://stackoverflow.com/q/142003/1115360) - OPはコントロールが終了したときだけでなく、BGWが実行されている間に更新されます。 –

関連する問題