2016-11-17 5 views
0

特定のネットワークをスキャンして有効なIPアドレスを返すWinFormsプロジェクトがあります。すべてのアドレスが見つかると、それぞれのユーザーコントロールを作成してフォームに配置します。 ipアドレスへの私の機能は、何か他のことをする前に実行するのを "待つ"と思ったasyncTaskを使っていますが、そうではありません。フォームが空白になり、5秒以内にすべてのユーザーコントロールがフォームに表示されます。非同期関数が完了する前にフォームが表示されています

宣言:

private List<string> networkComputers = new List<string>(); 

ここForm_Loadイベントだ:

private async void MainForm_Load(object sender, EventArgs e) 
{ 
    //Load network computers. 
    await LoadNetworkComputers(); 
    LoadWidgets(); 
} 

LoadNetworkComputers機能はここにある:

private async Task LoadNetworkComputers() 
{ 
    try 
    { 
     if (SplashScreenManager.Default == null) 
     { 
      SplashScreenManager.ShowForm(this, typeof(LoadingForm), false, true, false); 
      SplashScreenManager.Default.SetWaitFormCaption("Finding computers"); 
     } 
     else 
      Utilities.SetSplashFormText(SplashForm.SplashScreenCommand.SetLabel, "Scanning network for computers. This may take several minutes..."); 

     networkComputers = await GetNetworkComputers(); 
    } 
    catch (Exception e) 
    { 
     MessageBox.Show(e.Message + Environment.NewLine + e.InnerException); 
    } 
    finally 
    { 
     //Close "loading" window. 
     SplashScreenManager.CloseForm(false); 
    } 
} 

そして最後に2つの機能:

private async Task<List<string>> GetNetworkComputers() 
{ 
    networkComputers.Clear(); 
    List<string> ipAddresses = new List<string>(); 
    List<string> computersFound = new List<string>(); 

    for (int i = StartIPRange; i <= EndIPRange; i++) 
     ipAddresses.Add(IPBase + i.ToString()); 

    List<PingReply> replies = await PingAsync(ipAddresses); 

    foreach(var reply in replies) 
    { 
     if (reply.Status == IPStatus.Success) 
      computersFound.Add(reply.Address.ToString()); 
    } 

    return computersFound; 
} 

private async Task<List<PingReply>> PingAsync(List<string> theListOfIPs) 
{ 
    var tasks = theListOfIPs.Select(ip => new Ping().SendPingAsync(ip, 2000)); 
    var results = await Task.WhenAll(tasks); 

    return results.ToList(); 
} 

MainForm_Loadイベントのコードが終了する前に、フォームが表示されている理由について私は本当に固執しています。私はLoadNetworkComputersで、それはユーザーがアプリが実行されていることを知ることができますスプラッシュフォームをロードすることを言及するのを忘れ

EDIT 。フォームがその背後に現れ、私が避けようとしているときです。ここで、スクリーンショットは(機密情報がブラックアウトされています)です: enter image description here

+0

おそらく私は何かが不足していますが、長時間の操作が進んでいる間にコードを続行できるようにすることは非同期/完全な目的ではありませんか? – Steve

答えて

2

async-awaitの理由は、関数の呼び出し側が関数が何かを待たなければならないときはいつでもコードを実行できるようにするためです。

素晴らしいことは、待っている機能が終了していなくても、これがあなたのUIを反応的に保つことです。たとえば、LoadNetworkComputersLoadWidgetsのボタンを使用する場合、この比較的長い動作の間はウィンドウはまだ再描画されていることがうれしいでしょう。

Mainform_Loadを非同期として定義しているので、LoadNetWorkComputersの結果を待たずにUIを続行することを表明しています。

In this interview with Eric Lippert(async-awaitのために真ん中で検索)async-awaitは、料理を作る夕食と比較されます。料理人がパンを乾かすのを待たなければならないときはいつでも、彼は周りを見回して何か他のことをすることができるかどうかを調べ始めます。しばらくしてパンが焼かれると、彼は焼かれたパンを準備し続けます。

フォームロードを非同期にすることで、フォームが表示され、ネットワークコンピュータがロードされていることを示すことさえできます。

さらに良い方法は、プログラムがネットワークコンピュータを読み込んでいることを示す簡単な起動ダイアログを作成することです。このスタートアップダイアログの非同期フォームロードは、アクションを実行して終了するとフォームを閉じることができます。

public class MyStartupForm 
{ 
    public List<string> LoadedNetworkComputers {get; private set;} 

    private async OnFormLoad() 
    { 
     // start doing the things async. 
     // keep the UI responsive so it can inform the operator 
     var taskLoadComputers = LoadNetworkComputers(); 
     var taskLoadWidgets = LoadWidgets(); 
     await Task.WhenAll(new Task{} {taskLoadComputers, taskLoadWidgets}); 

     this.LoadedNetworkCoputers = taskLadComputers.Result; 
     this.Close(); 
    } 
} 

そして、あなたのメインフォーム:ロード中に

private void MainForm_Load(object sender, EventArgs e) 
{ 
    using (var form = new MyStartupForm()) 
    { 
     form.ShowDialog(this); 
    } 
} 

は今、あなたのMainFormを示したが、StartupFormされていません。メインフォームがなぜまだ表示されていないのか、オペレーターに通知されます。これははるかに良いUIです。

1

私のフォームは空白現れ、その後、5秒以内に、すべてのユーザーコントロールがフォームに表示されます。

これは仕様です。 UIフレームワークでフォームを表示するようにアプリに指示するときは、すぐにとする必要があります。

async仕事これを解決するには、あなたが更新 UIを使用すると、あなたのアプリは、起動時にその状態を初期化し、async作業が進行している間に見えるようにしたいものを決定する必要があり、その後、ますが完了する。スピナーとローディングページは一般的な選択です。

関連する問題