3

Windowsフォームのc#アプリケーションを開発しました。GUIフォームをブロックせずに別のスレッドをスピンオフして、メインフォームのリストボックスの項目を更新したいだけです。スレッドはリストボックスのようなフォームエンティティにアクセスできないため、デリゲートを使用することを考えました。以下のコードは、デリゲートを使用してそのタスクを実行する方法を示していますが、GUIフォームがブロックされています。だから私はそれをGUIフォームをブロックせずにリストボックスを更新する非同期デリゲートに変換したいだけです

デリゲート宣言

 delegate void monitoringServiceDel();

代理人に電話する

new monitoringServiceDel(monitoringService).BeginInvoke(null, null);

デリゲートメソッドの実装

private void monitoringService()
{
        this.listEvents.Invoke(new MethodInvoker(delegate()
        {
            int i = 0 ;
            while (i<50)
            {

                listEvents.Items.Add("count :" + count++);
                Thread.Sleep(1000);
                i ++;
            }

        }));


}
4

4 に答える 4

8

Winフォームの場合、コントロールのInvokeメソッドを使用する必要があります。

コントロールの基になるウィンドウハンドルを所有するスレッドで指定されたデリゲートを実行します

基本的なシナリオは次のとおりです。

次のようなもの:

var bw = new BackgroundWorker();
bw.DoWork += (sender, args) => MethodToDoWork;
bw.RunWorkerCompleted += (sender, args) => MethodToUpdateControl;
bw.RunWorkerAsync();

これにより、正しい方向に進むことができます。

編集:作業サンプル

public List<string> MyList { get; set; }

private void button1_Click( object sender, EventArgs e )
{
    MyList = new List<string>();

    var bw = new BackgroundWorker();
    bw.DoWork += ( o, args ) => MethodToDoWork();
    bw.RunWorkerCompleted += ( o, args ) => MethodToUpdateControl();
    bw.RunWorkerAsync();
}

private void MethodToDoWork()
{
    for( int i = 0; i < 10; i++ )
    {
        MyList.Add( string.Format( "item {0}", i ) );
        System.Threading.Thread.Sleep( 100 );
    }
}

private void MethodToUpdateControl()
{
    // since the BackgroundWorker is designed to use
    // the form's UI thread on the RunWorkerCompleted
    // event, you should just be able to add the items
    // to the list box:
    listBox1.Items.AddRange( MyList.ToArray() );

    // the above should not block the UI, if it does
    // due to some other code, then use the ListBox's
    // Invoke method:
    // listBox1.Invoke( new Action( () => listBox1.Items.AddRange( MyList.ToArray() ) ) );
}
于 2012-04-04T04:48:51.677 に答える
2

最も簡単な解決策はBackgroundWorker、2つと組み合わせてコントロールを使用することPanelsです。Visibleアイデアは、フォームが読み込まれるときに前面に1つのパネルを配置し、ImageBoxその内部に単純な読み込みgifを再生するパネルを配置することです。はListBox、デフォルトでは表示されない他のパネルの内側にあり、最初のパネルのすぐ後ろにあります。

フォームが読み込まれたら、BackgroundWorkerデータの取得または更新を開始して実行します。タスクが完了したら、リストボックス内にデータを設定し、ListBoxパネルを表示して表示します。

そうすればListBox、すべてのアイテムが追加された後に更新されることなく、の半非同期ロードが可能になります。この手法は、フォームの読み込みだけでなく、いつでも使用できます。

コード例は次のとおりです。

namespace AsyncForm
{
    public partial class Form1 : Form
    {

        private List<String> collectionItems = new List<String>();

        public Form1()
        {
            InitializeComponent();
        }

        private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
        {
            for (int i = 0; i < 20; i++)
            {
                ((List<String>)e.Argument).Add("Something " + i);
                System.Threading.Thread.Sleep(200);
            }
        }

        private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            listBox1.Items.AddRange(collectionItems.ToArray());
            listBox1.Visible = true;
            pictureBox1.Visible = false;
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            backgroundWorker1.RunWorkerAsync(collectionItems);
        }
    }
}
于 2012-04-04T04:09:05.957 に答える
2

UI要素を変更する場合は、UIスレッドをブロックする必要があります。アイテムがバーストして来る場合、または各アイテムを追加する間に処理が必要な場合は、バックグラウンドワーカーまたはタスクを介して処理をバックグラウンドで実行することを検討することをお勧めします。ただし、データを取得してリストにデータを入力するだけの場合は、UIスレッドを使用する必要があります。

于 2012-04-04T03:49:07.287 に答える
1

UIを更新する機能と長時間のプロセスを分離する必要があります。

UIロジックを処理します。

    private void UpdateUI(string item) 
    {
        if (Thread.CurrentThread.IsBackground) 
        {
            listEvents.Dispatcher.Invoke(new Action(() => //dispatch to UI Thread
            {
                listEvents.Items.Add(item);
            }));
        }
        else
        {
            listEvents.Items.Add(item);
        }
    }

TaskParallelを使用して非同期プロセスを実行するには

    private void Dowork()
    {
        Task task = Task.Factory.StartNew(() =>
        {
            int i = 0;
            while (i < 10)
            {
                Thread.Sleep(1000);
                UpdateUI(i.ToString());
                i++;
            }
        });
    }
于 2012-04-04T05:32:06.760 に答える