diff --git a/Documentation/Blazorise.Docs/Blazorise.Docs.csproj b/Documentation/Blazorise.Docs/Blazorise.Docs.csproj index 7b364bec0a..c88195e427 100644 --- a/Documentation/Blazorise.Docs/Blazorise.Docs.csproj +++ b/Documentation/Blazorise.Docs/Blazorise.Docs.csproj @@ -82,11 +82,6 @@ - - - true - - diff --git a/Documentation/Blazorise.Docs/Models/Snippets.generated.cs b/Documentation/Blazorise.Docs/Models/Snippets.generated.cs index fbe2cab561..433ef49285 100644 --- a/Documentation/Blazorise.Docs/Models/Snippets.generated.cs +++ b/Documentation/Blazorise.Docs/Models/Snippets.generated.cs @@ -9001,6 +9001,73 @@ protected override async Task OnInitializedAsync() } }"; + public const string DataGridSelectColumnMultipleExample = @" + ((Activity)x).Code"" + TextField=""(x) => ((Activity)x).Description"" /> + + + +@code { + [Inject] + public EmployeeData EmployeeData { get; set; } + private List employeeList; + + protected override async Task OnInitializedAsync() + { + employeeList = (await EmployeeData.GetDataAsync()).Select(x => new EmployeeActivity(x) + { + Activities = activities + .OrderBy(x => Random.Shared.Next()) + .Take(Random.Shared.Next(5)) + .Select(x => x.Code).ToArray() + }).ToList(); + + await base.OnInitializedAsync(); + } + + private List activities = new List + { + new Activity { Code = ""MEET"", Description = ""Meeting"" }, + new Activity { Code = ""TRAIN"", Description = ""Training"" }, + new Activity { Code = ""CODE"", Description = ""Coding"" }, + new Activity { Code = ""R&D"", Description = ""Research"" }, + new Activity { Code = ""TEST"", Description = ""Testing"" }, + }; + + public class EmployeeActivity : Employee + { + public string[] Activities { get; set; } + + public EmployeeActivity(Employee employee) + { + this.City = employee.City; + this.Email = employee.Email; + this.FirstName = employee.FirstName; + this.LastName = employee.LastName; + this.Salary = employee.Salary; + this.DateOfBirth = employee.DateOfBirth; + this.Gender = employee.Gender; + this.Childrens = employee.Childrens; + this.Id = employee.Id; + this.Zip = employee.Zip; + this.Tax = employee.Tax; + this.Salaries = employee.Salaries; + this.IsActive = employee.IsActive; + } + } + + public class Activity + { + public string Code { get; set; } + public string Description { get; set; } + } +}"; + public const string DataGridSelectingExample = @" x.Item.FirstName != ""John"") diff --git a/Documentation/Blazorise.Docs/Pages/Docs/Extensions/DataGrid/Code/DataGridSelectColumnMultipleExampleCode.html b/Documentation/Blazorise.Docs/Pages/Docs/Extensions/DataGrid/Code/DataGridSelectColumnMultipleExampleCode.html new file mode 100644 index 0000000000..9803c5f7d3 --- /dev/null +++ b/Documentation/Blazorise.Docs/Pages/Docs/Extensions/DataGrid/Code/DataGridSelectColumnMultipleExampleCode.html @@ -0,0 +1,71 @@ +
+
+<DataGrid TItem="EmployeeActivity" Data="@employeeList" PageSize="5" Responsive Editable>
+    <DataGridSelectColumn TItem="EmployeeActivity" Field="@nameof( EmployeeActivity.Activities )"
+                          Caption="Activity" 
+                          Editable
+                          Multiple 
+                          Data="activities"
+                          ValueField="(x) => ((Activity)x).Code"
+                          TextField="(x) => ((Activity)x).Description" />
+    <DataGridCommandColumn />
+</DataGrid>
+
+
+@code {
+    [Inject]
+    public EmployeeData EmployeeData { get; set; }
+    private List<EmployeeActivity> employeeList;
+
+    protected override async Task OnInitializedAsync()
+    {
+        employeeList = (await EmployeeData.GetDataAsync()).Select(x => new EmployeeActivity(x)
+            {
+                Activities = activities
+                        .OrderBy(x => Random.Shared.Next())
+                        .Take(Random.Shared.Next(5))
+                        .Select(x => x.Code).ToArray()
+            }).ToList();
+
+        await base.OnInitializedAsync();
+    }
+
+    private List<Activity> activities = new List<Activity>
+    {
+        new Activity { Code = "MEET", Description = "Meeting" },
+        new Activity { Code = "TRAIN", Description = "Training" },
+        new Activity { Code = "CODE", Description = "Coding" },
+        new Activity { Code = "R&D", Description = "Research" },
+        new Activity { Code = "TEST", Description = "Testing" },
+    };
+
+    public class EmployeeActivity : Employee
+    {
+        public string[] Activities { get; set; }
+
+        public EmployeeActivity(Employee employee)
+        {
+            this.City = employee.City;
+            this.Email = employee.Email;
+            this.FirstName = employee.FirstName;
+            this.LastName = employee.LastName;
+            this.Salary = employee.Salary;
+            this.DateOfBirth = employee.DateOfBirth;
+            this.Gender = employee.Gender;
+            this.Childrens = employee.Childrens;
+            this.Id = employee.Id;
+            this.Zip = employee.Zip;
+            this.Tax = employee.Tax;
+            this.Salaries = employee.Salaries;
+            this.IsActive = employee.IsActive;
+        }
+    }
+
+    public class Activity
+    {
+        public string Code { get; set; }
+        public string Description { get; set; }
+    }
+}
+
+
diff --git a/Documentation/Blazorise.Docs/Pages/Docs/Extensions/DataGrid/ColumnsPage.razor b/Documentation/Blazorise.Docs/Pages/Docs/Extensions/DataGrid/ColumnsPage.razor index 7c05ad5500..a7a27efa75 100644 --- a/Documentation/Blazorise.Docs/Pages/Docs/Extensions/DataGrid/ColumnsPage.razor +++ b/Documentation/Blazorise.Docs/Pages/Docs/Extensions/DataGrid/ColumnsPage.razor @@ -87,6 +87,17 @@ + + + Column template for selectable values. Allow multiple values support by setting Multiple to true. Bind a string or value type array. + + + + + + + + \ No newline at end of file diff --git a/Documentation/Blazorise.Docs/Pages/Docs/Extensions/DataGrid/Examples/DataGridSelectColumnMultipleExample.razor b/Documentation/Blazorise.Docs/Pages/Docs/Extensions/DataGrid/Examples/DataGridSelectColumnMultipleExample.razor new file mode 100644 index 0000000000..d82f431617 --- /dev/null +++ b/Documentation/Blazorise.Docs/Pages/Docs/Extensions/DataGrid/Examples/DataGridSelectColumnMultipleExample.razor @@ -0,0 +1,68 @@ +@namespace Blazorise.Docs.Docs.Examples + + + + + + +@code { + [Inject] + public EmployeeData EmployeeData { get; set; } + private List employeeList; + + protected override async Task OnInitializedAsync() + { + employeeList = (await EmployeeData.GetDataAsync()).Select(x => new EmployeeActivity(x) + { + Activities = activities + .OrderBy(x => Random.Shared.Next()) + .Take(Random.Shared.Next(5)) + .Select(x => x.Code).ToArray() + }).ToList(); + + await base.OnInitializedAsync(); + } + + private List activities = new List + { + new Activity { Code = "MEET", Description = "Meeting" }, + new Activity { Code = "TRAIN", Description = "Training" }, + new Activity { Code = "CODE", Description = "Coding" }, + new Activity { Code = "R&D", Description = "Research" }, + new Activity { Code = "TEST", Description = "Testing" }, + }; + + public class EmployeeActivity : Employee + { + public string[] Activities { get; set; } + + public EmployeeActivity(Employee employee) + { + this.City = employee.City; + this.Email = employee.Email; + this.FirstName = employee.FirstName; + this.LastName = employee.LastName; + this.Salary = employee.Salary; + this.DateOfBirth = employee.DateOfBirth; + this.Gender = employee.Gender; + this.Childrens = employee.Childrens; + this.Id = employee.Id; + this.Zip = employee.Zip; + this.Tax = employee.Tax; + this.Salaries = employee.Salaries; + this.IsActive = employee.IsActive; + } + } + + public class Activity + { + public string Code { get; set; } + public string Description { get; set; } + } +} \ No newline at end of file diff --git a/Documentation/Blazorise.Docs/Pages/News/2025-05-01-release-notes-200.razor b/Documentation/Blazorise.Docs/Pages/News/2025-05-01-release-notes-200.razor new file mode 100644 index 0000000000..a25f862da2 --- /dev/null +++ b/Documentation/Blazorise.Docs/Pages/News/2025-05-01-release-notes-200.razor @@ -0,0 +1,107 @@ +@page "/news/release-notes/200" + + + + + + + Announcing Blazorise 2.0 - [CodeName] + + + + Welcome to the Blazorise 2.0 release, packed with exciting new features, optimizations, and support for the latest .NET framework. Dive into the highlights below to explore how Blazorise 2.0 can enhance your applications. + + + + Key Blazorise 1.0 Highlights 💡 + + + + Here's a summary of what's new in this release: + + + + + + DataGridSelectColumn: Multiple support + + + + + + Dive into each section for a comprehensive overview of these features and learn how they can enhance your projects. We value your feedback and encourage you to share your thoughts as we continue to refine and improve Blazorise. + + + + Upgrading from 1.7.x to 2.0 👨‍🔧 + + + + Upgrade your Blazorise application seamlessly with the following steps: + + + + + + Update all Blazorise.* package references to 2.0. + + + + + Blazorise should now work without any major breaking change to the API, but there are some necessary changes that we had to do to make Blazorise better. Continue reading the Migration section for more details. + + + + + + Migration Notes 🛠 + + + + A few API changes and behavior updates have been introduced in Blazorise 2.0 to improve consistency and functionality. Here’s a summary: + + + + + + + + + + + + + + + + + + + New Features & Enhancements 🚀 + + + + DataGrid + + + + DataGridSelectColumn Multiple support + + + + You may now allow multiple values to be selected in the DataGridSelectColumn. Set the new Multiple parameter to true to enable this feature. Please bind the corresponding array to successfully bind the multiple values. + + + + Final Notes + + + + + + + + As always, your feedback is invaluable in guiding future Blazorise development. We encourage you to try out the new features and let us know your thoughts. Thank you for your continued support and enthusiasm for Blazorise, and we look forward to bringing you even more enhancements in future updates! + + + \ No newline at end of file diff --git a/Shared/Blazorise.Shared/Data/EmployeeData.cs b/Shared/Blazorise.Shared/Data/EmployeeData.cs index bb54f2c9cd..e490ebb61d 100644 --- a/Shared/Blazorise.Shared/Data/EmployeeData.cs +++ b/Shared/Blazorise.Shared/Data/EmployeeData.cs @@ -56,8 +56,8 @@ public EmployeeData( IMemoryCache memoryCache ) public async Task> GetDataAsync() => ( await cache.GetOrCreateAsync( employeesCacheKey, LoadData ) ) - .Select( x => new Employee(x) ) //new() is used so we make sure that we are not returning the same item references avoiding an application wide "data corruption". - .ToList(); + .Select( x => new Employee( x ) ) //new() is used so we make sure that we are not returning the same item references avoiding an application wide "data corruption". + .ToList(); private Task> LoadData( ICacheEntry cacheEntry ) { diff --git a/Shared/Blazorise.Shared/Models/Employee.cs b/Shared/Blazorise.Shared/Models/Employee.cs index 4c7b01d389..4a6fdc4eeb 100644 --- a/Shared/Blazorise.Shared/Models/Employee.cs +++ b/Shared/Blazorise.Shared/Models/Employee.cs @@ -8,7 +8,6 @@ public class Employee { public Employee() { - } public Employee( Employee other ) @@ -85,6 +84,4 @@ public decimal ChildrensPerSalary public decimal TaxPercentage = 0.25m; private decimal tax; -} - - +} \ No newline at end of file diff --git a/Source/Extensions/Blazorise.DataGrid/BaseDataGridColumn.cs b/Source/Extensions/Blazorise.DataGrid/BaseDataGridColumn.cs index 5f3704ac0a..6e68687e32 100644 --- a/Source/Extensions/Blazorise.DataGrid/BaseDataGridColumn.cs +++ b/Source/Extensions/Blazorise.DataGrid/BaseDataGridColumn.cs @@ -16,9 +16,9 @@ public class BaseDataGridColumn : BaseDataGridComponent /// /// Item the contains the value to format. /// Formatted display value. - public string FormatDisplayValue( object value ) + public virtual string FormatDisplayValue( object value ) { - if ( DisplayFormat != null ) + if ( DisplayFormat is not null ) { return string.Format( DisplayFormatProvider ?? CultureInfo.CurrentCulture, DisplayFormat, value ); } diff --git a/Source/Extensions/Blazorise.DataGrid/DataGridSelectColumn.cs b/Source/Extensions/Blazorise.DataGrid/DataGridSelectColumn.cs index aa774f9000..19a90a1f9f 100644 --- a/Source/Extensions/Blazorise.DataGrid/DataGridSelectColumn.cs +++ b/Source/Extensions/Blazorise.DataGrid/DataGridSelectColumn.cs @@ -1,11 +1,32 @@ -using System; +#region Using directives +using System; +using System.Collections; using System.Collections.Generic; +using System.Linq; using Microsoft.AspNetCore.Components; +#endregion namespace Blazorise.DataGrid; public class DataGridSelectColumn : DataGridColumn { + #region Methods + + /// + public override string FormatDisplayValue( object value ) + { + if ( value is not string && value is IEnumerable values ) + { + return base.FormatDisplayValue( string.Join( ", ", values.Cast().Select( x => x?.ToString() ) ) ); + } + + return base.FormatDisplayValue( value ); + } + + #endregion + + #region Properties + public override DataGridColumnType ColumnType => DataGridColumnType.Select; /// @@ -81,9 +102,16 @@ public class DataGridSelectColumn : DataGridColumn /// [Parameter] public bool Disabled { get; set; } + /// + /// Specifies that multiple items can be selected. + /// + [Parameter] public bool Multiple { get; set; } + /// /// Captures all the custom attribute that are not part of Blazorise component. /// [Parameter( CaptureUnmatchedValues = true )] public Dictionary Attributes { get; set; } + + #endregion } \ No newline at end of file diff --git a/Source/Extensions/Blazorise.DataGrid/_DataGridCellSelectEdit.razor b/Source/Extensions/Blazorise.DataGrid/_DataGridCellSelectEdit.razor index 7345ba5b22..2a7ca6b80f 100644 --- a/Source/Extensions/Blazorise.DataGrid/_DataGridCellSelectEdit.razor +++ b/Source/Extensions/Blazorise.DataGrid/_DataGridCellSelectEdit.razor @@ -1,7 +1,7 @@ @typeparam TItem @inherits ComponentBase - @if ( Column.DefaultItemText is not null ) { diff --git a/Source/Extensions/Blazorise.DataGrid/_DataGridCellSelectEdit.razor.cs b/Source/Extensions/Blazorise.DataGrid/_DataGridCellSelectEdit.razor.cs index fd2fc9d501..40e5276259 100644 --- a/Source/Extensions/Blazorise.DataGrid/_DataGridCellSelectEdit.razor.cs +++ b/Source/Extensions/Blazorise.DataGrid/_DataGridCellSelectEdit.razor.cs @@ -1,4 +1,5 @@ #region Using directives +using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using Blazorise.Modules; @@ -77,6 +78,74 @@ private void OnSelectedValueChanged( object value ) } } + private async Task OnSelectedValuesChanged( IReadOnlyList values ) + { + var columnType = Column.GetValueType( default ); + + if ( columnType.IsArray ) + { + var valueType = columnType.GetElementType(); + if ( valueType == typeof( int ) ) + { + await CellValueChanged.InvokeAsync( values?.Select( x => int.Parse( x.ToString() ) )?.ToArray() ); + } + else if ( valueType == typeof( short ) ) + { + await CellValueChanged.InvokeAsync( values?.Select( x => short.Parse( x.ToString() ) )?.ToArray() ); + } + else if ( valueType == typeof( decimal ) ) + { + await CellValueChanged.InvokeAsync( values?.Select( x => decimal.Parse( x.ToString() ) )?.ToArray() ); + } + else if ( valueType == typeof( double ) ) + { + await CellValueChanged.InvokeAsync( values?.Select( x => double.Parse( x.ToString() ) )?.ToArray() ); + } + else if ( valueType == typeof( float ) ) + { + await CellValueChanged.InvokeAsync( values?.Select( x => float.Parse( x.ToString() ) )?.ToArray() ); + } + else + { + await CellValueChanged.InvokeAsync( values?.Select( x => x.ToString() )?.ToArray() ); + } + return; + } + + await CellValueChanged.InvokeAsync( values?.Select( x => x.ToString() )?.ToArray() ); + } + + public object[] GetSelectedValues() + { + var columnType = Column.GetValueType( default ); + + if ( CellValue is not null && columnType.IsArray ) + { + var valueType = columnType.GetElementType(); + if ( valueType == typeof( int ) ) + { + return ( CellValue as int[] )?.Select( x => (object)x )?.ToArray(); + } + else if ( valueType == typeof( short ) ) + { + return ( CellValue as short[] )?.Select( x => (object)x )?.ToArray(); + } + else if ( valueType == typeof( decimal ) ) + { + return ( CellValue as decimal[] )?.Select( x => (object)x )?.ToArray(); + } + else if ( valueType == typeof( double ) ) + { + return ( CellValue as double[] )?.Select( x => (object)x )?.ToArray(); + } + else if ( valueType == typeof( float ) ) + { + return ( CellValue as float[] )?.Select( x => (object)x )?.ToArray(); + } + } + return CellValue as object[]; + } + protected override async Task OnAfterRenderAsync( bool firstRender ) { if ( firstRender )