using System.Collections.ObjectModel; using Microsoft.VisualBasic.Logging; using System.Drawing.Drawing2D; using OpenCvSharp.Extensions; using VisionBuilder.UI.Common.ViewModel; using VisionBuilder.UI.Common.ViewModel.Classes; using System.Collections.Specialized; namespace VisionBuilder.UI.Windows.Components { public partial class ErrorPreview : UserControl { private ErrorsVM _errorPreviewVM; // Keep track of subscription to avoid duplicate handlers private ObservableCollection _subscribedErrors; public void SetViewModel(ErrorsVM errorPreviewVm) { // Unsubscribe from previous Errors collection if needed if (_subscribedErrors != null) _subscribedErrors.CollectionChanged -= Errors_CollectionChanged; _errorPreviewVM = errorPreviewVm; if (_errorPreviewVM != null) { _subscribedErrors = _errorPreviewVM.Errors; _subscribedErrors.CollectionChanged += Errors_CollectionChanged; // Initial sync: clear and add all flowLayoutPanel1.Controls.Clear(); foreach (var error in _subscribedErrors) { AddErrorPreviewInternal(error); } } } public ErrorPreview() { InitializeComponent(); } private Font _numberedFont = new Font(FontFamily.GenericSansSerif, 10, FontStyle.Regular); private void AddErrorPreviewInternal(ErrorData errorData) { var pb = new PictureBox(); var width = 293 / 1.6f; var height = 220 / 1.6f; pb.Size = new Size((int)width, (int)height + 20); pb.SizeMode = PictureBoxSizeMode.Zoom; pb.Margin = new Padding(5,0,5,5); var numberedImage = new Bitmap((int)width, (int)height + 20); var text = errorData.Title; using (Graphics g = Graphics.FromImage(numberedImage)) { g.Clear(Color.White); g.InterpolationMode = InterpolationMode.HighQualityBicubic; try { g.DrawImage(errorData.ImageAnalysis.ToBitmap(), 0, 0, width, height); } catch (Exception ex) { } var measure = g.MeasureString(text, _numberedFont); g.TranslateTransform(width / 2 - measure.Width / 2, height); g.DrawString(text, _numberedFont, Brushes.Black, 0, 0); } pb.Image = numberedImage; pb.SizeMode = PictureBoxSizeMode.Zoom; pb.Cursor = Cursors.Hand; pb.Click += (sender, args) => { _errorPreviewVM.ShowImage(errorData); }; var tag = (errorData, text); pb.Tag = tag; flowLayoutPanel1.Controls.Add(pb); flowLayoutPanel1.Controls.SetChildIndex(pb, 0); try { flowLayoutPanel1.Refresh(); } catch { } } private void Errors_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e) { if (InvokeRequired) { BeginInvoke(new NotifyCollectionChangedEventHandler(Errors_CollectionChanged), sender, e); return; } if (e.Action == NotifyCollectionChangedAction.Add) { foreach (ErrorData newError in e.NewItems) { AddErrorPreviewInternal(newError); } } else if (e.Action == NotifyCollectionChangedAction.Remove) { foreach (ErrorData oldError in e.OldItems) { // Remove the PictureBox whose Tag contains the oldError foreach (Control ctrl in flowLayoutPanel1.Controls) { if (ctrl is PictureBox pb && pb.Tag is ValueTuple tag && tag.Item1 == oldError) { flowLayoutPanel1.Controls.Remove(pb); pb.Dispose(); break; } } } } else if (e.Action == NotifyCollectionChangedAction.Reset) { flowLayoutPanel1.Controls.Clear(); } } } }