Link to home
Start Free TrialLog in
Avatar of Sn0wb0y
Sn0wb0y

asked on

How to update items in a datagridview with BindingList?

In my windows forms application, I have a list of items <Container> which are populated into a datagridview. Each container has a unique ID. As follows:

User generated image
In the datagridview, I have a "Modify" button column that when clicked, transfers the properties of the selected container onto the textbox controls in my UI. As follows:

User generated image
Question: Given the above, how do I update the properties of a container within my list?

Background code:

Container class:

public class Container
    {
        #region Properties

        // Unique container ID
        public string ContainerID { get; set; }
        // Container description
        public string Description { get; set; }
        // Container payload capacity - weight
        public double CapacityWeight { get; set; }
        // Container payload capacity - cube
        public double CapacityCube { get; set; }
        
        #endregion  

        #region Constructor

        // Default constructor
        public Container()
        {
            ContainerID = Extension.NewID();
        }

        #endregion
    }

Open in new window


List initialization:

// Create an initial arbitrary list of containers to choose from
BindingList<Container> Containers = new BindingList<Container>();

Open in new window


private void initContainers()
        {
            // Add some containers to the container list
            Containers.Add(new Container() { Description = "20FT GENERAL PURPOSE", CapacityWeight = 23.4, CapacityCube = 30 });
            Containers.Add(new Container() { Description = "40FT GENERAL PURPOSE", CapacityWeight = 24.5, CapacityCube = 60 });
            Containers.Add(new Container() { Description = "40FT GENERAL PURPOSE - HIGH CUBE", CapacityWeight = 25.0, CapacityCube = 70 });
            Containers.Add(new Container() { Description = "US CHEP TWO-WAY PALLET", CapacityWeight = 1.524, CapacityCube = 1.8 });
        }

Open in new window

Avatar of it_saige
it_saige
Flag of United States of America image

Like this:

Form1.cs -
using System;
using System.ComponentModel;
using System.Linq;
using System.Windows.Forms;

namespace EE_Q29157886
{
	public partial class Form1 : Form
	{
		BindingList<Container> containers = new BindingList<Container>();

		public Form1()
		{
			InitializeComponent();
		}

		private void OnLoad(object sender, EventArgs e)
		{
			containers.Add(new Container() { ContainerID = 1, Description = "20FT GENERAL PURPOSE", CapacityWeight = 23.4, CapacityCube = 30 });
			containers.Add(new Container() { ContainerID = 2, Description = "40FT GENERAL PURPOSE", CapacityWeight = 24.5, CapacityCube = 60 });
			containers.Add(new Container() { ContainerID = 3, Description = "40FT GENERAL PURPOSE - HIGH CUBE", CapacityWeight = 25.0, CapacityCube = 70 });
			containers.Add(new Container() { ContainerID = 4, Description = "US CHEP TWO-WAY PALLET", CapacityWeight = 1.524, CapacityCube = 1.8 });

			bindingSource1.DataSource = containers;
			dataGridView1.DataSource = bindingSource1;
		}

		private void OnClick(object sender, EventArgs e)
		{
			if (sender is ToolStripMenuItem)
			{
				var mnu = sender as ToolStripMenuItem;
				if (mnu.Equals(modifyToolStripMenuItem))
				{
					var container = dataGridView1?.SelectedRows?.Cast<DataGridViewRow>()?.First()?.DataBoundItem as Container;
					if (container == default(Container))
					{
						container = new Container() { ContainerID = containers.Max(c => c.ContainerID) + 1 };
					}
					var editor = new DynamicForm<Container>("Modify Container", container);
					editor.ShowDialog();
					dataGridView1.Refresh();
				}
				else if (mnu.Equals(addToolStripMenuItem))
				{
					var container = new Container() { ContainerID = containers.Max(c => c.ContainerID) + 1 };
					var editor = new DynamicForm<Container>("Add Container", container);
					if (editor.ShowDialog() == DialogResult.OK)
					{
						containers.Add(container);
					}
					dataGridView1.Refresh();
				}
				else if (mnu.Equals(removeToolStripMenuItem))
				{
					var container = dataGridView1?.SelectedRows?.Cast<DataGridViewRow>()?.First()?.DataBoundItem as Container;
					if (container != default(Container))
					{
						containers.Remove(container);
					}
					dataGridView1.Refresh();
				}
			}
		}

		private void OnRowContextMenuStripNeeded(object sender, DataGridViewRowContextMenuStripNeededEventArgs e)
		{
			if (sender is DataGridView)
			{
				var grid = sender as DataGridView;
				if (!grid.SelectedRows.Contains(grid.Rows[e.RowIndex]))
					grid.Rows[e.RowIndex].Selected = true;
				e.ContextMenuStrip = contextMenuStrip1;
			}
		}
	}
}

Open in new window

