When I click the Delete Selected button, the wrong picture is being deleted. Most of the times it deleted the picture on the right of a selected picture. Other times, for example when everything is selected, it only deletes a single picture.
I don't know what's going on. Here's a picture to illustrate what happens:
Here is the code for both user controls I'm using: HorizontalPictureScroller and SelectablePicture.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Collections.ObjectModel;
using System.Runtime.Serialization;
using System.ComponentModel.Design.Serialization;
namespace WinformsPlayground
{
public partial class HorizontalPictureScroller : UserControl
{
public HorizontalPictureScroller()
{
InitializeComponent();
Pictures = new ObservableCollection<SelectablePicture>();
Pictures.CollectionChanged += new System.Collections.Specialized.NotifyCollectionChangedEventHandler(Pictures_CollectionChanged);
}
#region "Properties"
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public ObservableCollection<SelectablePicture> Pictures { get; set; }
private int PositionControlX = 0;
#endregion
#region "Methods"
private void RedrawPictures()
{
PositionControlX = 0;
foreach (var picture in Pictures)
{
picture.Location = new Point(PositionControlX + panelPicturesWrapper.AutoScrollPosition.X, 0);
PositionControlX += 130;
panelPicturesWrapper.Controls.Add(picture);
}
}
public void AddPicture(SelectablePicture picture)
{
Pictures.Add(picture);
}
public void RemovePicture(SelectablePicture picture)
{
Pictures.Remove(picture);
}
public void MovePictureLeft(int index)
{
SelectablePicture tmpPicture = Pictures[index];
Pictures[index] = Pictures[index - 1];
Pictures[index - 1] = tmpPicture;
}
public void MovePictureRight(int index)
{
SelectablePicture tmpPicture = Pictures[index];
Pictures[index] = Pictures[index + 1];
Pictures[index + 1] = tmpPicture;
}
public void SelectAllImages()
{
foreach (var picture in panelPicturesWrapper.Controls)
{
((SelectablePicture)picture).SelectPicture();
}
}
public void DeselectAllImages()
{
foreach (var picture in panelPicturesWrapper.Controls)
{
((SelectablePicture)picture).DeselectPicture();
}
}
public void DeleteSelectedImages()
{
foreach (var picture in panelPicturesWrapper.Controls)
{
if (((SelectablePicture)picture).IsSelected())
{
this.RemovePicture((SelectablePicture)picture);
}
}
}
#endregion
#region "Events"
void Pictures_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
{
RedrawPictures();
}
#endregion
}
}
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Runtime.Serialization;
namespace WinformsPlayground
{
public partial class SelectablePicture : UserControl
{
public SelectablePicture()
{
InitializeComponent();
panel1.BackgroundImageLayout = ImageLayout.Zoom;
}
public SelectablePicture(Image image)
{
InitializeComponent();
panel1.BackgroundImage = image;
panel1.BackgroundImageLayout = ImageLayout.Zoom;
}
#region "Properties"
public Image Image()
{
return panel1.BackgroundImage;
}
public bool IsSelected()
{
return chkSelected.Checked;
}
#endregion
#region "Methods"
public void ToggleCheckBox()
{
chkSelected.Checked = chkSelected.Checked ? false : true;
}
public void VisuallySelect()
{
this.BackColor = Color.FromArgb(51, 153, 255);
}
public void VisuallyDeselect()
{
//If none of the controls inside the usercontrol have focus, set this control to white.
if (!this.Focused && !this.panel1.Focused && !this.chkSelected.Focused)
{
this.BackColor = Color.White;
}
}
public void SelectPicture()
{
this.chkSelected.Checked = true;
}
public void DeselectPicture()
{
this.chkSelected.Checked = false;
}
#endregion
#region "Events"
private void panel1_Click(object sender, EventArgs e)
{
VisuallySelect();
ToggleCheckBox();
panel1.Focus();
}
private void chkSelected_Click(object sender, EventArgs e)
{
VisuallySelect();
ToggleCheckBox();
chkSelected.Focus();
}
private void SelectablePicture_Click(object sender, EventArgs e)
{
VisuallySelect();
ToggleCheckBox();
this.Focus();
}
private void panel1_Leave(object sender, EventArgs e)
{
VisuallyDeselect();
}
private void chkSelected_Leave(object sender, EventArgs e)
{
VisuallyDeselect();
}
private void SelectablePicture_Leave(object sender, EventArgs e)
{
VisuallyDeselect();
}
#endregion
}
}
The code is simple enough. I've used breakpoints and I can confirm that the HorizontalPictureScroller.DeleteSelectedImages() method is correctly iterating through selected pictures. I'm not sure what else I could do to see what's going on. I'm stumped!
Any ideas? Maybe the .Remove() method that comes with the ObservableCollection type doesn't work as I thought it did.
Every time the Pictures collection changes, you're calling RedrawPictures. That adds all of the pictures again, but doesn't clear anything... so you'll be trying to add a control to panelPicturesWrapper.Controls
when it already contains that control. That sounds like a bad idea to me.
Further, you're iterating over the Controls
collection while changing it, which is generally a bad idea.
I suggest you change your removal code to something like this:
public void DeleteSelectedImages()
{
var picturesToRemove = panelPicturesWrapper.Controls
.Cast<SelectablePicture>();
.Where(p => p.IsSelected())
.ToList();
foreach (var picture in picturesToRemove)
{
RemovePicture(picture);
}
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.