Winforms 将图像加载到不同线程上的PictureBox中

Winforms 将图像加载到不同线程上的PictureBox中,winforms,multithreading,image,c#-3.0,picturebox,Winforms,Multithreading,Image,C# 3.0,Picturebox,我正试图加载一张根据(英国)邮政编码从谷歌静态地图按需获取的图片 假设我有一个客户,客户有一个地址。客户端的属性之一是邮政编码。我有一个表单可以加载客户。我将客户机ID提供给该表单的构造函数,然后使用LINQ 2 SQL加载包括地址在内的各种信息 private void LoadBranchDetails() { Text_Update_BI_Name.Text = Branch.BranchNumber; Text_Update_BI_Manager.Text = String.Fo

我正试图加载一张根据(英国)邮政编码从谷歌静态地图按需获取的图片

假设我有一个客户,客户有一个地址。客户端的属性之一是邮政编码。我有一个表单可以加载客户。我将客户机ID提供给该表单的构造函数,然后使用LINQ 2 SQL加载包括地址在内的各种信息

private void LoadBranchDetails() {
  Text_Update_BI_Name.Text = Branch.BranchNumber;
  Text_Update_BI_Manager.Text = String.Format("{0} {1}", Branch.PharmacyManager.FirstName, Branch.PharmacyManager.LastName);
  DropDownList_Update_BI_Coordinator.SelectedValue = Branch.CoordinatorID;
  DropDownList_Update_BI_ComputerSystem.SelectedValue = Branch.ComputerSystemID;
  Text_Update_BI_Phone.Text = Branch.PhoneNumber;
  Text_Update_BI_Fax.Text = Branch.FaxNumber;

  Address BranchAddress = Branch.Contact.Addresses.FirstOrDefault();
  Text_Update_AI_House.Text = BranchAddress.HouseNumber;
  Text_Update_AI_Street.Text = BranchAddress.Street;
  Text_Update_AI_Area.Text = BranchAddress.Area;
  Text_Update_AI_Post.Text = BranchAddress.PostCode;
  DropDownList_Update_AI_City.SelectedValue = BranchAddress.City.OID;

  MaskedText_Update_OI_NoPharmacist.Value = Branch.NumberOfPharmacists;
  MaskedText_Update_OI_NoDispensers.Value = Branch.NumberOfDispensers;
  MaskedText_Update_OI_NoMonFri.Value = Branch.NumberOfItemsMondayToFriday;
  MaskedText_Update_OI_NoSat.Value = Branch.NumberOfItemsSaturday;
  MaskedText_Update_OI_NoSun.Value = Branch.NumberOfItemsSunday;
  MaskedText_Update_OI_NoAddicts.Value = Branch.NumberOfAddicts;
  MaskedText_Update_OI_NoSupervised.Value = Branch.Supervised;
  MaskedText_Update_OI_NoUnsupervised.Value = Branch.Unsupervised;

  Check_Update_OI_ConfRoom.Checked = Branch.ConsultationRoom;

  try {        
    PictureGoogleMaps.Image = GoogleAddressInfo.FetchMapInfo(Text_Update_AI_Post.Text).GoogleStaticMap;

  } catch (Exception) {
    PictureGoogleMaps.Image = Resources.DefaultGoogleMap;

  }
}
将图像加载到PictureLogleMaps的行会导致挂起UI,“.GoogleStaticMap”属性在调用时生成Google静态图像

在搜索互联网时,我发现了这个有用的例子:

public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();

        // Declare a list of URLs and their respective picture boxes
        var items = new Dictionary<string, PictureBox> 
        { 
            { "http://www.google.com/logos/spring09.gif", new PictureBox() { Top = 0, Width = 300, Height = 80  } }, 
            { "http://www.google.com/logos/stpatricks_d4gwinner_eo09.gif", new PictureBox() { Top = 100, Width = 300, Height = 80 } },
            { "http://www.google.com/logos/schiaparelli09.gif", new PictureBox() { Top = 200, Width = 300, Height = 80 } },
            { "http://www.google.com/logos/drseuss09.gif", new PictureBox() { Top = 300, Width = 300, Height = 80 } },
            { "http://www.google.com/logos/valentines09.gif", new PictureBox() { Top = 400, Width = 300, Height = 80 } },
            { "http://www.google.com/logos/unix1234567890.gif", new PictureBox() { Top = 500, Width = 300, Height = 80 } },
            { "http://www.google.com/logos/charlesdarwin_09.gif", new PictureBox() { Top = 600, Width = 300, Height = 80 } },
        };

        foreach (var item in items)
        {
            var worker = new BackgroundWorker();
            worker.DoWork += (o, e) =>
            {
                // This function will be run on a background thread
                // spawned from the thread pool.
                using (var client = new WebClient())
                {
                    var pair = (KeyValuePair<string, PictureBox>)e.Argument;
                    e.Result = new KeyValuePair<PictureBox, byte[]>(pair.Value, client.DownloadData(pair.Key));
                }
            };
            worker.RunWorkerCompleted += (o, e) => 
            {
                // This function will be run on the main GUI thread
                var pair = (KeyValuePair<PictureBox, byte[]>)e.Result;
                using (var stream = new MemoryStream(pair.Value))
                {
                    pair.Key.Image = new Bitmap(stream);
                }
                Controls.Add(pair.Key);
            };
            worker.RunWorkerAsync(item);
        }
    }
}
公共部分类表单1:表单
{
公共表格1()
{
初始化组件();
//声明URL列表及其相应的图片框
var items=新字典
{ 
{ "http://www.google.com/logos/spring09.gif,new PictureBox(){Top=0,Width=300,Height=80},
{ "http://www.google.com/logos/stpatricks_d4gwinner_eo09.gif,new PictureBox(){Top=100,Width=300,Height=80},
{ "http://www.google.com/logos/schiaparelli09.gif,new PictureBox(){Top=200,Width=300,Height=80},
{ "http://www.google.com/logos/drseuss09.gif,new PictureBox(){Top=300,Width=300,Height=80},
{ "http://www.google.com/logos/valentines09.gif,new PictureBox(){Top=400,Width=300,Height=80},
{ "http://www.google.com/logos/unix1234567890.gif,new PictureBox(){Top=500,Width=300,Height=80},
{ "http://www.google.com/logos/charlesdarwin_09.gif,new PictureBox(){Top=600,Width=300,Height=80},
};
foreach(项目中的var项目)
{
var worker=新的BackgroundWorker();
worker.DoWork+=(o,e)=>
{
//此函数将在后台线程上运行
//从线程池生成。
使用(var client=new WebClient())
{
var对=(KeyValuePair)e.参数;
e、 结果=新的KeyValuePair(pair.Value,client.DownloadData(pair.Key));
}
};
worker.RunWorkerCompleted+=(o,e)=>
{
//此函数将在主GUI线程上运行
var对=(KeyValuePair)e.Result;
使用(var流=新内存流(pair.Value))
{
pair.Key.Image=新位图(流);
}
控件。添加(pair.Key);
};
worker.RunWorkerAsync(项目);
}
}
}
现在我只需要弄清楚如何删除for循环,并在我的场景中使用它。有什么想法吗

示例代码来自于此


谢谢。

删除foreach循环有那么难吗?您只需加载一张图片,就可以删除foreach循环,并将图片的url和目标picturebox传递给backgroundworker

public partial class Form1 : Form
    {        
        private BackgroundWorker imageLoader;

        public Form1()
        {
            InitializeComponent();

            this.imageLoader = new BackgroundWorker();
            this.imageLoader.DoWork += HandleOnImageLoaderDoWork;
            this.imageLoader.RunWorkerCompleted += HandleImageLoaderOnRunWorkerCompleted;

            this.LoadUserDetails(1);
        }

        private void LoadUserDetails(Int32 userID)
        {
            this.imageLoader.RunWorkerAsync(userID.ToString());
            // get the user details
            // populate the UI controls with the data....
        }

        private void HandleImageLoaderOnRunWorkerCompleted(Object sender, RunWorkerCompletedEventArgs e)
        {
            this.pictureBox1.Image = (Image)e.Result;
        }

        private void HandleOnImageLoaderDoWork(Object sender, DoWorkEventArgs e)
        {
            // simulate a web request for an image;
            Thread.Sleep(3000);
            Image image = Image.FromFile(@"test.jpg");
            e.Result = image;
        }
    }

另外,请确保显示一些UI通知,说明正在进行后台操作…类似于PictureBox中的初始图像(加载.gif)。

否,删除ForEach很容易。在循环的最后一行我有点困惑:worker.RunWorkerAsync(item);谢谢这将很好地工作。另外,我注意到您向RunWorkerAsync发送了一个用户id,如:this.imageLoader.RunWorkerAsync(userID.ToString());现在我想知道是否可以使用这种方法将数据本身与图像一起加载。是的,您可以。但为了保持代码整洁,您可以创建一个类型(保存数据)并在DoWork和RunWorkerCompleted事件处理程序之间传递它。