Form1.Designer.cs -
namespace EE_Q29157886
{
	partial class Form1
	{
		/// <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.components = new System.ComponentModel.Container();
			this.dataGridView1 = new System.Windows.Forms.DataGridView();
			this.bindingSource1 = new System.Windows.Forms.BindingSource(this.components);
			this.contextMenuStrip1 = new System.Windows.Forms.ContextMenuStrip(this.components);
			this.modifyToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
			this.addToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
			this.removeToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
			((System.ComponentModel.ISupportInitialize)(this.dataGridView1)).BeginInit();
			((System.ComponentModel.ISupportInitialize)(this.bindingSource1)).BeginInit();
			this.contextMenuStrip1.SuspendLayout();
			this.SuspendLayout();
			// 
			// dataGridView1
			// 
			this.dataGridView1.AllowUserToAddRows = false;
			this.dataGridView1.AllowUserToDeleteRows = false;
			this.dataGridView1.AutoSizeColumnsMode = System.Windows.Forms.DataGridViewAutoSizeColumnsMode.Fill;
			this.dataGridView1.AutoSizeRowsMode = System.Windows.Forms.DataGridViewAutoSizeRowsMode.AllCells;
			this.dataGridView1.ColumnHeadersHeightSizeMode = System.Windows.Forms.DataGridViewColumnHeadersHeightSizeMode.AutoSize;
			this.dataGridView1.Dock = System.Windows.Forms.DockStyle.Fill;
			this.dataGridView1.Location = new System.Drawing.Point(0, 0);
			this.dataGridView1.MultiSelect = false;
			this.dataGridView1.Name = "dataGridView1";
			this.dataGridView1.ReadOnly = true;
			this.dataGridView1.RowHeadersVisible = false;
			this.dataGridView1.SelectionMode = System.Windows.Forms.DataGridViewSelectionMode.FullRowSelect;
			this.dataGridView1.Size = new System.Drawing.Size(516, 223);
			this.dataGridView1.TabIndex = 0;
			this.dataGridView1.RowContextMenuStripNeeded += new System.Windows.Forms.DataGridViewRowContextMenuStripNeededEventHandler(this.OnRowContextMenuStripNeeded);
			// 
			// contextMenuStrip1
			// 
			this.contextMenuStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
            this.modifyToolStripMenuItem,
            this.addToolStripMenuItem,
            this.removeToolStripMenuItem});
			this.contextMenuStrip1.Name = "contextMenuStrip1";
			this.contextMenuStrip1.Size = new System.Drawing.Size(181, 92);
			// 
			// modifyToolStripMenuItem
			// 
			this.modifyToolStripMenuItem.Name = "modifyToolStripMenuItem";
			this.modifyToolStripMenuItem.Size = new System.Drawing.Size(180, 22);
			this.modifyToolStripMenuItem.Text = "Modify";
			this.modifyToolStripMenuItem.Click += new System.EventHandler(this.OnClick);
			// 
			// addToolStripMenuItem
			// 
			this.addToolStripMenuItem.Name = "addToolStripMenuItem";
			this.addToolStripMenuItem.Size = new System.Drawing.Size(180, 22);
			this.addToolStripMenuItem.Text = "Add";
			this.addToolStripMenuItem.Click += new System.EventHandler(this.OnClick);
			// 
			// removeToolStripMenuItem
			// 
			this.removeToolStripMenuItem.Name = "removeToolStripMenuItem";
			this.removeToolStripMenuItem.Size = new System.Drawing.Size(180, 22);
			this.removeToolStripMenuItem.Text = "Remove";
			this.removeToolStripMenuItem.Click += new System.EventHandler(this.OnClick);
			// 
			// Form1
			// 
			this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
			this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
			this.ClientSize = new System.Drawing.Size(516, 223);
			this.Controls.Add(this.dataGridView1);
			this.Name = "Form1";
			this.Text = "Form1";
			this.Load += new System.EventHandler(this.OnLoad);
			((System.ComponentModel.ISupportInitialize)(this.dataGridView1)).EndInit();
			((System.ComponentModel.ISupportInitialize)(this.bindingSource1)).EndInit();
			this.contextMenuStrip1.ResumeLayout(false);
			this.ResumeLayout(false);

		}

		#endregion

		private System.Windows.Forms.DataGridView dataGridView1;
		private System.Windows.Forms.BindingSource bindingSource1;
		private System.Windows.Forms.ContextMenuStrip contextMenuStrip1;
		private System.Windows.Forms.ToolStripMenuItem modifyToolStripMenuItem;
		private System.Windows.Forms.ToolStripMenuItem addToolStripMenuItem;
		private System.Windows.Forms.ToolStripMenuItem removeToolStripMenuItem;
	}
}

Open in new window

DynamicForm.cs -
using System;
using System.Collections.Generic;
using System.Reflection;
using System.Windows.Forms;

namespace EE_Q29157886
{
	public partial class DynamicForm<T> : Form
	{
		List<Control> controls;
		public T DataItem { get; private set; }

