在线程中创建控件并加载照片异步

时间:2013-10-04 03:47:16

标签: c# multithreading winforms async-await

我有一个Windows窗体,里面有一个Button和一个Panel。

在按钮上单击我正在向面板添加控件...尽可能多。此过程正在使用任务工厂。例如:

private void ButtonClick()
{
// This line needs to happen on the UI thread...
            TaskScheduler uiScheduler = TaskScheduler.FromCurrentSynchronizationContext();

            Task.Factory.StartNew(() =>
            {

               CustomControl.PersonResult newControl = new CustomControl.PersonResult();
               this.panel1.Controls.Add(newControl);

            }, CancellationToken.None, TaskCreationOptions.None, uiScheduler);
}

我的PersonResult.cs控件具有以下布局:

enter image description here

该控件有一个图片框和3个标签。

现在,当一个新的 PersonResult 控件添加到表单中时,我想执行其他后台工作程序,以便从Internet获取图像并将其放在图片框中。

所以,情景是:

我多次按下按钮,我会立即看到自定义控件添加到面板中,但每个控件的图片框都是空的,但是一旦工作人员从互联网加载图像并将其放置,图像就会立即显示在图片框上。

有关如何实现这一点的任何线索?

非常感谢

3 个答案:

答案 0 :(得分:0)

有些事情: 您不必异步添加控件。将它们添加到GUI线程中,每次创建一个新的工作线程,为其提供来自控件的委托,当工作人员完成加载图像时,将委托异步调用(使用BeginInvoke?)。

答案 1 :(得分:0)

每次触摸控件时都必须从UI线程执行此操作。您可以从线程/任务中实际下载图片和其他长时间运行的任务。从您的线程中,您使用Control.Invoke在UI线程上调用委托。

这篇MSDN文章提供了一个使用Control.Invoke和一些简单变量(如字符串等)的好例子:

http://msdn.microsoft.com/en-us/library/a1hetckb(v=vs.100).aspx

但是通常使用辅助类,因此您可以在代理之间传递更复杂的数据,而无需使用大讨厌的对象数组。

以下是我做过的一些示例代码:

    private void button1_Click(object sender, EventArgs e) {

        Task.Factory.StartNew(() =>
            {
                DataClass dataClass = new DataClass(this.textBox1);

                Thread.Sleep(5000); // simulate long running task

                dataClass.TextToPass = "set some text";
                dataClass.updateTargetControl();

            });
    }


    private class DataClass {
        delegate void updateTextBoxOnUiThreadDelegate();

        private TextBox _targetControl= null;
        private updateTextBoxOnUiThreadDelegate _updateDelegate; 




        internal DataClass(TextBox targetControl) {
            _updateDelegate = new updateTextBoxOnUiThreadDelegate(updateOnUiThread);
            _targetControl = targetControl;
        }

        internal string TextToPass = "";


        internal void updateTargetControl() {
            _targetControl.Invoke(_updateDelegate);
        }

        private void updateOnUiThread() {
            _targetControl.Text = this.TextToPass;
        } 

    }

答案 2 :(得分:0)

我不太清楚我理解为什么你在自己的Task中包装了一个UI操作..当它没有链接到异步任务时。

无论如何.. PictureBoxes有一个LoadAsync方法。为什么要比实际需要更难?

private void ButtonClick()
{
    CustomControl.PersonResult newControl = new CustomControl.PersonResult();
    this.panel1.Controls.Add(newControl);
    newControl.PictureBox.WaitOnLoad = false;
    newControl.PictureBox.LoadAsync("http://url-here.com/image.jpg");
}