From d0608e72a356ad991f9c9d12518e29b43a1fb4f0 Mon Sep 17 00:00:00 2001 From: Igor Velikorossov Date: Thu, 12 Nov 2020 15:24:05 +1100 Subject: [PATCH] Fix `ListView` no longer displays images (#4184) --- .../Forms/ImageList.ImageCollection.cs | 20 ++++-- .../src/System/Windows/Forms/ImageList.cs | 2 - .../ListViewTest.Designer.cs | 62 ++++++++++++++++++- .../WinformsControlsTest/ListViewTest.cs | 56 +++++++++++++++++ 4 files changed, 132 insertions(+), 8 deletions(-) diff --git a/src/System.Windows.Forms/src/System/Windows/Forms/ImageList.ImageCollection.cs b/src/System.Windows.Forms/src/System/Windows/Forms/ImageList.ImageCollection.cs index 04ae9e59c05..acee045ec4e 100644 --- a/src/System.Windows.Forms/src/System/Windows/Forms/ImageList.ImageCollection.cs +++ b/src/System.Windows.Forms/src/System/Windows/Forms/ImageList.ImageCollection.cs @@ -29,6 +29,9 @@ public sealed class ImageCollection : IList /// issues by holding on to extra references. private int _lastAccessedIndex = -1; + // Indicates whether images are added in a batch. + private bool _isBatchAdd; + /// /// Returns the keys in the image list - images without keys return String.Empty. /// @@ -182,6 +185,8 @@ public Image this[int index] bitmap.Dispose(); } } + + _owner.OnRecreateHandle(EventArgs.Empty); } } @@ -195,7 +200,7 @@ object IList.this[int index] throw new ArgumentException(SR.ImageListBadImage, nameof(value)); } - this[index] = (Image)value; + this[index] = image; } } @@ -372,9 +377,10 @@ private int Add(Original original, ImageInfo imageInfo) _imageInfoCollection.Add(imageInfo); } - if (!_owner._inAddRange) + if (!_isBatchAdd) { _owner.OnChangeHandle(EventArgs.Empty); + _owner.OnRecreateHandle(EventArgs.Empty); } return index; @@ -387,14 +393,15 @@ public void AddRange(Image[] images) throw new ArgumentNullException(nameof(images)); } - _owner._inAddRange = true; + _isBatchAdd = true; foreach (Image image in images) { Add(image); } - _owner._inAddRange = false; + _isBatchAdd = false; _owner.OnChangeHandle(EventArgs.Empty); + _owner.OnRecreateHandle(EventArgs.Empty); } /// @@ -445,6 +452,7 @@ public void Clear() } _owner.OnChangeHandle(EventArgs.Empty); + _owner.OnRecreateHandle(EventArgs.Empty); } [EditorBrowsable(EditorBrowsableState.Never)] @@ -554,7 +562,9 @@ void IList.Remove(object value) if (value is Image image) { Remove(image); + _owner.OnChangeHandle(EventArgs.Empty); + _owner.OnRecreateHandle(EventArgs.Empty); } } @@ -575,7 +585,9 @@ public void RemoveAt(int index) if ((_imageInfoCollection != null) && (index >= 0 && index < _imageInfoCollection.Count)) { _imageInfoCollection.RemoveAt(index); + _owner.OnChangeHandle(EventArgs.Empty); + _owner.OnRecreateHandle(EventArgs.Empty); } } diff --git a/src/System.Windows.Forms/src/System/Windows/Forms/ImageList.cs b/src/System.Windows.Forms/src/System/Windows/Forms/ImageList.cs index 0cd1dec9ded..241195dc591 100644 --- a/src/System.Windows.Forms/src/System/Windows/Forms/ImageList.cs +++ b/src/System.Windows.Forms/src/System/Windows/Forms/ImageList.cs @@ -53,8 +53,6 @@ public sealed partial class ImageList : Component, IHandle private EventHandler _recreateHandler; private EventHandler _changeHandler; - private bool _inAddRange; - /// /// Creates a new ImageList Control with a default image size of 16x16 /// pixels diff --git a/src/System.Windows.Forms/tests/IntegrationTests/WinformsControlsTest/ListViewTest.Designer.cs b/src/System.Windows.Forms/tests/IntegrationTests/WinformsControlsTest/ListViewTest.Designer.cs index 941d3e2290d..23a942f1a0d 100644 --- a/src/System.Windows.Forms/tests/IntegrationTests/WinformsControlsTest/ListViewTest.Designer.cs +++ b/src/System.Windows.Forms/tests/IntegrationTests/WinformsControlsTest/ListViewTest.Designer.cs @@ -39,6 +39,11 @@ private void InitializeComponent() this.columnHeader1 = (System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader()); this.columnHeader2 = (System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader()); this.imageList2 = new System.Windows.Forms.ImageList(this.components); + this.btnClearListView1 = new System.Windows.Forms.Button(); + this.btnLoadImagesListView1 = new System.Windows.Forms.Button(); + this.LargeImageList = new System.Windows.Forms.ImageList(this.components); + this.btnReplaceImageListView1 = new System.Windows.Forms.Button(); + this.openFileDialog1 = new System.Windows.Forms.OpenFileDialog(); this.SuspendLayout(); // // imageList1 @@ -71,8 +76,11 @@ private void InitializeComponent() (System.Windows.Forms.ListViewItem)(resources.GetObject("listView1.Items2"))}); this.listView1.LargeImageList = this.imageList2; resources.ApplyResources(this.listView1, "listView1"); + this.listView1.Location = new System.Drawing.Point(12, 33); this.listView1.Name = "listView1"; + this.listView1.Size = new System.Drawing.Size(439, 159); this.listView1.SmallImageList = this.imageList1; + this.listView1.TabIndex = 0; this.listView1.UseCompatibleStateImageBehavior = false; // // imageList2 @@ -82,10 +90,55 @@ private void InitializeComponent() this.imageList2.Images.SetKeyName(0, "LargeA.bmp"); this.imageList2.Images.SetKeyName(1, "LargeABlue.bmp"); // - // Form1 + // btnClearListView1 + // + this.btnClearListView1.Location = new System.Drawing.Point(13, 4); + this.btnClearListView1.Name = "btnClearListView1"; + this.btnClearListView1.Size = new System.Drawing.Size(75, 23); + this.btnClearListView1.TabIndex = 1; + this.btnClearListView1.Text = "Clear"; + this.btnClearListView1.UseVisualStyleBackColor = true; + this.btnClearListView1.Click += new System.EventHandler(this.btnClearListView1_Click); + // + // btnLoadImagesListView1 + // + this.btnLoadImagesListView1.Location = new System.Drawing.Point(95, 4); + this.btnLoadImagesListView1.Name = "btnLoadImagesListView1"; + this.btnLoadImagesListView1.Size = new System.Drawing.Size(75, 23); + this.btnLoadImagesListView1.TabIndex = 2; + this.btnLoadImagesListView1.Text = "Load images"; + this.btnLoadImagesListView1.UseVisualStyleBackColor = true; + this.btnLoadImagesListView1.Click += new System.EventHandler(this.btnLoadImagesListView1_Click); + // + // LargeImageList + // + this.LargeImageList.ColorDepth = System.Windows.Forms.ColorDepth.Depth24Bit; + this.LargeImageList.ImageSize = new System.Drawing.Size(256, 256); + this.LargeImageList.TransparentColor = System.Drawing.Color.Transparent; + // + // openFileDialog1 + // + this.openFileDialog1.FileName = "openFileDialog1"; + this.openFileDialog1.Multiselect = true; + this.openFileDialog1.SupportMultiDottedExtensions = true; + // + // btnReplaceImageListView1 + // + this.btnReplaceImageListView1.Location = new System.Drawing.Point(176, 4); + this.btnReplaceImageListView1.Name = "btnReplaceImageListView1"; + this.btnReplaceImageListView1.Size = new System.Drawing.Size(87, 23); + this.btnReplaceImageListView1.TabIndex = 3; + this.btnReplaceImageListView1.Text = "Replace image"; + this.btnReplaceImageListView1.UseVisualStyleBackColor = true; + this.btnReplaceImageListView1.Click += new System.EventHandler(this.btnReplaceImageListView1_Click); + // + // ListViewTest // resources.ApplyResources(this, "$this"); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.Controls.Add(this.btnReplaceImageListView1); + this.Controls.Add(this.btnLoadImagesListView1); + this.Controls.Add(this.btnClearListView1); this.Controls.Add(this.listView1); this.Name = "ListViewTest"; this.Text = "ListView Test"; @@ -95,10 +148,15 @@ private void InitializeComponent() #endregion - private System.Windows.Forms.ImageList imageList1; private System.Windows.Forms.ListView listView1; + private System.Windows.Forms.ImageList imageList1; private System.Windows.Forms.ImageList imageList2; + private System.Windows.Forms.ImageList LargeImageList; private System.Windows.Forms.ColumnHeader columnHeader1; private System.Windows.Forms.ColumnHeader columnHeader2; + private System.Windows.Forms.Button btnClearListView1; + private System.Windows.Forms.Button btnLoadImagesListView1; + private System.Windows.Forms.Button btnReplaceImageListView1; + private System.Windows.Forms.OpenFileDialog openFileDialog1; } } diff --git a/src/System.Windows.Forms/tests/IntegrationTests/WinformsControlsTest/ListViewTest.cs b/src/System.Windows.Forms/tests/IntegrationTests/WinformsControlsTest/ListViewTest.cs index d5d074c08d4..a4bb553ed08 100644 --- a/src/System.Windows.Forms/tests/IntegrationTests/WinformsControlsTest/ListViewTest.cs +++ b/src/System.Windows.Forms/tests/IntegrationTests/WinformsControlsTest/ListViewTest.cs @@ -5,6 +5,7 @@ using System; using System.Diagnostics; using System.Drawing; +using System.IO; using System.Windows.Forms; namespace WinformsControlsTest @@ -223,5 +224,60 @@ private void listView2_SelectedIndexChanged(object sender, System.EventArgs e) var random = new Random(); listView2.Columns[random.Next(0, listView2.Columns.Count)].ImageIndex = random.Next(0, 2); } + + private void btnClearListView1_Click(object sender, EventArgs e) + { + listView1.Clear(); + LargeImageList.Images.Clear(); + + listView1.LargeImageList = LargeImageList; + listView1.View = View.LargeIcon; + } + + private void btnLoadImagesListView1_Click(object sender, EventArgs e) + { + if (openFileDialog1.ShowDialog() != DialogResult.OK) + { + return; + } + + foreach (string file in openFileDialog1.FileNames) + { + Bitmap bitmap = (Bitmap)Bitmap.FromFile(file); + LargeImageList.Images.Add(file, bitmap); + + ListViewItem item = new ListViewItem + { + Text = Path.GetFileName(file), + Name = file, + ImageKey = file, + Checked = true + }; + listView1.Items.Add(item); + } + } + + private void btnReplaceImageListView1_Click(object sender, EventArgs e) + { + if (listView1.SelectedIndices.Count != 1) + { + return; + } + + openFileDialog1.Multiselect = false; + DialogResult result = openFileDialog1.ShowDialog(); + openFileDialog1.Multiselect = true; + + if (result != DialogResult.OK) + { + return; + } + + string file = openFileDialog1.FileName; + Bitmap bitmap = (Bitmap)Bitmap.FromFile(file); + LargeImageList.Images[listView1.SelectedIndices[0]] = bitmap; + + listView1.Refresh(); + } } }