		public DynamicForm(string title, T item)
		{
			InitializeComponent();
			InitializeForm(title);
			InitializeControls(item);
			DataItem = item;

			// We need to ensure that the required fields are clearly marked, so that
			// the user can see which controls they must complete in order for the OK
			// button to become enabled.
			ValidateControls();
		}

		private void InitializeForm(string title)
		{
			Text = title;
			MaximizeBox = false;
			MinimizeBox = false;
			ShowIcon = false;
			ShowInTaskbar = false;
			FormBorderStyle = FormBorderStyle.FixedDialog;
			StartPosition = FormStartPosition.CenterParent;
			errorProvider.BlinkStyle = ErrorBlinkStyle.NeverBlink;
			controls = new List<Control>();
		}

		private void InitializeControls(T item)
		{
			PropertyInfo[] properties = item.GetType().GetProperties();

			// Create layout table
			tableLayoutPanel1.RowCount = properties.Length;

			// For each property
			int rowNumber = 0;
			foreach (var property in properties)
			{
				Control ctrl = ControlFactory<T>.CreateControl(item, property);
				if (ctrl != null)
				{
					// Get custom attributes
					object[] attributes = property.GetCustomAttributes(true);
					ctrl = ApplyAttributes(ctrl, attributes);

					// Disable the control if property read only
					if (!property.CanWrite)
					{
						ctrl.Enabled = false;
					}

					// Build label
					if (ctrl.Visible)
					{
						ControlTag tag = (ControlTag)ctrl.Tag;
						Label label = ControlFactory<T>.CreateLabel(property.Name);
						if (!string.IsNullOrEmpty(tag.CustomLabel))
						{
							label.Text = tag.CustomLabel;
						}
						tableLayoutPanel1.Controls.Add(label, 0, rowNumber);
						tableLayoutPanel1.Controls.Add(ctrl, 1, rowNumber);
						controls.Add(ctrl);
					}
				}
				rowNumber++;
			}

			// Resize the form
			Width = tableLayoutPanel1.Width + 40;
			Height = tableLayoutPanel1.Height + 90;
		}

		/// <summary>
		/// Applies the settings from the custom attributes to the control.
		/// </summary>
		/// <param name="ctrl">A control bound to property</param>
		/// <param name="attributes">Custom attributes for the property</param>
		/// <returns></returns>
		private Control ApplyAttributes(Control ctrl, object[] attributes)
		{
			ControlTag tag = (ControlTag)ctrl.Tag;
			NumericSettingsAttribute attrRange = null;
			DisplaySettingsAttribute attrDisplay = null;
			RequiredFieldAttribute attrRequired = null;
			foreach (object attribute in attributes)
			{
				if (attribute is NumericSettingsAttribute)
				{
					attrRange = (NumericSettingsAttribute)attribute;
				}
				else if (attribute is DisplaySettingsAttribute)
				{
					attrDisplay = (DisplaySettingsAttribute)attribute;
				}
				else if (attribute is RequiredFieldAttribute)
				{
					attrRequired = (RequiredFieldAttribute)attribute;
				}
			}

			// Attach LostFocus handler for input validation
			ctrl.LostFocus += OnLostFocus;

			// Display Attribute
			if (attrDisplay != null)
			{
				tag.CustomLabel = attrDisplay.Label;
				ctrl.Enabled = !attrDisplay.ReadOnly;
				ctrl.Visible = attrDisplay.Visible;
				if (attrDisplay.Width > 0)
				{
					ctrl.Width = attrDisplay.Width;
				}

				if (!string.IsNullOrWhiteSpace(attrDisplay.Description))
				{
					toolTip.SetToolTip(ctrl, attrDisplay.Description);
				}
			}

			// Required Field Attribute
			if (attrRequired != null)
			{
				tag.ErrorMessage = string.IsNullOrEmpty(attrRequired.Message) ? "Required" : attrRequired.Message;
			}
			return ctrl;
		}

		private void OnLostFocus(object sender, EventArgs e)
		{
			ValidateControls();
		}

		private void OnClick(object sender, EventArgs e)
		{
			SaveControlValues();
		}

		private bool ValidateControl(Control control)
		{
			bool isValid = true;

			// Validation currently limited to TextBoxes only
			TextBox txt = control as TextBox;
			if (txt != null)
			{
				// If the textbox is empty, show a warning
				ControlTag tag = (ControlTag)txt.Tag;
				if (tag.IsRequired && string.IsNullOrEmpty(txt.Text))
				{
					errorProvider.SetError(txt, tag.ErrorMessage);
					isValid = false;
				}
				else
				{
					errorProvider.SetError(txt, string.Empty);
				}
			}
			return isValid;
		}

		/// <summary>
		/// Returns false if any controls are invalid.
		/// </summary>
		/// <returns></returns>
		private void ValidateControls()
		{
			bool isValid = true;
			foreach (Control control in controls)
			{
				if (!ValidateControl(control))
				{
					isValid = false;
				}
			}
			btnOk.Enabled = isValid;
		}

