![]() |
|
|
#1 |
|
Guest
Posts: n/a
|
Populate an ImageList from another thread
I want to fill an ImageList with bitmaps for a ListView from another
thread, because it's a time-consuming process. I expect the ListViewItems' images to "load" one by one, as in a Web browser. I wrote the following code, but the form freezes up while CreateTileBitmaps is running, just as if I'd done it on the main thread. How can I add items to the ImageList without this problem? (Note: I do *not* want to use an owner-draw ListView and Paint events, because painting the extra things like captions and focus rectangles is too tiresome.) private void FindTileForm_Load(object sender, EventArgs e) { ThreadPool.QueueUserWorkItem(new WaitCallback(CreateTileBitmaps)); } private void CreateTileBitmaps(object notUsed) { foreach (Tile t in _tiles.Tiles) { Bitmap bmp = new Bitmap(32, 32); // ... do some drawing ... lvwMatches.Invoke( (MethodInvoker) delegate { imlMatches.Images.Add(bmp); } ); } } |
|
|
|
#2 |
|
Guest
Posts: n/a
|
Re: Populate an ImageList from another thread
On Fri, 14 Dec 2007 17:05:54 -0800, Paul E Collins
<find_my_real_address@CL4.org> wrote: > I want to fill an ImageList with bitmaps for a ListView from another > thread, because it's a time-consuming process. I expect the > ListViewItems' images to "load" one by one, as in a Web browser. > > I wrote the following code, but the form freezes up while > CreateTileBitmaps is running, just as if I'd done it on the main > thread. How can I add items to the ImageList without this problem? Well, you could do it correctly. That would work. There's nothing obvious in the code that you posted that's wrong, which means you didn't post the code that's wrong. But you must have some code somewhere that's wrong, otherwise it would be fine. You should post a concise-but-complete sample of code that reliably reproduces the problem. In the meantime, see below for an example of code that _does_ work (I put a 2-second delay in between item additions to make it easier to watch). Pete using System; using System.Collections.Generic; using System.ComponentModel; using System.Drawing; using System.Text; using System.Windows.Forms; using System.Threading; namespace TestListViewWorkerSingleFile { static class Program { /// <summary> /// The main entry point for the application. /// </summary> [STAThread] static void Main() { Application.EnableVisualStyles(); Application.SetCompatibleTextRenderingDefault(fals e); Application.Run(new Form1()); } } public class Form1 : Form { public Form1() { InitializeComponent(); } private void _InitListView(object obj) { for (int iitem = 0; iitem < 10; iitem++) { Bitmap bmpItem = new Bitmap(32, 32); string strItem = iitem.ToString(); Thread.Sleep(2000); using (Graphics gfx = Graphics.FromImage(bmpItem)) { using (Font font = new Font(Font.FontFamily, Font.SizeInPoints * 1.1f, FontStyle.Bold)) { SizeF szf = gfx.MeasureString(strItem, font); StringFormat format = new StringFormat(); format.Alignment = StringAlignment.Center; format.LineAlignment = StringAlignment.Center; gfx.DrawString(strItem, font, Brushes.Black, new RectangleF(0, 0, 32, 32), format); } } Invoke((MethodInvoker)delegate() { listView1.LargeImageList.Images.Add(strItem, bmpItem); }); Invoke((MethodInvoker)delegate() { listView1.Items.Add(strItem, strItem); }); } } private void Form1_Load(object sender, EventArgs e) { listView1.LargeImageList = new ImageList(); listView1.LargeImageList.ImageSize = new Size(32, 32); ThreadPool.QueueUserWorkItem(_InitListView); } /// <summary> /// Required designer variable. /// </summary> private System.ComponentModel.IContainer components = null; /// <summary> /// Clean up any resources being used. /// </summary> /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param> protected override void Dispose(bool disposing) { if (disposing && (components != null)) { components.Dispose(); } base.Dispose(disposing); } #region Windows Form Designer generated code /// <summary> /// Required method for Designer support - do not modify /// the contents of this method with the code editor. /// </summary> private void InitializeComponent() { this.listView1 = new System.Windows.Forms.ListView(); this.SuspendLayout(); // // listView1 // this.listView1.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Win dows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) | System.Windows.Forms.AnchorStyles.Left) | System.Windows.Forms.AnchorStyles.Right))); this.listView1.Location = new System.Drawing.Point(13, 13); this.listView1.Name = "listView1"; this.listView1.Size = new System.Drawing.Size(267, 241); this.listView1.TabIndex = 0; this.listView1.UseCompatibleStateImageBehavior = false; // // Form1 // this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; this.ClientSize = new System.Drawing.Size(292, 266); this.Controls.Add(this.listView1); this.Name = "Form1"; this.Text = "Form1"; this.Load += new System.EventHandler(this.Form1_Load); this.ResumeLayout(false); } #endregion private System.Windows.Forms.ListView listView1; } } |
|
|
|
#3 |
|
Guest
Posts: n/a
|
Re: Populate an ImageList from another thread
"Peter Duniho" <NpOeStPeAdM@nnowslpianmk.com> wrote:
> Well, you could do it correctly. That would work. Thanks for your code sample and meaningless sneering. Your sample has the same problem with locking up if I remove the Thread.Sleep call, and my original code works acceptably with a Thread.Sleep call, so that seems to be the issue. I don't understand why it is required. I also noticed that ImageList.Items.AddRange is a *lot* faster than several calls to Add, so I'll pass the bitmaps in groups instead of one at a time. Eq. |
|
|
|
#4 |
|
Guest
Posts: n/a
|
Re: Populate an ImageList from another thread
On Fri, 14 Dec 2007 18:27:21 -0800, Paul E Collins
<find_my_real_address@CL4.org> wrote: > "Peter Duniho" <NpOeStPeAdM@nnowslpianmk.com> wrote: > >> Well, you could do it correctly. That would work. > > Thanks for your code sample and meaningless sneering. There was no "sneering" in my post. > Your sample has the same problem with locking up if I remove the > Thread.Sleep call, and my original code works acceptably with a > Thread.Sleep call, so that seems to be the issue. I don't understand > why it is required. I don't either. Mine works fine on my computer with or without the call to Sleep(). In any case, you still haven't posted a code sample that would allow anyone to help advise you. Given the apparent difference in behavior with respect to the computer, you should probably also be specific about what version of .NET you have installed and what OS you're using. Without all of that, I don't think you're going to get a real answer. Pete |
|
|
|
#5 |
|
Guest
Posts: n/a
|
Re: Populate an ImageList from another thread
On Dec 14, 5:05 pm, "Paul E Collins" <find_my_real_addr...@CL4.org>
wrote: > I want to fill an ImageList with bitmaps for a ListView from another > thread, because it's a time-consuming process. I expect the > ListViewItems' images to "load" one by one, as in a Web browser. > > I wrote the following code, but the form freezes up while > CreateTileBitmaps is running, just as if I'd done it on the main > thread. How can I add items to the ImageList without this problem? > (Note: I do *not* want to use an owner-draw ListView and Paint events, > because painting the extra things like captions and focus rectangles > is too tiresome.) > > private void FindTileForm_Load(object sender, EventArgs e) > { > ThreadPool.QueueUserWorkItem(new WaitCallback(CreateTileBitmaps)); > > } > > private void CreateTileBitmaps(object notUsed) > { > foreach (Tile t in _tiles.Tiles) > { > Bitmap bmp = new Bitmap(32, 32); > // ... do some drawing ... > > lvwMatches.Invoke( > (MethodInvoker) delegate { imlMatches.Images.Add(bmp); } > ); > } > > > > }- Hide quoted text - > > - Show quoted text - You can't simply call lvwMatches.Invoke. Try lvwMatches.BeginInvoke. Fire and forget... Greg |
|
![]() |
| Thread Tools | |
| Display Modes | |
|
|