diff --git a/PreventSelection.gif b/PreventSelection.gif new file mode 100644 index 0000000..2ec01a4 Binary files /dev/null and b/PreventSelection.gif differ diff --git a/README.md b/README.md index 7a1558e..4ad11ae 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,23 @@ -# How-to-prevent-the-user-from-selecting-more-than-a-specific-number-of-rows-in-a-WinForms-DataGrid -This demo shows how to prevent the user from selecting more than a specific number of rows in a WinForms DataGrid +# How to prevent the user from selecting more than a specific number of rows in a WinForms DataGrid? + +In [WinForms DataGrid](https://www.syncfusion.com/winforms-ui-controls/datagrid) (SfDataGrid), limiting selection to a maximum of two can be achieved by handling the [SelectionChanging](https://help.syncfusion.com/cr/windowsforms/Syncfusion.WinForms.DataGrid.SfDataGrid.html#Syncfusion_WinForms_DataGrid_SfDataGrid_SelectionChanging) event. Within this event, logic can be applied to evaluate the counts of [SelectedItems](https://help.syncfusion.com/cr/windowsforms/Syncfusion.WinForms.DataGrid.SfDataGrid.html#Syncfusion_WinForms_DataGrid_SfDataGrid_SelectedItems), **RemovedItems**, and **AddedItems**. If the total number of selected rows exceeds two, the selection process can be cancelled by setting **e.cancel** to **true**. + +```csharp +//Event subscription +sfDataGrid1.SelectionChanging += OnSelectionChanging; + +//Event customization +private void OnSelectionChanging(object sender, SelectionChangingEventArgs e) +{ + var dataGrid = (sender as SfDataGrid); + if (dataGrid != null && (dataGrid.SelectedItems.Count + e.AddedItems.Count - e.RemovedItems.Count > 2)) + { + // Cancel the selection above 2 rows + e.Cancel = true; + } +} +``` + +![Prevent the selection](PreventSelection.gif) + +Take a moment to peruse the [WinForms DataGrid - Selection](https://help.syncfusion.com/windowsforms/datagrid/selection) documentation, to learn more about selection with examples. \ No newline at end of file diff --git a/SfDataGridDemo/App.config b/SfDataGridDemo/App.config new file mode 100644 index 0000000..4bfa005 --- /dev/null +++ b/SfDataGridDemo/App.config @@ -0,0 +1,6 @@ + + + + + + diff --git a/SfDataGridDemo/Form1.Designer.cs b/SfDataGridDemo/Form1.Designer.cs new file mode 100644 index 0000000..5c0e488 --- /dev/null +++ b/SfDataGridDemo/Form1.Designer.cs @@ -0,0 +1,65 @@ +namespace SfDataGrid_Demo +{ + partial class Form1 + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.sfDataGrid1 = new Syncfusion.WinForms.DataGrid.SfDataGrid(); + ((System.ComponentModel.ISupportInitialize)(this.sfDataGrid1)).BeginInit(); + this.SuspendLayout(); + // + // sfDataGrid1 + // + this.sfDataGrid1.AccessibleName = "Table"; + this.sfDataGrid1.Location = new System.Drawing.Point(20, 20); + this.sfDataGrid1.Margin = new System.Windows.Forms.Padding(4, 5, 4, 5); + this.sfDataGrid1.Name = "sfDataGrid1"; + this.sfDataGrid1.PreviewRowHeight = 42; + this.sfDataGrid1.Size = new System.Drawing.Size(829, 538); + this.sfDataGrid1.TabIndex = 0; + this.sfDataGrid1.Text = "sfDataGrid1"; + // + // Form1 + // + this.AutoScaleDimensions = new System.Drawing.SizeF(9F, 20F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.ClientSize = new System.Drawing.Size(892, 589); + this.Controls.Add(this.sfDataGrid1); + this.Margin = new System.Windows.Forms.Padding(4, 5, 4, 5); + this.Name = "Form1"; + this.Text = "PeventSelection"; + ((System.ComponentModel.ISupportInitialize)(this.sfDataGrid1)).EndInit(); + this.ResumeLayout(false); + + } + + #endregion + + private Syncfusion.WinForms.DataGrid.SfDataGrid sfDataGrid1; + } +} + diff --git a/SfDataGridDemo/Form1.cs b/SfDataGridDemo/Form1.cs new file mode 100644 index 0000000..758cfd2 --- /dev/null +++ b/SfDataGridDemo/Form1.cs @@ -0,0 +1,52 @@ +using SfDataGrid_Demo; +using Syncfusion.WinForms.DataGrid; +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Data; +using System.Drawing; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Forms; +using Syncfusion.WinForms.DataGrid.Events; +using Syncfusion.WinForms.DataGrid.Enums; + +namespace SfDataGrid_Demo +{ + public partial class Form1 : Form + { + OrderInfoCollection orderInfo; + + public Form1() + { + InitializeComponent(); + + orderInfo = new OrderInfoCollection(); + + sfDataGrid1.AutoGenerateColumns = false; + sfDataGrid1.SelectionMode = GridSelectionMode.Multiple; + sfDataGrid1.DataSource = orderInfo.Orders; + + sfDataGrid1.Columns.Add(new GridNumericColumn() { MappingName = "OrderID", HeaderText = "Order ID", AllowEditing = false }); + sfDataGrid1.Columns.Add(new GridTextColumn() { MappingName = "CustomerID", HeaderText = "Customer ID" , AllowEditing = true}); + sfDataGrid1.Columns.Add(new GridTextColumn() { MappingName = "CustomerName", HeaderText = "Name", AllowEditing = false }); + sfDataGrid1.Columns.Add(new GridTextColumn() { MappingName = "Country", HeaderText = "Country" , AllowEditing = true }); + sfDataGrid1.Columns.Add(new GridTextColumn() { MappingName = "ShipCity", HeaderText = "Ship City" , AllowEditing = false }); + + //Event subscription + sfDataGrid1.SelectionChanging += OnSelectionChanging; + } + + //Event customization + private void OnSelectionChanging(object sender, SelectionChangingEventArgs e) + { + var dataGrid = (sender as SfDataGrid); + if (dataGrid != null && (dataGrid.SelectedItems.Count + e.AddedItems.Count - e.RemovedItems.Count > 2)) + { + // Cancel the selection above 2 rows + e.Cancel = true; + } + } + } +} diff --git a/SfDataGridDemo/Form1.resx b/SfDataGridDemo/Form1.resx new file mode 100644 index 0000000..1af7de1 --- /dev/null +++ b/SfDataGridDemo/Form1.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/SfDataGridDemo/Model/Model.cs b/SfDataGridDemo/Model/Model.cs new file mode 100644 index 0000000..5020937 --- /dev/null +++ b/SfDataGridDemo/Model/Model.cs @@ -0,0 +1,90 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace SfDataGrid_Demo +{ + public class OrderInfo : INotifyPropertyChanged + { + int orderID; + string customerId; + string country; + string customerName; + string shipCity; + + public int OrderID + { + get { return orderID; } + set + { + orderID = value; + OnPropertyChanged("OrderID"); + } + } + + public string CustomerID + { + get { return customerId; } + set + { + customerId = value; + OnPropertyChanged("CustomerID"); + } + } + + public string CustomerName + { + get { return customerName; } + set + { + customerName = value; + OnPropertyChanged("CustomerName"); + } + } + + public string Country + { + get { return country; } + set + { + country = value; + OnPropertyChanged("Country"); + } + } + + public string ShipCity + { + get { return shipCity; } + set + { + shipCity = value; + OnPropertyChanged("ShipCity"); + } + } + + public OrderInfo(int orderId, string customerName, string country, string customerId, string shipCity) + { + this.OrderID = orderId; + this.CustomerName = customerName; + this.Country = country; + this.CustomerID = customerId; + this.ShipCity = shipCity; + } + + public OrderInfo() + { + + } + + public event PropertyChangedEventHandler PropertyChanged; + + public void OnPropertyChanged(string PropertyName) + { + if (PropertyChanged != null) + PropertyChanged(this, new PropertyChangedEventArgs(PropertyName)); + } + } +} diff --git a/SfDataGridDemo/Program.cs b/SfDataGridDemo/Program.cs new file mode 100644 index 0000000..5e3880d --- /dev/null +++ b/SfDataGridDemo/Program.cs @@ -0,0 +1,22 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using System.Windows.Forms; + +namespace SfDataGrid_Demo +{ + internal static class Program + { + /// + /// The main entry point for the application. + /// + [STAThread] + static void Main() + { + Application.EnableVisualStyles(); + Application.SetCompatibleTextRenderingDefault(false); + Application.Run(new Form1()); + } + } +} diff --git a/SfDataGridDemo/Properties/AssemblyInfo.cs b/SfDataGridDemo/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..a588b52 --- /dev/null +++ b/SfDataGridDemo/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("SfDataGrid_Demo")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("SfDataGrid_Demo")] +[assembly: AssemblyCopyright("Copyright © 2023")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("bdbd569e-f901-47fa-b118-e30f45de782a")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/SfDataGridDemo/Properties/Resources.Designer.cs b/SfDataGridDemo/Properties/Resources.Designer.cs new file mode 100644 index 0000000..4a9b293 --- /dev/null +++ b/SfDataGridDemo/Properties/Resources.Designer.cs @@ -0,0 +1,63 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.42000 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace SfDataGrid_Demo.Properties { + using System; + + + /// + /// A strongly-typed resource class, for looking up localized strings, etc. + /// + // This class was auto-generated by the StronglyTypedResourceBuilder + // class via a tool like ResGen or Visual Studio. + // To add or remove a member, edit your .ResX file then rerun ResGen + // with the /str option, or rebuild your VS project. + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + internal class Resources { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal Resources() { + } + + /// + /// Returns the cached ResourceManager instance used by this class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Resources.ResourceManager ResourceManager { + get { + if (object.ReferenceEquals(resourceMan, null)) { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("SfDataGrid_Demo.Properties.Resources", typeof(Resources).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture { + get { + return resourceCulture; + } + set { + resourceCulture = value; + } + } + } +} diff --git a/SfDataGridDemo/Properties/Resources.resx b/SfDataGridDemo/Properties/Resources.resx new file mode 100644 index 0000000..af7dbeb --- /dev/null +++ b/SfDataGridDemo/Properties/Resources.resx @@ -0,0 +1,117 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/SfDataGridDemo/Properties/Settings.Designer.cs b/SfDataGridDemo/Properties/Settings.Designer.cs new file mode 100644 index 0000000..a646a6f --- /dev/null +++ b/SfDataGridDemo/Properties/Settings.Designer.cs @@ -0,0 +1,26 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.42000 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace SfDataGrid_Demo.Properties { + + + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "17.14.0.0")] + internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase { + + private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); + + public static Settings Default { + get { + return defaultInstance; + } + } + } +} diff --git a/SfDataGridDemo/Properties/Settings.settings b/SfDataGridDemo/Properties/Settings.settings new file mode 100644 index 0000000..3964565 --- /dev/null +++ b/SfDataGridDemo/Properties/Settings.settings @@ -0,0 +1,7 @@ + + + + + + + diff --git a/SfDataGridDemo/SfDataGrid_Demo.csproj b/SfDataGridDemo/SfDataGrid_Demo.csproj new file mode 100644 index 0000000..82d9010 --- /dev/null +++ b/SfDataGridDemo/SfDataGrid_Demo.csproj @@ -0,0 +1,96 @@ + + + + + Debug + AnyCPU + {BDBD569E-F901-47FA-B118-E30F45DE782A} + WinExe + SfDataGrid_Demo + SfDataGrid_Demo + v4.8 + 512 + true + true + + + + AnyCPU + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + AnyCPU + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + + + + + + + + + + + + + + + + + + + + + + + Form + + + Form1.cs + + + + + + + Form1.cs + + + ResXFileCodeGenerator + Resources.Designer.cs + Designer + + + True + Resources.resx + True + + + SettingsSingleFileGenerator + Settings.Designer.cs + + + True + Settings.settings + True + + + + + + + \ No newline at end of file diff --git a/SfDataGridDemo/SfDataGrid_Demo.sln b/SfDataGridDemo/SfDataGrid_Demo.sln new file mode 100644 index 0000000..f69f567 --- /dev/null +++ b/SfDataGridDemo/SfDataGrid_Demo.sln @@ -0,0 +1,25 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.6.33723.286 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SfDataGrid_Demo", "SfDataGrid_Demo.csproj", "{BDBD569E-F901-47FA-B118-E30F45DE782A}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {BDBD569E-F901-47FA-B118-E30F45DE782A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {BDBD569E-F901-47FA-B118-E30F45DE782A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {BDBD569E-F901-47FA-B118-E30F45DE782A}.Release|Any CPU.ActiveCfg = Release|Any CPU + {BDBD569E-F901-47FA-B118-E30F45DE782A}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {DEA26F63-1CEC-4975-A166-16B22A14E545} + EndGlobalSection +EndGlobal diff --git a/SfDataGridDemo/ViewModel/ViewModel.cs b/SfDataGridDemo/ViewModel/ViewModel.cs new file mode 100644 index 0000000..4ab9f24 --- /dev/null +++ b/SfDataGridDemo/ViewModel/ViewModel.cs @@ -0,0 +1,41 @@ +using SfDataGrid_Demo; +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace SfDataGrid_Demo +{ + public class OrderInfoCollection + { + private ObservableCollection _orders; + + public ObservableCollection Orders + { + get { return _orders; } + set { _orders = value; } + } + + public OrderInfoCollection() + { + _orders = new ObservableCollection(); + this.GenerateOrders(); + } + + private void GenerateOrders() + { + _orders.Add(new OrderInfo(1001, "Maria", "Germany", "ALFKI", "Berlin")); + _orders.Add(new OrderInfo(1002, "Trujilo", "Mexico", "ANATR", "Mexico D.F.")); + _orders.Add(new OrderInfo(1003, "Antonio", "Mexico", "ANTON", "Mexico D.F.")); + _orders.Add(new OrderInfo(1004, "Thomas", "UK", "AROUT", "London")); + _orders.Add(new OrderInfo(1005, "Christina", "Sweden", "BERGS", "Lula")); + _orders.Add(new OrderInfo(1006, "Hanna", "Germany", "BLAUS", "Mannheim")); + _orders.Add(new OrderInfo(1007, "Citeaux", "France", "BLONP", "Strasbourg")); + _orders.Add(new OrderInfo(1008, "Martin", "Spain", "BOLID", "Madrid")); + _orders.Add(new OrderInfo(1009, "Laurence", "France", "BONAP", "Marseille")); + _orders.Add(new OrderInfo(1010, "Elizabeth", "Canada", "BOTTM", "Tsawassen")); + } + } +}