		/// <summary>
		/// Saves the controls value back to the data object.
		/// </summary>
		private void SaveControlValues()
		{
			// For each TextBox, Dropdown etc...
			foreach (Control c in controls)
			{
				ControlTag tag = (ControlTag)c.Tag;
				PropertyInfo property = DataItem.GetType().GetProperty(tag.PropertyName);
				Type type = property.PropertyType;
				if (c is TextBox)
				{
					TextBox textbox = (TextBox)c;
					property.SetValue(DataItem, Convert.ChangeType(textbox.Text, type), null);
				}
				else if (c is NumericUpDown)
				{
					NumericUpDown numeric = (NumericUpDown)c;
					property.SetValue(DataItem, Convert.ChangeType(numeric.Value, type), null);
				}
				else if (c is CheckBox)
				{
					CheckBox checkbox = c as CheckBox;
					property.SetValue(DataItem, checkbox.Checked, null);
				}
				else if (c is ComboBox)
				{
					ComboBox dropdown = c as ComboBox;
					property.SetValue(DataItem, Enum.Parse(tag.PropertyType, Convert.ToString(dropdown.SelectedItem)), null);
				}
			}
		}
	}
}

Open in new window

DynamicForm.Designer.cs -
namespace EE_Q29157886
{
	partial class DynamicForm<T>
	{
		/// <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.components = new System.ComponentModel.Container();
			this.btnCancel = new System.Windows.Forms.Button();
			this.btnOk = new System.Windows.Forms.Button();
			this.tableLayoutPanel1 = new System.Windows.Forms.TableLayoutPanel();
			this.errorProvider = new System.Windows.Forms.ErrorProvider(this.components);
			this.toolTip = new System.Windows.Forms.ToolTip(this.components);
			((System.ComponentModel.ISupportInitialize)(this.errorProvider)).BeginInit();
			this.SuspendLayout();
			// 
			// btnCancel
			// 
			this.btnCancel.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
			this.btnCancel.DialogResult = System.Windows.Forms.DialogResult.Cancel;
			this.btnCancel.Location = new System.Drawing.Point(135, 55);
			this.btnCancel.Margin = new System.Windows.Forms.Padding(4);
			this.btnCancel.Name = "btnCancel";
			this.btnCancel.Size = new System.Drawing.Size(100, 28);
			this.btnCancel.TabIndex = 3;
			this.btnCancel.Text = "Cancel";
			this.btnCancel.UseVisualStyleBackColor = true;
			// 
			// btnOk
			// 
			this.btnOk.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
			this.btnOk.DialogResult = System.Windows.Forms.DialogResult.OK;
			this.btnOk.Location = new System.Drawing.Point(27, 55);
			this.btnOk.Margin = new System.Windows.Forms.Padding(4);
			this.btnOk.Name = "btnOk";
			this.btnOk.Size = new System.Drawing.Size(100, 28);
			this.btnOk.TabIndex = 2;
			this.btnOk.Text = "OK";
			this.btnOk.UseVisualStyleBackColor = true;
			this.btnOk.Click += new System.EventHandler(this.OnClick);
			// 
			// tableLayoutPanel1
			// 
			this.tableLayoutPanel1.AutoSize = true;
			this.tableLayoutPanel1.ColumnCount = 2;
			this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle());
			this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle());
			this.tableLayoutPanel1.Location = new System.Drawing.Point(16, 15);
			this.tableLayoutPanel1.Margin = new System.Windows.Forms.Padding(4);
			this.tableLayoutPanel1.Name = "tableLayoutPanel1";
			this.tableLayoutPanel1.RowCount = 1;
			this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle());
			this.tableLayoutPanel1.Size = new System.Drawing.Size(219, 25);
			this.tableLayoutPanel1.TabIndex = 4;
			// 
			// errorProvider
			// 
			this.errorProvider.ContainerControl = this;
			// 
			// DynamicForm
			// 
			this.AutoScaleDimensions = new System.Drawing.SizeF(8F, 16F);
			this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
			this.ClientSize = new System.Drawing.Size(251, 98);
			this.Controls.Add(this.tableLayoutPanel1);
			this.Controls.Add(this.btnCancel);
			this.Controls.Add(this.btnOk);
			this.Margin = new System.Windows.Forms.Padding(4);
			this.Name = "DynamicForm";
			this.Text = "DialogBuilder";
			this.TopMost = true;
			((System.ComponentModel.ISupportInitialize)(this.errorProvider)).EndInit();
			this.ResumeLayout(false);
			this.PerformLayout();

		}

		#endregion

		private System.Windows.Forms.Button btnCancel;
		private System.Windows.Forms.Button btnOk;
		private System.Windows.Forms.TableLayoutPanel tableLayoutPanel1;
		private System.Windows.Forms.ErrorProvider errorProvider;
		private System.Windows.Forms.ToolTip toolTip;
	}
}

Open in new window

SupportingObjects.cs -
using System;
using System.Reflection;
using System.Text;
using System.Windows.Forms;

namespace EE_Q29157886
{
	class Container
	{
		[DisplaySettings(ReadOnly = true, Width = 200)]
		public int ContainerID { get; set; }
		[DisplaySettings(Width = 200)]
		public string Description { get; set; }
		[DisplaySettings(Width = 200)]
		public double CapacityWeight { get; set; }
		[DisplaySettings(Width = 200)]
		public double CapacityCube { get; set; }
	}

	internal class ControlFactory<T>
	{
		internal static Control CreateControl(T item, PropertyInfo property)
		{
			Control ctrl = null;
			Type type = property.PropertyType;

			// The control depends on the property type
			if (type == typeof(string))
			{
				ctrl = new TextBox();
				TextBox textbox = ctrl as TextBox;
				textbox.Name = $"tbx{property.Name}";
				textbox.Text = (string)property.GetValue(item, null);
				textbox.Margin = new Padding(3, 3, 16, 0);
			}
			else if (type == typeof(char))
			{
				ctrl = new TextBox();
				TextBox textbox = ctrl as TextBox;
				textbox.MaxLength = 1;
				textbox.Name = $"tbx{property.Name}";
				textbox.Width = 20;
				textbox.Text = Convert.ToString(property.GetValue(item, null));
				textbox.Margin = new Padding(3, 3, 16, 0);
			}
			else if (type == typeof(int))
			{
				ctrl = new NumericUpDown();
				NumericUpDown numeric = ctrl as NumericUpDown;
				numeric.Name = $"nud{property.Name}";
				numeric.Value = Convert.ToDecimal(property.GetValue(item, null));
			}
			else if (type == typeof(double))
			{
				ctrl = new NumericUpDown();
				NumericUpDown numeric = ctrl as NumericUpDown;
				numeric.DecimalPlaces = 2;
				numeric.Name = $"nud{property.Name}";
				numeric.Value = (decimal)Convert.ToDouble(property.GetValue(item, null));
			}
			else if (type == typeof(decimal))
			{
				ctrl = new NumericUpDown();
				NumericUpDown numeric = ctrl as NumericUpDown;
				numeric.DecimalPlaces = 2;
				numeric.Name = $"nud{property.Name}";
				numeric.Value = Convert.ToDecimal(property.GetValue(item, null));
			}
			else if (type == typeof(bool))
			{
				ctrl = new CheckBox();
				CheckBox checkbox = ctrl as CheckBox;
				checkbox.Name = $"cbx{property.Name}";
				checkbox.Checked = Convert.ToBoolean(property.GetValue(item, null));
			}
			else if (type.BaseType == typeof(Enum))
			{
				ctrl = new ComboBox();
				ComboBox dropdown = ctrl as ComboBox;
				dropdown.DropDownStyle = ComboBoxStyle.DropDownList;
				dropdown.Name = "ddl{property.Name}";
				string[] names = Enum.GetNames(type);
				string value = Convert.ToString(property.GetValue(item, null));
				foreach (var name in names)
				{
					dropdown.Items.Add(name);
					if (name == value)
					{
						dropdown.SelectedIndex = dropdown.Items.Count - 1;
					}
				}
			}
			else if (type == typeof(DateTime))
			{
				ctrl = new DateTimePicker();
				DateTimePicker date = ctrl as DateTimePicker;
				DateTime dateValue = Convert.ToDateTime(property.GetValue(item, null));
				date.Name = $"dtp{property.Name}";
				if (dateValue < date.MinDate)
				{
					dateValue = date.MinDate;
				}

				if (dateValue > date.MaxDate)
				{
					dateValue = date.MaxDate;
				}

				date.Value = dateValue;
			}
			if (ctrl != null)
			{
				ControlTag tag = new ControlTag();
				tag.PropertyName = property.Name;
				tag.PropertyType = property.PropertyType;
				ctrl.Tag = tag;
			}
			return ctrl;
		}

		/// <summary>
		/// Creates a new instance of the Label control using the specified text value.
		/// </summary>
		/// <param name="text"></param>
		/// <returns></returns>
		internal static Label CreateLabel(string text)
		{
			Label label = new Label();
			label.Name = $"lbl{text}";
			label.Text = $"{GetLabel(text)}:";
			label.AutoSize = true;
			label.Margin = new Padding(3, 6, 6, 0);
			return label;
		}

		/// <summary>
		/// Returns a friendly label from the supplied name. For example, the
		/// string "firstName" would be returned as "First Name".
		/// </summary>
		/// <param name="text"></param>
		/// <returns></returns>
		private static string GetLabel(string text)
		{
			bool isFirst = true;
			StringBuilder sb = new StringBuilder();
			foreach (char c in text.ToCharArray())
			{
				if (isFirst)
				{
					sb.Append(char.ToUpper(c));
					isFirst = false;
				}
				else
				{
					if (char.IsUpper(c))
						sb.Append(' ');
					sb.Append(c);
				}
			}
			return sb.ToString();
		}
	}

	internal class ControlTag
	{
		public string CustomLabel { get; set; }
		public string ErrorMessage { get; set; }
		public string PropertyName { get; set; }
		public Type PropertyType { get; set; }

		public bool IsRequired
		{
			get { return !string.IsNullOrEmpty(ErrorMessage); }
		}
	}

	[AttributeUsage(AttributeTargets.Property)]
	public class DisplaySettingsAttribute : Attribute
	{
		public string Label { get; set; }
		public string Description { get; set; }
		public bool ReadOnly { get; set; }
		public bool Visible { get; set; }
		public int Width { get; set; }

		public DisplaySettingsAttribute()
		{
			Visible = true;
		}
	}

	[AttributeUsage(AttributeTargets.Property)]
	public class NumericSettingsAttribute : Attribute
	{
		public float MinValue { get; set; }
		public float MaxValue { get; set; }
		public int DecimalPlaces { get; set; }
	}

	[AttributeUsage(AttributeTargets.Property)]
	public class RequiredFieldAttribute : Attribute
	{
		public string Message { get; set; }
	}
}

Open in new window

Produces the following output -User generated imageUser generated imageUser generated imageUser generated imageUser generated imageUser generated imageUser generated imageUser generated image-saige-
Avatar of Sn0wb0y
Sn0wb0y

ASKER

Wow! That's completely awesome but way over the top of my head it_saige! I am just starting out with learning C# winforms here, sorry I would have to study it for days to work out what you did! Lolz
I understand that it can be a little overwhelming, at first, but you will find that this is really simple at it's core.  You are more than welcome to take what I implemented and create a new solution so that you can step through what it is doing.

-saige-
Avatar of Sn0wb0y

ASKER

Hey thanks for the encouragement it_saige. I can see the logic in what you have done and really do appreciate the effort you put into it. It makes sense in that my UI will become much cleaner, (I know it looks horrible as it is with all those button columns!) and windows user friendly.

However, as I am self learning, I was really looking for an easy way to update the property values on my existing binding list objects as I am wanting to learn these fundamental components first before diving into more complex things.

I will certainly try and use what you have done. Thanks again
ASKER CERTIFIED SOLUTION
Avatar of it_saige
it_saige
Flag of United States of America image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of Sn0wb0y

ASKER

Hi it_saige,

First off, I want to thank you again for taking the time to respond to my question. As I mentioned earlier, I am just starting out and really got myself in a tangle with your solution. In hindsight, I should of provided my existing form code, as clunky as it is, to help you further understand what I was trying to do.

From reviewing that code you provided, I managed to identify and implement the updating of my bound list as intended from my original question. I am absolutely sure it is far from perfect and would appreciate any feedback you might have. As follows:

Main.cs

using System;
using System.Collections.Generic;
using System.Windows.Forms;
using System.ComponentModel;
using System.Linq;
using System.Drawing;

namespace ContainerPackerWinForms
{
    public partial class Main : Form
    {
        // Create an initial arbitrary list of containers to choose from
        BindingList<Container> Containers = new BindingList<Container>();
		Container current = default(Container);

        public Main()
        {
            InitializeComponent(); 
        }
        
        private void Main_Load(object sender, EventArgs e)
        {			 
			initContainers();
			dgvContainer.DataSource = Containers;
			initContainerDGV();            
            initContainerSection();
        }
		
        #region Container
		
		// Add / edit / remove container
        private void DgvContainer_CellContentClick(object sender, DataGridViewCellEventArgs e)
        {
            // Validate row selection
            if (this.dgvContainer.CurrentRow != null)
            {
                // Validate modify container button click
                if (e.ColumnIndex == this.dgvContainer.Columns["modify_container_button_column"].Index)
                {
                    // Perform a second validation of container selection            
                    if (this.dgvContainer.CurrentRow != null && this.dgvContainer.SelectedRows.Count > 0)
                    {
                        // Transfer selected cell bindings to UI controls
                        this.txtContainerDescription.Text = this.dgvContainer.SelectedCells[1].Value.ToString();
                        this.txtContainerCapacityWeight.Text = this.dgvContainer.SelectedCells[2].Value.ToString();
                        this.txtContainerCapacityCube.Text = this.dgvContainer.SelectedCells[3].Value.ToString();

                        // Change button caption and set focus to description field
                        this.btnAddUpdateContainer.Text = "Save Changes";                        
                        this.txtContainerDescription.Focus();
                    }                    
                }                
                // Validate remove container button click
                else if (e.ColumnIndex == this.dgvContainer.Columns["remove_container_button_column"].Index)
                {
                    // Perform a second validation of container selection            
                    if (this.dgvContainer.CurrentRow != null && this.dgvContainer.SelectedRows.Count > 0)
                    {
                        // TO DO: 
                        // ADD FUNCTIONALITY TO REMOVE ALL EXISTING SHIPMENT CONTAINERS AND PACKING DETAILS
                        
                        // Remove the selected container from the container list
                        Containers.RemoveAt(this.dgvContainer.CurrentRow.Index);

                        // Initialize the container section                        
                        initContainerSection();
                        this.txtShipmentName.Focus();
                    }
                }
            }
            else
            {
                // Prompt user to select a container
                MessageBox.Show("Error! Please select a container from the list.");                
            }
        }

        // Add / update container
        private void BtnAddUpdateContainer_Click(object sender, EventArgs e)
        {
            current = dgvContainer?.SelectedRows?.Cast<DataGridViewRow>()?.First()?.DataBoundItem as Container;

            // Validate add container mode
            if (this.btnAddUpdateContainer.Text == "Add New Container")
            {
                // Validate form fields
                if (!IsEmpty(this.txtContainerDescription.Text, this.txtContainerCapacityWeight.Text, this.txtContainerCapacityCube.Text))
                {
                    // Add container to list
                    Containers.Add(new Container()
                    {
                        Description = this.txtContainerDescription.Text,
                        CapacityWeight = Convert.ToDouble(this.txtContainerCapacityWeight.Text),
                        CapacityCube = Convert.ToDouble(this.txtContainerCapacityCube.Text)
                    });

                    // Clear and initialize the container section                
                    this.dgvContainer.ClearSelection();
                    initContainerSection();
                    this.txtShipmentName.Focus();
                }
                else
                {
                    // Prompt user to provide required values
                    MessageBox.Show("Error! Please provide values for all data entry fields.");
                    initContainerSection();
                    this.txtContainerDescription.Focus();
                }
            }
            // Validate update container mode
            else if (this.btnAddUpdateContainer.Text == "Save Changes")
            {
                if (this.dgvContainer.CurrentRow != null && this.dgvContainer.SelectedRows.Count > 0)
                {
                    if (current != default(Container))
                    {
                        current.Description = txtContainerDescription.Text;
                        current.CapacityWeight = Convert.ToDouble(txtContainerCapacityWeight.Text);
                        current.CapacityCube = Convert.ToDouble(txtContainerCapacityCube.Text);
                    }                    

                    // Clear and initialize the container section                
                    this.dgvContainer.ClearSelection();
                    initContainerSection();                    
                }
            }
        }
		
        // Initializes a list of containers
        private void initContainers()
        {
            // Add some containers to the container list
            Containers.Add(new Container() { Description = "20FT GENERAL PURPOSE", CapacityWeight = 23.4, CapacityCube = 30 });
            Containers.Add(new Container() { Description = "40FT GENERAL PURPOSE", CapacityWeight = 24.5, CapacityCube = 60 });
            Containers.Add(new Container() { Description = "40FT GENERAL PURPOSE - HIGH CUBE", CapacityWeight = 25.0, CapacityCube = 70 });
            Containers.Add(new Container() { Description = "US CHEP TWO-WAY PALLET", CapacityWeight = 1.524, CapacityCube = 1.8 });
        }
        
        // Initializes container section
        private void initContainerSection()
        {
            if (this.dgvContainer.Rows.Count > 0)
            {
                clearContainerFields();
                this.dgvContainer.Enabled = true;
                this.txtContainerDescription.Enabled = true;
                this.txtContainerCapacityWeight.Enabled = true;
                this.txtContainerCapacityCube.Enabled = true;
                this.btnAddUpdateContainer.Text = "Add New Container";
                this.btnAddUpdateContainer.Enabled = true;                
            }
            else
            {
                clearContainerFields();
                this.dgvContainer.Enabled = false;
                this.txtContainerDescription.Enabled = false;
                this.txtContainerCapacityWeight.Enabled = false;
                this.txtContainerCapacityCube.Enabled = false;
                this.btnAddUpdateContainer.Text = "Add New Container";
                this.btnAddUpdateContainer.Enabled = true;
            }
        }

        // Clears container entry fields
        private void clearContainerFields()
        {
            this.txtContainerCapacityCube.Text = null;
            this.txtContainerCapacityWeight.Text = null;
            this.txtContainerDescription.Text = null;
        }

		// Initializes container datagrid
        private void initContainerDGV()
        {
            // Set control properties            
            this.dgvContainer.AutoGenerateColumns = false;
            this.dgvContainer.MultiSelect = false;
            this.dgvContainer.SelectionMode = DataGridViewSelectionMode.FullRowSelect;
            this.dgvContainer.RowHeadersVisible = false;
            this.dgvContainer.RowsDefaultCellStyle.BackColor = Color.White;
            this.dgvContainer.AlternatingRowsDefaultCellStyle.BackColor = Color.FromArgb(240, 244, 244);
            this.dgvContainer.ScrollBars = ScrollBars.Vertical;

            // Set column definitions
            this.dgvContainer.Columns[0].HeaderText = "Container ID";
            this.dgvContainer.Columns[0].DataPropertyName = "ContainerID";
            this.dgvContainer.Columns[0].MinimumWidth = 85;
            this.dgvContainer.Columns[0].Width = 90;
            this.dgvContainer.Columns[0].DefaultCellStyle.Alignment = DataGridViewContentAlignment.MiddleLeft;

            this.dgvContainer.Columns[1].HeaderText = "Container Description";
            this.dgvContainer.Columns[1].DataPropertyName = "Description";
            this.dgvContainer.Columns[1].MinimumWidth = 220;
            this.dgvContainer.Columns[1].Width = 230;
            this.dgvContainer.Columns[1].DefaultCellStyle.Alignment = DataGridViewContentAlignment.MiddleLeft;

            this.dgvContainer.Columns[2].HeaderText = "Weight Capacity (MT)";
            this.dgvContainer.Columns[2].DataPropertyName = "CapacityWeight";
            this.dgvContainer.Columns[2].MinimumWidth = 130;
            this.dgvContainer.Columns[2].Width = 135;
            this.dgvContainer.Columns[2].DefaultCellStyle.Alignment = DataGridViewContentAlignment.MiddleRight;
            this.dgvContainer.Columns[2].DefaultCellStyle.Format = "0.00";

            this.dgvContainer.Columns[3].HeaderText = "Cube Capacity (CBM)";
            this.dgvContainer.Columns[3].DataPropertyName = "CapacityCube";
            this.dgvContainer.Columns[3].MinimumWidth = 130;
            this.dgvContainer.Columns[3].Width = 135;
            this.dgvContainer.Columns[3].DefaultCellStyle.Alignment = DataGridViewContentAlignment.MiddleRight;
            this.dgvContainer.Columns[3].DefaultCellStyle.Format = "0.00";

            // Edit container button column
            DataGridViewButtonColumn modifyContainerButtonColumn = new DataGridViewButtonColumn();
            modifyContainerButtonColumn.Name = "modify_container_button_column";
            modifyContainerButtonColumn.HeaderText = "Modify";
            modifyContainerButtonColumn.Text = "Modify";
            modifyContainerButtonColumn.UseColumnTextForButtonValue = true;
            int columnIndex1 = 4;
            if (this.dgvContainer.Columns["modify_container_button_column"] == null)
            {
                this.dgvContainer.Columns.Insert(columnIndex1, modifyContainerButtonColumn);
            }
            
            // Add container to shipment button column
            DataGridViewButtonColumn addContainerToShipmentButtonColumn = new DataGridViewButtonColumn();
            addContainerToShipmentButtonColumn.Name = "add_container_to_shipment_button_column";
            addContainerToShipmentButtonColumn.HeaderText = "Add";
            addContainerToShipmentButtonColumn.Text = "Add";
            addContainerToShipmentButtonColumn.UseColumnTextForButtonValue = true;
            int columnIndex2 = 5;
            if (this.dgvContainer.Columns["add_container_to_shipment_button_column"] == null)
            {
                this.dgvContainer.Columns.Insert(columnIndex2, addContainerToShipmentButtonColumn);
            }

            // Remove container button column
            DataGridViewButtonColumn removeContainerButtonColumn = new DataGridViewButtonColumn();
            removeContainerButtonColumn.Name = "remove_container_button_column";
            removeContainerButtonColumn.HeaderText = "Remove";
            removeContainerButtonColumn.Text = "Remove";
            removeContainerButtonColumn.UseColumnTextForButtonValue = true;
            int columnIndex3 = 6;
            if (this.dgvContainer.Columns["remove_container_button_column"] == null)
            {
                this.dgvContainer.Columns.Insert(columnIndex3, removeContainerButtonColumn);
            }
        }
        
        #endregion
		
        #region Form Helper Methods

        // Function to validate textbox entries
        private static bool IsEmpty(params string[] args)
        {
            if (args.Length == 0) return true;
            return args.Any(p => string.IsNullOrEmpty(p));
        }

        #endregion
    }
}

Open in new window


ExtensionMethods.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ExtensionMethods
{
    public static class Extension
    {
        public static string NewID()
        {
            return Guid.NewGuid().ToString().Replace("-", string.Empty).Replace("=", string.Empty).Replace("+", string.Empty).Substring(0, 6);
        }
    }
}

Open in new window


Container.cs

using System;
using ExtensionMethods;

namespace ContainerPackerWinForms
{
    public class Container
    {
        #region Properties
        
        public string ContainerID { get; private set; }        
        public string Description { get; set; }        
        public double CapacityWeight { get; set; }        
        public double CapacityCube { get; set; }
        
        #endregion  

        #region Constructor

        // Default constructor
        public Container()
        {
            ContainerID = Extension.NewID();
        }

        #endregion
    }
}

Open in new window