Compare commits

...

176 Commits

Author SHA1 Message Date
Vladimir Enchev
c4608f9465 Radzen.Blazor updated 2021-08-25 11:32:58 +03:00
Vladimir Enchev
6828ee95d7 Version updated 2021-08-25 11:24:49 +03:00
Vladimir Enchev
3cecde7c50 DataGrid column null ref. exception fixed when SortOrder is bound to null
Fix #204
2021-08-25 09:54:16 +03:00
Vladimir Enchev
1aec2dbfb4 DataGrid loading panel not working properly with frozen columns 2021-08-25 07:21:03 +03:00
Vladimir Enchev
ba3f28cd5b DataGrid and DataList pager Count not calculated properly 2021-08-24 09:42:03 +03:00
Vladimir Enchev
b8b6a749ce Switch mouse events not raised 2021-08-23 20:32:45 +03:00
Vladimir Enchev
1d1c64119d Radzen.Blazor updated 2021-08-23 18:01:34 +03:00
Vladimir Enchev
e93e4d03a1 Version updated 2021-08-23 17:56:26 +03:00
Vladimir Enchev
1ddbb1b197 Fixed DropDown LINQ expression cannot be translated with AllowFiltering and IQueryable 2021-08-23 07:06:20 +03:00
Vladimir Enchev
3632c3b19e DataGrid InsertRow() fixed to work with LoadData binding 2021-08-20 17:23:09 +03:00
Vladimir Enchev
25651d84dd DataGrid InsertRow() will break the pager if not on first page 2021-08-20 16:58:46 +03:00
Vladimir Enchev
5a59b245ce Focused element lost after DropDown select 2021-08-20 16:28:10 +03:00
Vladimir Enchev
cf33f8bf74 DataGrid group rows not update on groups remove 2021-08-19 18:46:24 +03:00
Atanas Korchev
bfb86a67da DataGrid validation does not work. 2021-08-19 18:23:22 +03:00
douglassimaodev
c076f7641d AllowInput Implementation (#201)
* AllowInput Implementation

Co-authored-by: Douglas Simao <douglas.simao@hse.ie>
2021-08-19 17:06:19 +03:00
Vladimir Enchev
ff6efc7681 Radzen.Blazor updated 2021-08-18 19:14:23 +03:00
Vladimir Enchev
30a0583aab Version updated 2021-08-18 18:33:39 +03:00
Atanas Korchev
ea27a1802d Use oninput to prevent bypassing of the mask. 2021-08-18 18:24:47 +03:00
Vladimir Enchev
9c23bbd309 Radzen.Blazor updated 2021-08-18 12:42:01 +03:00
Vladimir Enchev
a0680ffa8f Version updated 2021-08-18 12:36:46 +03:00
Vladimir Enchev
94c4b723ad DataGrid GroupHeaderText renamed to GroupPanelText 2021-08-18 12:36:08 +03:00
Vladimir Enchev
23ee6c2bb1 Fixed component cannot be focused after leaving DropDown 2021-08-18 10:50:26 +03:00
Vladimir Enchev
02058e523f Radzen.Blazor updated 2021-08-18 09:55:01 +03:00
Vladimir Enchev
e1951f3637 Version updated 2021-08-18 09:51:52 +03:00
Vladimir Enchev
7039478ebc DataGrid grouping support added (#199)
* grouping by column added

* grouping examples added

* group model added

* Groups exposed
2021-08-18 09:50:08 +03:00
Vladimir Enchev
ff566466c8 Fixed reordering DataGrid columns with hidden columns is not working
Fix #194
2021-08-16 09:06:45 +03:00
Vladimir Enchev
3dae1aac2d Fixed DropDownDataGrid exception when filtering non string data
Fix #196
2021-08-16 08:59:32 +03:00
Vladimir Enchev
43dad21cad Radzen.Blazor updated 2021-08-09 11:13:15 +03:00
Vladimir Enchev
9f07373e33 Version updated 2021-08-09 11:07:07 +03:00
Vladimir Enchev
b09e4f3b6a Login tests updated 2021-08-09 11:06:40 +03:00
Vladimir Enchev
be66132498 Count not correct when filtering 2021-08-09 09:28:42 +03:00
viordash
a6a70cc88e Fix pager visibility (#192)
* RadzenPager. disable hiding by count of items if PageSizeOptions are specified

* add tests for Pager
2021-08-09 09:24:00 +03:00
viordash
63d04b7734 RadzenPager. fix current page selection after page size changed (#193) 2021-08-09 09:23:47 +03:00
Vladimir Enchev
90edd71274 DataGrid column reorder (#191)
* DataGrid columns reorder added

* Columns reorder demo updated

* ColumnReordered event added to demo
2021-08-06 18:45:33 +03:00
Vladimir Enchev
db0252dc2c Examples filtering fixed 2021-08-06 10:32:44 +03:00
Vladimir Enchev
8b3e13ecba DataGrid DoesNotContain not working properly with LoadData binding 2021-08-04 09:49:22 +03:00
Vladimir Enchev
5ac96dd852 Tooltip dispose fixed 2021-08-04 09:39:27 +03:00
Vladimir Enchev
cf1ad22af1 Radzen.Blazor updated 2021-08-03 10:53:48 +03:00
Vladimir Enchev
4cf7e6888b Version updated 2021-08-02 15:47:27 +03:00
Vladimir Enchev
1aa4e8bbb2 Fixed item select in DropDown bound to KeyValuePair throws exception 2021-08-02 15:47:04 +03:00
Vladimir Enchev
d9db327ffa Dashboard demo data fixed
Fix #190
2021-08-02 15:03:40 +03:00
GioeEng
6f484766ac Error in icon representation. Incorrect design compromised panel behavior (#188)
* New splitter component

* New Splitter component

* Fixed code style and naming conventions

* themes implemented

* Splitter: Error in icon representation. Incorrect design compromised panel behavior

Co-authored-by: lorenzo <lorenzo.muccioli@car-tech.com>
Co-authored-by: Vladimir Enchev <vladimir.enchev@gmail.com>
2021-08-02 10:21:11 +03:00
Vladimir Enchev
9b6468c0b4 Radzen.Blazor updated 2021-07-29 16:05:50 +03:00
Vladimir Enchev
c5880c9096 Version updated 2021-07-29 15:58:05 +03:00
GioeEng
4d588b62cb New splitter component (#166)
* New splitter component

* New Splitter component

* Fixed code style and naming conventions

* themes implemented

Co-authored-by: lorenzo <lorenzo.muccioli@car-tech.com>
Co-authored-by: Vladimir Enchev <vladimir.enchev@gmail.com>
2021-07-29 15:56:38 +03:00
Vladimir Enchev
f6d2ab2e0e Fixed virtualization with LoadData and OData service 2021-07-29 10:15:35 +03:00
Vladimir Enchev
c52636a6e8 DropDownDataGrid initial PageSize not respected 2021-07-28 11:38:39 +03:00
Atanas Korchev
a24fb43ae8 Popup position is inverted when there is enough space for it. 2021-07-27 12:02:05 +03:00
Vladimir Enchev
8f7ead0687 Radzen.Blazor updated 2021-07-26 10:07:45 +03:00
Vladimir Enchev
39e6cc64a2 Version updated 2021-07-26 09:57:32 +03:00
Vladimir Enchev
4f985776e1 DataGrid Single ExpandMode does nothing when RowExpand is not set
Fix #179
2021-07-26 09:03:17 +03:00
Marco Papst
b9e992f118 allow to use RenderFragment for empty DataGrids (#184)
* allow to use RenderFragment for empty DataGrids

* remove cshtml file

* revert sln file from VS2022
2021-07-26 08:45:19 +03:00
Ken Dudley
39e5f969e8 Fixed bug for topandbottom pager at the same time. bottomPager was named topPager (#180)
Co-authored-by: Kenneth Dudley <kenneth.dudley@lumen.com>
2021-07-23 09:25:57 +03:00
Vladimir Enchev
ee79ce4bf6 Radzen.Blazor updated 2021-07-21 16:50:34 +03:00
Vladimir Enchev
20e7a98395 Version updated 2021-07-21 16:47:02 +03:00
Vladimir Enchev
c66be99be7 MenuItem and PanelMenuItem Template added
Fix #177
2021-07-21 16:46:49 +03:00
Vladimir Enchev
0bb5873fc5 Fixed DropDownDataGrid paging controls will close the popup
Fix #178
2021-07-21 09:08:23 +03:00
Vladimir Enchev
50bf0b4a3b DoesNotContainText fixed 2021-07-21 08:45:24 +03:00
Vladimir Enchev
d664652b53 Badge Visible fixed 2021-07-21 07:10:25 +03:00
Vladimir Enchev
77d500235b DataGrid FilterOperator DoesNotContain added 2021-07-20 11:08:32 +03:00
Vladimir Enchev
a7811d9425 Radzen.Blazor updated 2021-07-19 09:57:10 +03:00
Vladimir Enchev
6c6d9d507f Version updated 2021-07-19 09:51:36 +03:00
Vladimir Enchev
36ebc21d3e DataGrid boolean filter should be applied on Apply button 2021-07-19 09:51:17 +03:00
Vladimir Enchev
12f900cb6c Radzen.Blazor updated 2021-07-19 08:48:29 +03:00
Vladimir Enchev
e515bb4933 Version updated 2021-07-19 08:46:02 +03:00
Atanas Korchev
d93f46f4d6 RowDoubleClick does not fire for cells in edit mode. 2021-07-16 08:24:11 +03:00
viordash
1d4aaf04fd Radzen data grid column filter (#172)
* сolumn Type parameter is used as dominant for filterPropertyType

* WIP. add test for DataGridColumn filter property type

* assign filterPropertyType from Type only when FilterProperty is empty, otherwise assign filter type from FilterProperty field && add related tests

* clean code
2021-07-15 07:08:39 +03:00
Vladimir Enchev
65469210b1 Missing documentation links fixed 2021-07-14 19:53:11 +03:00
Marco Papst
88a8bf2769 Feature/badge component (#171)
* fix button unit test

* add RadzenBadge Component

* add RadzenBadge Component tests

* use scss & rz- classes instead of bootstrap

* add missing newline

* add badge scss to components

* remove underlined text from badge link

* cleanup badge page

* remove badge as link

* Add the inherited attributes from RadzenComponent.

Co-authored-by: Marco Papst <papst@sma.de>
Co-authored-by: Atanas Korchev <akorchev@gmail.com>
2021-07-14 16:29:19 +03:00
Vladimir Enchev
8429ff3150 Radzen.Blazor updated 2021-07-13 08:51:14 +03:00
Vladimir Enchev
890d352a65 Version updated 2021-07-13 08:48:25 +03:00
Vladimir Enchev
acb85071f0 Fixed context menu throws exception
Fix #170
2021-07-13 08:32:31 +03:00
Vladimir Enchev
e41a60613c Fixed DataGrid boolean column second filter 2021-07-12 18:55:41 +03:00
Vladimir Enchev
9001668e1b DataGrid null reference exception fixed when accessing columns value fromsub properties 2021-07-12 09:42:00 +03:00
Vladimir Enchev
7b78f22fcc Radzen.Blazor updated 2021-07-08 06:56:10 +03:00
Vladimir Enchev
b614e6c1a4 Version updated 2021-07-08 06:53:58 +03:00
Vladimir Enchev
187abcbcdf Popup close on scroll reworked 2021-07-07 20:16:05 +03:00
Vladimir Enchev
5a3a755f1a Should not close popups on mobile devices scroll
DropDown popup closes when trying to type something for filter
2021-07-07 15:23:25 +03:00
Vladimir Enchev
386e539148 Radzen.Blazor updated 2021-07-05 16:49:59 +03:00
Vladimir Enchev
d05375447b Version updated 2021-07-05 16:46:59 +03:00
Vladimir Enchev
0fc5791b8e DataGrid filtering by numeric not working in simple mode
Fix #165
2021-07-05 16:46:28 +03:00
Vladimir Enchev
0e4f851098 Radzen.Blazor updated 2021-07-05 16:32:43 +03:00
Vladimir Enchev
2488378099 version updated 2021-07-05 16:28:49 +03:00
Vladimir Enchev
b906890de1 Cannot check Tree item when AllowCheckChildren is set to false 2021-07-05 16:28:16 +03:00
Vladimir Enchev
feb0236d50 Radzen.Blazor updated 2021-07-05 10:26:56 +03:00
Vladimir Enchev
22104a9bdb Version updated 2021-07-05 10:18:39 +03:00
Atanas Korchev
d0ccd9d77a Rating ReadOnly property. 2021-07-02 09:43:35 +03:00
Atanas Korchev
dc6a7cf712 ColorPicker does not show alpha value. 2021-07-02 09:30:25 +03:00
Vladimir Enchev
795d6bdab6 Radzen.Blazor version updated 2021-07-01 19:27:38 +03:00
Vladimir Enchev
a2b41531a0 Version updated 2021-07-01 19:20:32 +03:00
Vladimir Enchev
6ed4301ba4 DataGrid DateTimeOffset filtering fixed 2021-07-01 19:20:12 +03:00
Vladimir Enchev
7abab63049 Radzen.Blazor updated 2021-07-01 08:35:31 +03:00
Vladimir Enchev
b29fdd841b Version updated 2021-07-01 08:33:51 +03:00
Vladimir Enchev
7e73f6f074 DataGrid date filtering fixed 2021-06-30 16:09:43 +03:00
Atanas Korchev
efc1efdfe1 Gauge demo correctly shows hours > 12. 2021-06-30 13:27:09 +03:00
Vladimir Enchev
11fdff952c DataGrid numeric column filter value not applied properly in some cases 2021-06-30 11:09:33 +03:00
Vladimir Enchev
14f90b66f2 DialogOptions AutoFocusFirstElement property added 2021-06-30 09:32:56 +03:00
Vladimir Enchev
a8d1676156 Radzen.Blazor updated 2021-06-28 10:39:15 +03:00
Vladimir Enchev
951f588a31 Version updated 2021-06-28 10:34:41 +03:00
Vladimir Enchev
7081627776 Reposition popup on filter
Fix #162
2021-06-28 10:18:16 +03:00
Vladimir Enchev
391576f080 Fixed DatePicker month selection will close calendar popup 2021-06-28 09:42:11 +03:00
Atanas Korchev
8cca3b9ef6 Setting style attribute in CellRender overrides the built-in style of a RadzenDataGrid cell. 2021-06-25 10:11:14 +03:00
Vladimir Enchev
47c5f14eda DataGrid cell z-index values lowered 2021-06-25 09:58:48 +03:00
Vladimir Enchev
a757b3b326 Focus first focusable element on dialog open
Fix #156
2021-06-24 10:56:19 +03:00
Vladimir Enchev
1e1475c0e9 Focused element lost after popup open
Fixed #155
2021-06-24 09:45:23 +03:00
Vladimir Enchev
fa68a17ea3 LoadDataArgs.Sorts is with incorrect order with multiple column sorting
Fix #158
2021-06-24 09:22:20 +03:00
Vladimir Enchev
dc1bb0e2c1 Radzen.Blazor updated 2021-06-23 10:16:14 +03:00
Vladimir Enchev
656cfb62ff Version updated 2021-06-23 10:13:26 +03:00
Vladimir Enchev
65b26a25ea DataGrid virtualization not working with horizontal scroll
Fix #151
2021-06-23 09:47:30 +03:00
Vladimir Enchev
6a03246234 DialogService.Close() method will not complete Task properly 2021-06-22 10:48:07 +03:00
Vladimir Enchev
53289b8616 Popup will be closed on any scroll 2021-06-22 09:30:07 +03:00
Vladimir Enchev
349eb433ce Tree CheckBoxes support added (#153) 2021-06-21 15:49:08 +03:00
marcelbednarczyk
9a98e0db24 Provide Style for Image (#152)
Please add developers way to style the image
2021-06-21 15:18:54 +03:00
Vladimir Enchev
b89e8baba0 Reverted https://github.com/radzenhq/radzen-blazor/pull/148
Maybe a property for hour format will be better.
2021-06-21 11:30:47 +03:00
dhuesmann89
773f276a78 Culture for time format in Hours.razor (#148)
Instead of using a hard coded "h tt" format, use the current user culture to format the time shown on the left hand side of the day and month view.
2021-06-21 11:20:07 +03:00
Marco Papst
1085923163 fix: RadzenNumeric unable to convert currency formatted values (#150) 2021-06-21 11:17:25 +03:00
Vladimir Enchev
6b3ffed3e4 Northwind Employees images updated 2021-06-18 17:03:49 +03:00
Vladimir Enchev
16a142c3c4 DataGrid will keep last page when items are removed 2021-06-18 10:01:57 +03:00
Atanas Korchev
2b660c4d45 Chart tooltip throws exception when series data changes. 2021-06-17 09:31:38 +03:00
Vladimir Enchev
6283987323 Paging demo updated 2021-06-17 08:19:09 +03:00
Vladimir Enchev
fd778b0fa8 Radzen.Blazor updated 2021-06-17 08:15:05 +03:00
Vladimir Enchev
8f03d92f5b Version updated 2021-06-17 08:08:58 +03:00
Vladimir Enchev
2ca624e9e2 Fixed DataGrid frozen column resize exception
Fix #137
2021-06-16 14:21:11 +03:00
Vladimir Enchev
514b00f7af Pager, DataGrid and DataList PageSizeOptions property added 2021-06-16 14:00:50 +03:00
Vladimir Enchev
05b7f6dbe9 DataGrid non template columns cells will display data as tooltip 2021-06-16 10:13:50 +03:00
Vladimir Enchev
d22eb9c85a Dialog fixed to work properly with DataGrid frozen columns 2021-06-16 09:47:30 +03:00
Vladimir Enchev
4bd60c04a5 DataGrid InEditMode fixed in .NET 3.1
Fix #142
2021-06-16 09:31:08 +03:00
Vladimir Enchev
f361e61ce9 Numeric Value will respect Min/Max change 2021-06-15 09:46:39 +03:00
Vladimir Enchev
1e5807c585 DataGrid frozen column footer cell z-index fixed 2021-06-15 09:13:56 +03:00
Vladimir Enchev
8239b130bf Radzen.Blazor updated 2021-06-14 09:20:38 +03:00
Vladimir Enchev
09acf97c8d Merge branch 'master' of https://github.com/radzenhq/radzen-blazor 2021-06-14 09:16:06 +03:00
Vladimir Enchev
6e72d0bb14 Version updated 2021-06-14 09:15:55 +03:00
Marco Papst
34c6659703 Feature/fieldset allow summarytemplate (#139)
* add optional SummaryTemplate to Fieldset and Panel

* add Demos for Summary of Panel and Fieldset

* Add Unit Tests that check for rendering of new SummaryTemplate
2021-06-14 08:52:43 +03:00
Vladimir Enchev
42a067a32a DropDown binding to simple collection demo added 2021-06-11 16:53:42 +03:00
Vladimir Enchev
f2a995ccdc DataGrid insert row not working properly with enabled virtualization 2021-06-11 12:22:00 +03:00
Vladimir Enchev
463f064919 Fixed DataGrid frozen columns not working properly with in-line edit 2021-06-11 11:36:38 +03:00
Vladimir Enchev
bec20e7e5d Legacy grid column sort order indicator with sub properties fixed 2021-06-11 10:23:11 +03:00
Vladimir Enchev
da18b35d68 DataGrid bool simple filter not aligned properly 2021-06-11 09:37:28 +03:00
Vladimir Enchev
842d7f453c Radzen.Blazor updated 2021-06-10 09:22:39 +03:00
Vladimir Enchev
74e63fd176 Version updated 2021-06-10 09:17:16 +03:00
Vladimir Enchev
c8ec229629 DataGrid sorting by sub property fixed 2021-06-10 09:16:21 +03:00
Atanas Korchev
d955e09268 Set the @ref of the RadzenDataGrid. 2021-06-09 21:00:24 +03:00
Vladimir Enchev
106dfd8d47 Login component AutoComplete property added 2021-06-09 14:16:57 +03:00
Vladimir Enchev
aa4ff53d62 Fixed "Cannot read property addEventListener of null" 2021-06-09 14:12:03 +03:00
Vladimir Enchev
2a9e9932f6 DataGrid border removed 2021-06-08 09:19:56 +03:00
Vladimir Enchev
df853d9867 Radzen.Blazor updated 2021-06-07 11:30:36 +03:00
Vladimir Enchev
bcd185e508 Version updated 2021-06-07 11:24:24 +03:00
Vladimir Enchev
2032c30a4d DatePicker time not updated properly on Ok click
Fix #109
2021-06-07 11:05:52 +03:00
Vladimir Enchev
2b8e217459 various warnings fixed 2021-06-07 09:27:25 +03:00
Vladimir Enchev
29948c246d Merge branch 'master' of https://github.com/radzenhq/radzen-blazor 2021-06-07 09:18:19 +03:00
Vladimir Enchev
901d0effe7 demo updated 2021-06-07 09:18:11 +03:00
Atanas Korchev
6a21f98d14 Day and week view overlaps events in some cases. 2021-06-07 09:13:48 +03:00
Atanas Korchev
6eb05ce9b4 Do not use JSRuntime before OnAfterRenderAsync. 2021-06-04 20:07:21 +03:00
Vladimir Enchev
cae3414ddb RenderMode renamed to TabRenderMode 2021-06-04 17:54:28 +03:00
Vladimir Enchev
3e067c9ea5 Merge branch 'master' of https://github.com/radzenhq/radzen-blazor 2021-06-04 16:16:35 +03:00
Vladimir Enchev
12316e8611 DataGrid sorting API fixed 2021-06-04 16:16:25 +03:00
Atanas Korchev
bf3370fad1 Do not use JSInterop before OnAfterRenderAsync. 2021-06-04 15:52:50 +03:00
Vladimir Enchev
2cb2868d47 Tabs component RenderMode property added 2021-06-04 09:12:51 +03:00
Vladimir Enchev
6ab33ba06c Radzen.Blazor updated 2021-06-03 21:01:18 +03:00
Vladimir Enchev
f826575567 Version updated 2021-06-03 20:57:27 +03:00
Vladimir Enchev
498879a235 DataGrid frozen columns data cells should have z-index: 0 2021-06-03 10:36:42 +03:00
Vladimir Enchev
0283c5204f Radzen.Blazor updated 2021-06-03 09:19:05 +03:00
Vladimir Enchev
5bb7fea3ca Fixed DropDownBase IQueryable support when virtualization is enabled 2021-06-03 09:13:33 +03:00
Vladimir Enchev
593f0e7a18 Radzen.Blazor updated 2021-06-03 08:30:21 +03:00
Vladimir Enchev
1158c43430 Version updated 2021-06-03 08:25:32 +03:00
Vladimir Enchev
041d53c434 DatePicker time update fixed
Fixed #118 and #105
2021-06-02 18:01:01 +03:00
Vladimir Enchev
1e60b41226 DatePicker hour update from numeric fixed 2021-06-02 14:40:17 +03:00
Vladimir Enchev
855d831c33 DataGrid edit row should cancel insert
Fixed #126
2021-06-02 13:31:39 +03:00
Vladimir Enchev
425efa412f Changing PageSize should reload data
Fixed #123
2021-06-02 13:21:31 +03:00
Vladimir Enchev
0b5a284ceb ListBox, DropDown and DropDownDataGrid virtualization support added (#127)
* DropDown and ListBox virtualization support added

* code improved

* Support for columns in virtual DropDownDataGrid

* Example of RadzenDropDownDataGrid with virtualization and LoadData fixed

* RadzenDropDownDataGrid now will use RadzenDataGrid instead RadzenGrid

* NET3.1 code fixed

* Virtualized DropDownDataGrid refresh on filter fixed

* DropDownDataGrid refresh on filter improved

* DropDown and ListBox refresh after filter with enabled virtualization fixed
2021-06-02 11:00:31 +03:00
Atanas Korchev
75f1e6e569 Cannot close nested dialogs in some cases. 2021-06-01 18:34:34 +03:00
Vladimir Enchev
0258316d21 DatePicker null ref. exception fixed when TimeOnly is set to true 2021-06-01 16:37:24 +03:00
Vladimir Enchev
b55cd42aaf DataGrid multi column sorting order fixed 2021-05-31 10:44:42 +03:00
Vladimir Enchev
8781a53f21 DataGrid equals and not equals string filters fixed 2021-05-31 09:58:46 +03:00
Vladimir Enchev
75a2b47abf DataGrid RowRender event not executed properly 2021-05-31 09:01:38 +03:00
Atanas Korchev
9b531f83a6 Increase the z index of the popup to 2000 to make it appear on top of Bootstrap modals. 2021-05-28 11:39:39 +03:00
114 changed files with 4363 additions and 808 deletions

View File

@@ -0,0 +1,47 @@
using Bunit;
using Xunit;
namespace Radzen.Blazor.Tests
{
public class BadgeTests
{
[Fact]
public void Badge_Renders_TextParameter()
{
using var ctx = new TestContext();
var component = ctx.RenderComponent<RadzenBadge>();
var text = "Test";
component.SetParametersAndRender(parameters => parameters.Add(p => p.Text, text));
Assert.Contains(text, component.Markup);
}
[Fact]
public void Badge_Renders_ChildContent()
{
using var ctx = new TestContext();
var component = ctx.RenderComponent<RadzenBadge>();
component.SetParametersAndRender(parameters => parameters.AddChildContent("SomeContent"));
Assert.Contains(@$"SomeContent", component.Markup);
}
[Fact]
public void Badge_Renders_BadgeStyle()
{
var badgeStyle = BadgeStyle.Danger;
using var ctx = new TestContext();
var component = ctx.RenderComponent<RadzenBadge>();
component.SetParametersAndRender(parameters => parameters.Add(p => p.BadgeStyle, badgeStyle));
Assert.Contains($"badge-{badgeStyle.ToString().ToLower()}", component.Markup);
}
}
}

View File

@@ -51,7 +51,7 @@ namespace Radzen.Blazor.Tests
Assert.DoesNotContain(@$"<i class=""rz-button-icon-left rzi"">{icon}</i>", component.Markup);
// renders the icon with busy spin animation
Assert.Contains(@"<i style=""animation: button-icon-spin", component.Markup);
Assert.Contains(@"<i style=""animation: rotation", component.Markup);
Assert.Contains(">refresh</i>", component.Markup);
}

View File

@@ -0,0 +1,98 @@
using System;
using System.Linq;
using Xunit;
namespace Radzen.Blazor.Tests
{
public class DataGridColumnTests
{
class TestModel
{
public Guid Id { get; set; }
public string Name { get; set; }
public int Age { get; set; }
}
class Testable : RadzenDataGridColumn<TestModel>
{
public Testable()
{
Grid = new RadzenDataGrid<TestModel>();
}
public void PublicMorozov_OnInitialized()
{
OnInitialized();
}
public Type PublicMorozov_FilterPropertyType()
{
var propertyInfo = this.GetType()
.GetProperties(System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance)
.FirstOrDefault(x => x.Name == "FilterPropertyType");
return propertyInfo?.GetValue(this) as Type;
}
}
[Fact]
public void FilterPropertyType_Assigned_From_Type_Parameter()
{
var column = new Testable()
{
Property = nameof(TestModel.Id),
Type = typeof(string),
FilterProperty = null
};
column.PublicMorozov_OnInitialized();
Assert.Equal(typeof(string), column.PublicMorozov_FilterPropertyType());
Assert.Equal(FilterOperator.Contains, column.FilterOperator);
}
[Fact]
public void FilterPropertyType_Assigned_From_FilterProperty_Parameter()
{
var column = new Testable()
{
Property = nameof(TestModel.Id),
Type = null,
FilterProperty = nameof(TestModel.Name)
};
column.PublicMorozov_OnInitialized();
Assert.Equal(typeof(string), column.PublicMorozov_FilterPropertyType());
Assert.Equal(FilterOperator.Contains, column.FilterOperator);
}
[Fact]
public void FilterPropertyType_Assigned_From_ColumnType()
{
var column = new Testable()
{
Property = nameof(TestModel.Id),
Type = null,
FilterProperty = null
};
column.PublicMorozov_OnInitialized();
Assert.Equal(typeof(Guid), column.PublicMorozov_FilterPropertyType());
Assert.Equal(FilterOperator.Equals, column.FilterOperator);
}
[Fact]
public void FilterPropertyType_Assigned_From_Type_If_FilterProperty_Is_Fake_Field()
{
var column = new Testable()
{
Property = nameof(TestModel.Id),
Type = typeof(decimal),
FilterProperty = "NotExistsField"
};
column.PublicMorozov_OnInitialized();
Assert.Equal(typeof(decimal), column.PublicMorozov_FilterPropertyType());
}
}
}

View File

@@ -2,9 +2,7 @@ using AngleSharp.Dom;
using Bunit;
using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.Components.Rendering;
using Radzen.Blazor.Rendering;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
@@ -22,9 +20,11 @@ namespace Radzen.Blazor.Tests
ctx.JSInterop.Mode = JSRuntimeMode.Loose;
ctx.JSInterop.SetupModule("_content/Radzen.Blazor/Radzen.Blazor.js");
var component = ctx.RenderComponent<RadzenGrid<dynamic>>(parameterBuilder => {
var component = ctx.RenderComponent<RadzenGrid<dynamic>>(parameterBuilder =>
{
parameterBuilder.Add<IEnumerable<dynamic>>(p => p.Data, new[] { new { Id = 1 }, new { Id = 2 }, new { Id = 3 } });
parameterBuilder.Add<RenderFragment>(p => p.Columns, builder => {
parameterBuilder.Add<RenderFragment>(p => p.Columns, builder =>
{
builder.OpenComponent(0, typeof(RadzenGridColumn<dynamic>));
builder.AddAttribute(1, "Property", "Id");
builder.CloseComponent();
@@ -63,9 +63,11 @@ namespace Radzen.Blazor.Tests
ctx.JSInterop.Mode = JSRuntimeMode.Loose;
ctx.JSInterop.SetupModule("_content/Radzen.Blazor/Radzen.Blazor.js");
var component = ctx.RenderComponent<RadzenGrid<dynamic>>(parameterBuilder => {
parameterBuilder.Add<IEnumerable<dynamic>>(p => p.Data, new[] { new { Id = 1}, new { Id = 2 }, new { Id = 3 } });
parameterBuilder.Add<RenderFragment>(p => p.Columns, builder => {
var component = ctx.RenderComponent<RadzenGrid<dynamic>>(parameterBuilder =>
{
parameterBuilder.Add<IEnumerable<dynamic>>(p => p.Data, new[] { new { Id = 1 }, new { Id = 2 }, new { Id = 3 } });
parameterBuilder.Add<RenderFragment>(p => p.Columns, builder =>
{
builder.OpenComponent(0, typeof(RadzenGridColumn<dynamic>));
builder.AddAttribute(1, "Property", "Id");
builder.CloseComponent();
@@ -86,9 +88,11 @@ namespace Radzen.Blazor.Tests
ctx.JSInterop.Mode = JSRuntimeMode.Loose;
ctx.JSInterop.SetupModule("_content/Radzen.Blazor/Radzen.Blazor.js");
var component = ctx.RenderComponent<RadzenGrid<dynamic>>(parameterBuilder => {
var component = ctx.RenderComponent<RadzenGrid<dynamic>>(parameterBuilder =>
{
parameterBuilder.Add<IEnumerable<dynamic>>(p => p.Data, new[] { new { Id = 1 }, new { Id = 2 }, new { Id = 3 } });
parameterBuilder.Add<RenderFragment>(p => p.Columns, builder => {
parameterBuilder.Add<RenderFragment>(p => p.Columns, builder =>
{
builder.OpenComponent(0, typeof(RadzenGridColumn<dynamic>));
builder.AddAttribute(1, "Title", "MyId");
builder.CloseComponent();
@@ -107,20 +111,23 @@ namespace Radzen.Blazor.Tests
ctx.JSInterop.Mode = JSRuntimeMode.Loose;
ctx.JSInterop.SetupModule("_content/Radzen.Blazor/Radzen.Blazor.js");
var component = ctx.RenderComponent<RadzenGrid<dynamic>>(parameterBuilder => {
var component = ctx.RenderComponent<RadzenGrid<dynamic>>(parameterBuilder =>
{
parameterBuilder.Add<IEnumerable<dynamic>>(p => p.Data, new[] { new { Id = 1 }, new { Id = 2 }, new { Id = 3 } });
parameterBuilder.Add<RenderFragment>(p => p.Columns, builder => {
parameterBuilder.Add<RenderFragment>(p => p.Columns, builder =>
{
builder.OpenComponent(0, typeof(RadzenGridColumn<dynamic>));
builder.AddAttribute(1, "Property", "Id");
builder.AddAttribute(2, "Title", "Id");
builder.CloseComponent();
});
parameterBuilder.Add<bool>(p => p.AllowSorting, true) ;
parameterBuilder.Add<bool>(p => p.AllowSorting, true);
});
Assert.Contains(@$"rz-sortable-column", component.Markup);
component.SetParametersAndRender(parameters => {
component.SetParametersAndRender(parameters =>
{
parameters.Add<bool>(p => p.AllowSorting, false);
});
@@ -134,9 +141,11 @@ namespace Radzen.Blazor.Tests
ctx.JSInterop.Mode = JSRuntimeMode.Loose;
ctx.JSInterop.SetupModule("_content/Radzen.Blazor/Radzen.Blazor.js");
var component = ctx.RenderComponent<RadzenGrid<dynamic>>(parameterBuilder => {
var component = ctx.RenderComponent<RadzenGrid<dynamic>>(parameterBuilder =>
{
parameterBuilder.Add<IEnumerable<dynamic>>(p => p.Data, new[] { new { Id = 1 }, new { Id = 2 }, new { Id = 3 } });
parameterBuilder.Add<RenderFragment>(p => p.Columns, builder => {
parameterBuilder.Add<RenderFragment>(p => p.Columns, builder =>
{
builder.OpenComponent(0, typeof(RadzenGridColumn<dynamic>));
builder.AddAttribute(1, "Property", "Id");
builder.AddAttribute(2, "Title", "Id");
@@ -156,9 +165,11 @@ namespace Radzen.Blazor.Tests
ctx.JSInterop.Mode = JSRuntimeMode.Loose;
ctx.JSInterop.SetupModule("_content/Radzen.Blazor/Radzen.Blazor.js");
var component = ctx.RenderComponent<RadzenGrid<dynamic>>(parameterBuilder => {
var component = ctx.RenderComponent<RadzenGrid<dynamic>>(parameterBuilder =>
{
parameterBuilder.Add<IEnumerable<dynamic>>(p => p.Data, new[] { new { Id = 1 }, new { Id = 2 }, new { Id = 3 } });
parameterBuilder.Add<RenderFragment>(p => p.Columns, builder => {
parameterBuilder.Add<RenderFragment>(p => p.Columns, builder =>
{
builder.OpenComponent(0, typeof(RadzenGridColumn<dynamic>));
builder.AddAttribute(1, "Property", "Id");
builder.AddAttribute(2, "Title", "Id");
@@ -169,7 +180,8 @@ namespace Radzen.Blazor.Tests
Assert.Contains(@$"rz-cell-filter", component.Markup);
component.SetParametersAndRender(parameters => {
component.SetParametersAndRender(parameters =>
{
parameters.Add<bool>(p => p.AllowFiltering, false);
});
@@ -183,9 +195,11 @@ namespace Radzen.Blazor.Tests
ctx.JSInterop.Mode = JSRuntimeMode.Loose;
ctx.JSInterop.SetupModule("_content/Radzen.Blazor/Radzen.Blazor.js");
var component = ctx.RenderComponent<RadzenGrid<dynamic>>(parameterBuilder => {
var component = ctx.RenderComponent<RadzenGrid<dynamic>>(parameterBuilder =>
{
parameterBuilder.Add<IEnumerable<dynamic>>(p => p.Data, new[] { new { Id = 1 }, new { Id = 2 }, new { Id = 3 } });
parameterBuilder.Add<RenderFragment>(p => p.Columns, builder => {
parameterBuilder.Add<RenderFragment>(p => p.Columns, builder =>
{
builder.OpenComponent(0, typeof(RadzenGridColumn<dynamic>));
builder.AddAttribute(1, "Property", "Id");
builder.AddAttribute(2, "Title", "Id");
@@ -205,9 +219,11 @@ namespace Radzen.Blazor.Tests
ctx.JSInterop.Mode = JSRuntimeMode.Loose;
ctx.JSInterop.SetupModule("_content/Radzen.Blazor/Radzen.Blazor.js");
var component = ctx.RenderComponent<RadzenGrid<dynamic>>(parameterBuilder => {
var component = ctx.RenderComponent<RadzenGrid<dynamic>>(parameterBuilder =>
{
parameterBuilder.Add<IEnumerable<dynamic>>(p => p.Data, new[] { new { Id = 1 }, new { Id = 2 }, new { Id = 3 } });
parameterBuilder.Add<RenderFragment>(p => p.Columns, builder => {
parameterBuilder.Add<RenderFragment>(p => p.Columns, builder =>
{
builder.OpenComponent(0, typeof(RadzenGridColumn<dynamic>));
builder.AddAttribute(1, "Property", "Id");
builder.AddAttribute(2, "Title", "Id");
@@ -219,7 +235,8 @@ namespace Radzen.Blazor.Tests
Assert.Contains(@$"rz-grid-filter", component.Markup);
component.SetParametersAndRender(parameters => {
component.SetParametersAndRender(parameters =>
{
parameters.Add<FilterMode>(p => p.FilterMode, FilterMode.Simple);
});
@@ -233,9 +250,11 @@ namespace Radzen.Blazor.Tests
ctx.JSInterop.Mode = JSRuntimeMode.Loose;
ctx.JSInterop.SetupModule("_content/Radzen.Blazor/Radzen.Blazor.js");
var component = ctx.RenderComponent<RadzenGrid<int>>(parameterBuilder => {
var component = ctx.RenderComponent<RadzenGrid<int>>(parameterBuilder =>
{
parameterBuilder.Add<IEnumerable<int>>(p => p.Data, new[] { 1, 2, 3 });
parameterBuilder.Add<RenderFragment>(p => p.Columns, builder => {
parameterBuilder.Add<RenderFragment>(p => p.Columns, builder =>
{
builder.OpenComponent(0, typeof(RadzenGridColumn<int>));
builder.AddAttribute(1, "HeaderTemplate", (RenderFragment)delegate (RenderTreeBuilder b)
@@ -257,9 +276,11 @@ namespace Radzen.Blazor.Tests
ctx.JSInterop.Mode = JSRuntimeMode.Loose;
ctx.JSInterop.SetupModule("_content/Radzen.Blazor/Radzen.Blazor.js");
var component = ctx.RenderComponent<RadzenGrid<int>>(parameterBuilder => {
var component = ctx.RenderComponent<RadzenGrid<int>>(parameterBuilder =>
{
parameterBuilder.Add<IEnumerable<int>>(p => p.Data, new[] { 1, 2, 3 });
parameterBuilder.Add<RenderFragment>(p => p.Columns, builder => {
parameterBuilder.Add<RenderFragment>(p => p.Columns, builder =>
{
builder.OpenComponent(0, typeof(RadzenGridColumn<int>));
builder.AddAttribute(1, "FooterTemplate", (RenderFragment)delegate (RenderTreeBuilder b)
@@ -284,9 +305,11 @@ namespace Radzen.Blazor.Tests
ctx.JSInterop.Mode = JSRuntimeMode.Loose;
ctx.JSInterop.SetupModule("_content/Radzen.Blazor/Radzen.Blazor.js");
var component = ctx.RenderComponent<RadzenGrid<dynamic>>(parameterBuilder => {
var component = ctx.RenderComponent<RadzenGrid<dynamic>>(parameterBuilder =>
{
parameterBuilder.Add<IEnumerable<dynamic>>(p => p.Data, Enumerable.Range(0, 100).Select(i => new { Id = i }));
parameterBuilder.Add<RenderFragment>(p => p.Columns, builder => {
parameterBuilder.Add<RenderFragment>(p => p.Columns, builder =>
{
builder.OpenComponent(0, typeof(RadzenGridColumn<dynamic>));
builder.AddAttribute(1, "Property", "Id");
builder.AddAttribute(2, "Title", "Id");
@@ -328,9 +351,10 @@ namespace Radzen.Blazor.Tests
var component = ctx.RenderComponent<RadzenGrid<int>>(parameterBuilder => parameterBuilder.Add<IEnumerable<int>>(p => p.Data, Enumerable.Range(0, 100)));
component.SetParametersAndRender(parameters => {
component.SetParametersAndRender(parameters =>
{
parameters.Add<bool>(p => p.AllowPaging, true);
parameters.Add<PagerPosition>(p => p.PagerPosition, PagerPosition.Top);
parameters.Add<PagerPosition>(p => p.PagerPosition, PagerPosition.Top);
});
Assert.Contains(@$"rz-paginator", component.Markup);
@@ -346,7 +370,8 @@ namespace Radzen.Blazor.Tests
var component = ctx.RenderComponent<RadzenGrid<int>>(parameterBuilder => parameterBuilder.Add<IEnumerable<int>>(p => p.Data, Enumerable.Range(0, 100)));
component.SetParametersAndRender(parameters => {
component.SetParametersAndRender(parameters =>
{
parameters.Add<bool>(p => p.AllowPaging, true);
parameters.Add<PagerPosition>(p => p.PagerPosition, PagerPosition.TopAndBottom);
});
@@ -355,6 +380,57 @@ namespace Radzen.Blazor.Tests
Assert.Contains(@$"rz-paginator-bottom", component.Markup);
}
[Fact]
public void DataGrid_Renders_DefaultEmptyText()
{
using var ctx = new TestContext();
ctx.JSInterop.Mode = JSRuntimeMode.Loose;
ctx.JSInterop.SetupModule("_content/Radzen.Blazor/Radzen.Blazor.js");
var component = ctx.RenderComponent<RadzenGrid<int>>(parameterBuilder => parameterBuilder.Add<IEnumerable<int>>(p => p.Data, Array.Empty<int>()));
component.Render();
Assert.Contains("No records to display.", component.Markup);
}
[Fact]
public void DataGrid_Renders_EmptyText()
{
string emptyText = "Lorem Ipsum";
using var ctx = new TestContext();
ctx.JSInterop.Mode = JSRuntimeMode.Loose;
ctx.JSInterop.SetupModule("_content/Radzen.Blazor/Radzen.Blazor.js");
var component = ctx.RenderComponent<RadzenGrid<int>>(parameterBuilder => parameterBuilder.Add<IEnumerable<int>>(p => p.Data, Array.Empty<int>()));
component.SetParametersAndRender(parameters =>
{
parameters.Add(p => p.EmptyText, emptyText);
});
Assert.Contains(emptyText, component.Markup);
}
[Fact]
public void DataGrid_Renders_EmptyTemplate()
{
using var ctx = new TestContext();
ctx.JSInterop.Mode = JSRuntimeMode.Loose;
ctx.JSInterop.SetupModule("_content/Radzen.Blazor/Radzen.Blazor.js");
var component = ctx.RenderComponent<RadzenGrid<int>>(parameterBuilder => parameterBuilder.Add<IEnumerable<int>>(p => p.Data, Array.Empty<int>()));
component.SetParametersAndRender(parameters =>
{
parameters.Add<RenderFragment>(p => p.EmptyTemplate, builder =>
{
builder.OpenElement(0, "p");
builder.AddContent(0, "Lorem Ipsum");
builder.CloseElement();
});
});
Assert.Contains("<p>Lorem Ipsum</p>", component.Markup);
}
[Fact]
public void DataGrid_Raises_LoadDataEventOnNextPageClick()
{
@@ -367,7 +443,8 @@ namespace Radzen.Blazor.Tests
var raised = false;
LoadDataArgs newArgs = null;
component.SetParametersAndRender(parameters => {
component.SetParametersAndRender(parameters =>
{
parameters.Add<bool>(p => p.AllowPaging, true);
parameters.Add<LoadDataArgs>(p => p.LoadData, args => { raised = true; newArgs = args; });
});
@@ -391,7 +468,8 @@ namespace Radzen.Blazor.Tests
var raised = false;
LoadDataArgs newArgs = null;
component.SetParametersAndRender(parameters => {
component.SetParametersAndRender(parameters =>
{
parameters.Add<bool>(p => p.AllowPaging, true);
parameters.Add<LoadDataArgs>(p => p.LoadData, args => { raised = true; newArgs = args; });
});
@@ -415,7 +493,8 @@ namespace Radzen.Blazor.Tests
var raised = false;
LoadDataArgs newArgs = null;
component.SetParametersAndRender(parameters => {
component.SetParametersAndRender(parameters =>
{
parameters.Add<bool>(p => p.AllowPaging, true);
parameters.Add<LoadDataArgs>(p => p.LoadData, args => { raised = true; newArgs = args; });
});
@@ -440,7 +519,8 @@ namespace Radzen.Blazor.Tests
var raised = false;
LoadDataArgs newArgs = null;
component.SetParametersAndRender(parameters => {
component.SetParametersAndRender(parameters =>
{
parameters.Add<bool>(p => p.AllowPaging, true);
parameters.Add<LoadDataArgs>(p => p.LoadData, args => { raised = true; newArgs = args; });
});
@@ -464,7 +544,8 @@ namespace Radzen.Blazor.Tests
var raised = false;
component.SetParametersAndRender(parameters => {
component.SetParametersAndRender(parameters =>
{
parameters.Add<bool>(p => p.AllowPaging, true);
parameters.Add<LoadDataArgs>(p => p.LoadData, args => { raised = true; });
});
@@ -485,7 +566,8 @@ namespace Radzen.Blazor.Tests
var raised = false;
component.SetParametersAndRender(parameters => {
component.SetParametersAndRender(parameters =>
{
parameters.Add<bool>(p => p.AllowPaging, true);
parameters.Add<LoadDataArgs>(p => p.LoadData, args => { raised = true; });
});
@@ -506,13 +588,15 @@ namespace Radzen.Blazor.Tests
var raised = false;
component.SetParametersAndRender(parameters => {
component.SetParametersAndRender(parameters =>
{
parameters.Add<bool>(p => p.AllowPaging, true);
});
component.Find(".rz-paginator-last").Click();
component.SetParametersAndRender(parameters => {
component.SetParametersAndRender(parameters =>
{
parameters.Add<LoadDataArgs>(p => p.LoadData, args => { raised = true; });
});
@@ -532,13 +616,15 @@ namespace Radzen.Blazor.Tests
var raised = false;
component.SetParametersAndRender(parameters => {
component.SetParametersAndRender(parameters =>
{
parameters.Add<bool>(p => p.AllowPaging, true);
});
component.Find(".rz-paginator-last").Click();
component.SetParametersAndRender(parameters => {
component.SetParametersAndRender(parameters =>
{
parameters.Add<LoadDataArgs>(p => p.LoadData, args => { raised = true; });
});
@@ -559,7 +645,8 @@ namespace Radzen.Blazor.Tests
var raised = false;
LoadDataArgs newArgs = null;
component.SetParametersAndRender(parameters => {
component.SetParametersAndRender(parameters =>
{
parameters.Add<bool>(p => p.AllowPaging, true);
parameters.Add<int>(p => p.PageSize, 20);
parameters.Add<LoadDataArgs>(p => p.LoadData, args => { raised = true; newArgs = args; });

View File

@@ -1,4 +1,6 @@
using Bunit;
using Microsoft.AspNetCore.Components;
using System.Linq;
using Xunit;
namespace Radzen.Blazor.Tests
@@ -145,7 +147,8 @@ namespace Radzen.Blazor.Tests
var raised = false;
component.SetParametersAndRender(parameters => {
component.SetParametersAndRender(parameters =>
{
parameters.Add<bool>(p => p.AllowCollapse, true);
parameters.Add(p => p.Collapse, args => { raised = true; });
});
@@ -160,5 +163,57 @@ namespace Radzen.Blazor.Tests
component.Find("a").Click();
}
[Fact]
public void Fieldset_Renders_SummaryWhenCollapsed()
{
using var ctx = new TestContext();
var component = ctx.RenderComponent<RadzenFieldset>();
component.SetParametersAndRender(parameters =>
{
parameters.Add<bool>(p => p.AllowCollapse, true);
parameters.Add<bool>(p => p.Collapsed, true);
parameters.Add<RenderFragment>(p => p.SummaryTemplate, builder =>
{
builder.OpenElement(0, "p");
builder.AddContent(0, "SummaryContent");
builder.CloseElement();
});
});
Assert.Contains("SummaryContent", component.Markup);
Assert.Equal(
"",
component.Find(".rz-fieldset-content-summary").ParentElement.Attributes.First(attr => attr.Name == "style").Value
);
}
[Fact]
public void Fieldset_DontRenders_SummaryWhenOpen()
{
using var ctx = new TestContext();
var component = ctx.RenderComponent<RadzenFieldset>();
component.SetParametersAndRender(parameters =>
{
parameters.Add<bool>(p => p.AllowCollapse, true);
parameters.Add<bool>(p => p.Collapsed, false);
parameters.Add<RenderFragment>(p => p.SummaryTemplate, builder =>
{
builder.OpenElement(0, "p");
builder.AddContent(0, "SummaryContent");
builder.CloseElement();
});
});
Assert.Contains("SummaryContent", component.Markup);
Assert.Equal(
"display: none",
component.Find(".rz-fieldset-content-summary").ParentElement.Attributes.First(attr => attr.Name == "style").Value
);
}
}
}

View File

@@ -36,7 +36,7 @@ namespace Radzen.Blazor.Tests
var component = ctx.RenderComponent<RadzenLogin>();
Assert.Contains(@$"<input name=""userName"" class=""rz-textbox""", component.Markup);
Assert.Contains(@$"<input name=""Username""", component.Markup);
}
[Fact]
@@ -89,30 +89,6 @@ namespace Radzen.Blazor.Tests
Assert.True(!clicked);
}
[Fact]
public void Login_Validates_UsernameParameter()
{
using var ctx = new TestContext();
var component = ctx.RenderComponent<RadzenLogin>();
component.Find("button").Click();
Assert.Contains(@$"Username is required", component.Markup);
}
[Fact]
public void Login_Validates_PasswordParameter()
{
using var ctx = new TestContext();
var component = ctx.RenderComponent<RadzenLogin>();
component.Find("button").Click();
Assert.Contains(@$"Password is required", component.Markup);
}
[Fact]
public void Login_Renders_LoginTextParameter()
{
@@ -214,7 +190,7 @@ namespace Radzen.Blazor.Tests
parameters.Add(p => p.Register, args => { clicked = true; });
});
component.Find(".btn-secondary").Click();
component.Find(".register > button").Click();
Assert.True(clicked);
}
@@ -257,17 +233,5 @@ namespace Radzen.Blazor.Tests
Assert.True(!clicked);
}
[Fact]
public void Login_Validates_UsernameParameter_OnResetPasswordEvent()
{
using var ctx = new TestContext();
var component = ctx.RenderComponent<RadzenLogin>();
component.Find("a").Click();
Assert.Contains(@$"Username is required", component.Markup);
}
}
}

View File

@@ -0,0 +1,57 @@
using Bunit;
using Bunit.JSInterop;
using System;
using System.Collections.Generic;
using Xunit;
namespace Radzen.Blazor.Tests
{
public class PagerTests
{
[Fact]
public void RadzenPager_AutoHide_If_Count_Is_Less_Than_PageSize()
{
using var ctx = new TestContext();
ctx.JSInterop.Mode = JSRuntimeMode.Loose;
ctx.JSInterop.SetupModule("_content/Radzen.Blazor/Radzen.Blazor.js");
var component = ctx.RenderComponent<RadzenPager>(parameters =>
{
parameters.Add<int>(p => p.PageSize, 20);
parameters.Add<int>(p => p.Count, 100);
});
component.Render();
Assert.Contains(@$"rz-paginator", component.Markup);
component.SetParametersAndRender(parameters =>
{
parameters.Add<int>(p => p.PageSize, 101);
parameters.Add<int>(p => p.Count, 100);
});
Assert.DoesNotContain(@$"rz-paginator", component.Markup);
}
[Fact]
public void RadzenPager_Dont_AutoHide_If_PageSizeOptions_Specified()
{
using var ctx = new TestContext();
ctx.JSInterop.Mode = JSRuntimeMode.Loose;
ctx.JSInterop.SetupModule("_content/Radzen.Blazor/Radzen.Blazor.js");
var component = ctx.RenderComponent<RadzenPager>(parameters =>
{
parameters.Add<int>(p => p.PageSize, 101);
parameters.Add<int>(p => p.Count, 100);
parameters.Add<IEnumerable<int>>(p => p.PageSizeOptions, new int[] { 3, 7, 15 });
});
component.Render();
Assert.Contains(@$"rz-paginator", component.Markup);
Assert.Contains(@$"rz-dropdown-trigger", component.Markup);
}
}
}

View File

@@ -1,4 +1,6 @@
using Bunit;
using Microsoft.AspNetCore.Components;
using System.Linq;
using Xunit;
namespace Radzen.Blazor.Tests
@@ -159,7 +161,8 @@ namespace Radzen.Blazor.Tests
var raised = false;
component.SetParametersAndRender(parameters => {
component.SetParametersAndRender(parameters =>
{
parameters.Add<bool>(p => p.AllowCollapse, true);
parameters.Add(p => p.Collapse, args => { raised = true; });
});
@@ -174,5 +177,57 @@ namespace Radzen.Blazor.Tests
component.Find("a").Click();
}
[Fact]
public void Panel_Renders_SummaryWhenCollapsed()
{
using var ctx = new TestContext();
var component = ctx.RenderComponent<RadzenPanel>();
component.SetParametersAndRender(parameters =>
{
parameters.Add<bool>(p => p.AllowCollapse, true);
parameters.Add<bool>(p => p.Collapsed, true);
parameters.Add<RenderFragment>(p => p.SummaryTemplate, builder =>
{
builder.OpenElement(0, "p");
builder.AddContent(0, "SummaryContent");
builder.CloseElement();
});
});
Assert.Contains("SummaryContent", component.Markup);
Assert.Equal(
"display: block",
component.Find(".rz-panel-content-summary").ParentElement.Attributes.First(attr => attr.Name == "style").Value
);
}
[Fact]
public void Panel_DontRenders_SummaryWhenOpen()
{
using var ctx = new TestContext();
var component = ctx.RenderComponent<RadzenPanel>();
component.SetParametersAndRender(parameters =>
{
parameters.Add<bool>(p => p.AllowCollapse, true);
parameters.Add<bool>(p => p.Collapsed, false);
parameters.Add<RenderFragment>(p => p.SummaryTemplate, builder =>
{
builder.OpenElement(0, "p");
builder.AddContent(0, "SummaryContent");
builder.CloseElement();
});
});
Assert.Contains("SummaryContent", component.Markup);
Assert.Equal(
"display: none",
component.Find(".rz-panel-content-summary").ParentElement.Attributes.First(attr => attr.Name == "style").Value
);
}
}
}

View File

@@ -250,6 +250,7 @@ namespace Radzen.Blazor
}
Chart.Refresh(false);
Chart.DisplayTooltip();
}
}

View File

@@ -1,16 +1,15 @@
using System;
using System.Collections;
using System.Collections.Generic;
using Microsoft.AspNetCore.Components;
using System.Linq.Dynamic.Core;
using System.Linq;
using System.Linq.Expressions;
using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.Components.Forms;
using Radzen.Blazor;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Dynamic.Core;
using System.Linq.Expressions;
using System.Text.Encodings.Web;
using System.Text.Json;
using System.Threading.Tasks;
using System.Text.Encodings.Web;
using System.Security.Cryptography.X509Certificates;
namespace Radzen
{
@@ -173,6 +172,12 @@ namespace Radzen
}
}
public enum TabRenderMode
{
Server,
Client
}
public enum PagerPosition
{
Top,
@@ -283,7 +288,8 @@ namespace Radzen
GreaterThanOrEquals,
Contains,
StartsWith,
EndsWith
EndsWith,
DoesNotContain
}
public enum TextAlign
@@ -293,14 +299,32 @@ namespace Radzen
Center
}
public enum BadgeStyle
{
Primary,
Secondary,
Light,
Success,
Danger,
Warning,
Info
}
public class DataGridColumnResizedEventArgs<T>
{
public RadzenDataGridColumn<T> Column { get; internal set; }
public double Width { get; internal set; }
}
public class DataGridColumnReorderedEventArgs<T>
{
public RadzenDataGridColumn<T> Column { get; internal set; }
public int OldIndex { get; internal set; }
public int NewIndex { get; internal set; }
}
public class ColumnResizedEventArgs<T>
{
{
public RadzenGridColumn<T> Column { get; internal set; }
public double Width { get; internal set; }
}
@@ -317,7 +341,25 @@ namespace Radzen
public class SortDescriptor
{
public string Property { get; set; }
public SortOrder SortOrder { get; set; }
public SortOrder? SortOrder { get; set; }
}
public class GroupDescriptor
{
public string Property { get; set; }
public string Title { get; set; }
public string GetTitle()
{
return !string.IsNullOrEmpty(Title) ? Title : Property;
}
}
public class Group
{
public GroupResult Data { get; set; }
public GroupDescriptor GroupDescriptor { get; set; }
public int Level { get; set; }
}
public class LoadDataArgs
@@ -462,6 +504,7 @@ namespace Radzen
public static bool IsDate(Type source)
{
if (source == null) return false;
var type = source.IsGenericType ? source.GetGenericArguments()[0] : source;
if (type == typeof(DateTime) || type == typeof(DateTimeOffset))
@@ -726,4 +769,16 @@ namespace Radzen
return false;
}
}
public class RadzenSplitterEventArgs
{
public int PaneIndex { get; set; }
public RadzenSplitterPane Pane { get; set; }
public bool Cancel { get; set; }
}
public class RadzenSplitterResizeEventArgs:RadzenSplitterEventArgs
{
public double NewSize { get; set; }
}
}

View File

@@ -92,35 +92,26 @@ namespace Radzen
ShowClose = options != null ? options.ShowClose : true,
ChildContent = options?.ChildContent,
Style = options != null ? options.Style : "",
AutoFocusFirstElement = options != null ? options.AutoFocusFirstElement : true
});
}
private object closingDialog = null;
public void Close(dynamic result = null)
{
if (closingDialog == null)
var dialog = dialogs.LastOrDefault();
if (dialog != null)
{
closingDialog = dialogs.LastOrDefault();
if (closingDialog != null)
{
OnClose?.Invoke(result);
dialogs.Remove(closingDialog);
}
var task = tasks.LastOrDefault();
if (task != null && task.Task != null && !task.Task.IsCompleted)
{
task.SetResult(result);
tasks.Remove(task);
}
OnClose?.Invoke(result);
dialogs.Remove(dialog);
}
}
internal void DidCloseDialog()
{
closingDialog = null;
var task = tasks.LastOrDefault();
if (task != null && task.Task != null && !task.Task.IsCompleted)
{
tasks.Remove(task);
task.SetResult(result);
}
}
public void Dispose()
@@ -186,6 +177,7 @@ namespace Radzen
public string Height { get; set; }
public string Style { get; set; }
public RenderFragment<DialogService> ChildContent { get; set; }
public bool AutoFocusFirstElement { get; set; } = true;
}
public class ConfirmOptions : DialogOptions

View File

@@ -6,6 +6,7 @@ using System.Linq.Dynamic.Core;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.Components.Rendering;
using Microsoft.JSInterop;
using Radzen.Blazor;
@@ -13,6 +14,84 @@ namespace Radzen
{
public class DropDownBase<T> : DataBoundFormComponent<T>
{
#if NET5
internal Microsoft.AspNetCore.Components.Web.Virtualization.Virtualize<object> virtualize;
private async ValueTask<Microsoft.AspNetCore.Components.Web.Virtualization.ItemsProviderResult<object>> LoadItems(Microsoft.AspNetCore.Components.Web.Virtualization.ItemsProviderRequest request)
{
var data = Data != null ? Data.Cast<object>() : Enumerable.Empty<object>();
var view = (LoadData.HasDelegate ? data : View).Cast<object>().AsQueryable();
var totalItemsCount = LoadData.HasDelegate ? Count : view.Count();
var top = Math.Min(request.Count, totalItemsCount - request.StartIndex);
if (LoadData.HasDelegate)
{
await LoadData.InvokeAsync(new Radzen.LoadDataArgs() { Skip = request.StartIndex, Top = top, Filter = await JSRuntime.InvokeAsync<string>("Radzen.getInputValue", search) });
}
return new Microsoft.AspNetCore.Components.Web.Virtualization.ItemsProviderResult<object>(LoadData.HasDelegate ? Data.Cast<object>() : view.Skip(request.StartIndex).Take(top), totalItemsCount);
}
[Parameter]
public int Count { get; set; }
[Parameter]
public bool AllowVirtualization { get; set; }
[Parameter]
public int PageSize { get; set; } = 5;
#endif
internal bool IsVirtualizationAllowed()
{
#if NET5
return AllowVirtualization;
#else
return false;
#endif
}
internal virtual RenderFragment RenderItems()
{
return new RenderFragment(builder =>
{
#if NET5
if (AllowVirtualization)
{
builder.OpenComponent(0, typeof(Microsoft.AspNetCore.Components.Web.Virtualization.Virtualize<object>));
builder.AddAttribute(1, "ItemsProvider", new Microsoft.AspNetCore.Components.Web.Virtualization.ItemsProviderDelegate<object>(LoadItems));
builder.AddAttribute(2, "ChildContent", (RenderFragment<object>)((context) =>
{
return (RenderFragment)((b) =>
{
RenderItem(b, context);
});
}));
builder.AddComponentReferenceCapture(7, c => { virtualize = (Microsoft.AspNetCore.Components.Web.Virtualization.Virtualize<object>)c; });
builder.CloseComponent();
}
else
{
foreach (var item in LoadData.HasDelegate ? Data : View)
{
RenderItem(builder, item);
}
}
#else
foreach (var item in LoadData.HasDelegate ? Data : View)
{
RenderItem(builder, item);
}
#endif
});
}
internal virtual void RenderItem(RenderTreeBuilder builder, object item)
{
//
}
[Parameter]
public virtual bool AllowFiltering { get; set; }
@@ -189,7 +268,7 @@ namespace Radzen
if (Disabled)
return;
var items = (LoadData.HasDelegate ? Data != null ? Data : Enumerable.Empty<object>() : (View != null ? View : Enumerable.Empty<object>())).OfType<object>();
var items = (LoadData.HasDelegate ? Data != null ? Data : Enumerable.Empty<object>() : (View != null ? View : Enumerable.Empty<object>())).Cast<object>();
var key = args.Code != null ? args.Code : args.Key;
@@ -240,6 +319,11 @@ namespace Radzen
selectedIndex = -1;
await OnSelectItem(null, true);
}
if (AllowFiltering && isFilter)
{
Debounce(DebounceFilter, FilterDelay);
}
}
else if(AllowFiltering && isFilter)
{
@@ -258,12 +342,40 @@ namespace Radzen
{
searchText = await JSRuntime.InvokeAsync<string>("Radzen.getInputValue", search);
_view = null;
await InvokeAsync(() => { StateHasChanged(); });
if (IsVirtualizationAllowed())
{
#if NET5
if (virtualize != null)
{
await virtualize.RefreshDataAsync();
}
await InvokeAsync(() => { StateHasChanged(); });
#endif
}
else
{
await InvokeAsync(() => { StateHasChanged(); });
}
}
else
{
await LoadData.InvokeAsync(new Radzen.LoadDataArgs() { Filter = await JSRuntime.InvokeAsync<string>("Radzen.getInputValue", search) });
if (IsVirtualizationAllowed())
{
#if NET5
if (virtualize != null)
{
await InvokeAsync(virtualize.RefreshDataAsync);
}
await InvokeAsync(() => { StateHasChanged(); });
#endif
}
else
{
await LoadData.InvokeAsync(await GetLoadDataArgs());
}
}
await JSRuntime.InvokeAsync<string>("Radzen.repositionPopup", Element, PopupID);
}
protected async System.Threading.Tasks.Task OnKeyPress(Microsoft.AspNetCore.Components.Web.KeyboardEventArgs args)
@@ -278,16 +390,23 @@ namespace Radzen
protected virtual async System.Threading.Tasks.Task OnFilter(ChangeEventArgs args)
{
if (!LoadData.HasDelegate)
await DebounceFilter();
}
internal virtual async System.Threading.Tasks.Task<LoadDataArgs> GetLoadDataArgs()
{
#if NET5
if (AllowVirtualization)
{
searchText = await JSRuntime.InvokeAsync<string>("Radzen.getInputValue", search);
_view = null;
StateHasChanged();
return new Radzen.LoadDataArgs() { Skip = 0, Top = PageSize, Filter = await JSRuntime.InvokeAsync<string>("Radzen.getInputValue", search) };
}
else
{
await LoadData.InvokeAsync(new Radzen.LoadDataArgs() { Filter = await JSRuntime.InvokeAsync<string>("Radzen.getInputValue", search) });
return new Radzen.LoadDataArgs() { Filter = await JSRuntime.InvokeAsync<string>("Radzen.getInputValue", search) };
}
#else
return new Radzen.LoadDataArgs() { Filter = await JSRuntime.InvokeAsync<string>("Radzen.getInputValue", search) };
#endif
}
private bool firstRender = true;
@@ -301,6 +420,13 @@ namespace Radzen
public override async Task SetParametersAsync(ParameterView parameters)
{
#if NET5
var pageSize = parameters.GetValueOrDefault<int>(nameof(PageSize));
if(pageSize != default(int))
{
PageSize = pageSize;
}
#endif
var shouldClose = false;
if (parameters.DidParameterChange(nameof(Visible), Visible))
@@ -339,7 +465,7 @@ namespace Radzen
Value = args.Value;
}
protected bool isSelected(object item)
internal bool isSelected(object item)
{
if (Multiple)
{
@@ -372,7 +498,55 @@ namespace Radzen
{
get
{
return (LoadData.HasDelegate ? Data != null ? Data : Enumerable.Empty<object>() : (View != null ? View : Enumerable.Empty<object>())).OfType<object>();
return (LoadData.HasDelegate ? Data != null ? Data : Enumerable.Empty<object>() : (View != null ? View : Enumerable.Empty<object>())).Cast<object>();
}
}
protected override IEnumerable View
{
get
{
if (_view == null && Query != null)
{
if (!string.IsNullOrEmpty(searchText))
{
var ignoreCase = FilterCaseSensitivity == FilterCaseSensitivity.CaseInsensitive;
var query = new List<string>();
if (!string.IsNullOrEmpty(TextProperty))
{
query.Add(TextProperty);
}
if (typeof(EnumerableQuery).IsAssignableFrom(Query.GetType()))
{
query.Add("ToString()");
}
if (ignoreCase)
{
query.Add("ToLower()");
}
query.Add($"{Enum.GetName(typeof(StringFilterOperator), FilterOperator)}(@0)");
_view = Query.Where(String.Join(".", query), ignoreCase ? searchText.ToLower() : searchText);
}
else
{
if (IsVirtualizationAllowed())
{
_view = Query;
}
else
{
_view = (typeof(IQueryable).IsAssignableFrom(Data.GetType())) ? Query.Cast<object>().ToList().AsQueryable() : Query;
}
}
}
return _view;
}
}
@@ -380,10 +554,13 @@ namespace Radzen
{
if (selectedItem != null)
{
var result = Items.Select((x, i) => new { Item = x, Index = i }).FirstOrDefault(itemWithIndex => object.Equals(itemWithIndex.Item, selectedItem));
if (result != null)
if (typeof(EnumerableQuery).IsAssignableFrom(View.GetType()))
{
selectedIndex = result.Index;
var result = Items.Select((x, i) => new { Item = x, Index = i }).FirstOrDefault(itemWithIndex => object.Equals(itemWithIndex.Item, selectedItem));
if (result != null)
{
selectedIndex = result.Index;
}
}
}
else
@@ -392,6 +569,11 @@ namespace Radzen
}
}
internal async System.Threading.Tasks.Task SelectItemInternal(object item, bool raiseChange = true)
{
await SelectItem(item, raiseChange);
}
protected async System.Threading.Tasks.Task SelectItem(object item, bool raiseChange = true)
{
if (!Multiple)
@@ -498,7 +680,7 @@ namespace Radzen
item = View.AsQueryable().Where($@"{ValueProperty} == @0", v).FirstOrDefault();
}
if (item != null && selectedItems.IndexOf(item) == -1)
if (!object.Equals(item, null) && selectedItems.IndexOf(item) == -1)
{
selectedItems.Add(item);
}

View File

@@ -49,6 +49,9 @@ namespace Radzen
}
}
[Parameter]
public IEnumerable<int> PageSizeOptions { get; set; }
protected IQueryable<T> _view = null;
public virtual IQueryable<T> PagedView
{
@@ -56,7 +59,7 @@ namespace Radzen
{
if (_view == null)
{
_view = (AllowPaging ? View.Skip(skip).Take(PageSize) : View).ToList().AsQueryable();
_view = (AllowPaging && !LoadData.HasDelegate ? View.Skip(skip).Take(PageSize) : View).ToList().AsQueryable();
}
return _view;
}
@@ -97,6 +100,18 @@ namespace Radzen
}
public override async Task SetParametersAsync(ParameterView parameters)
{
bool pageSizeChanged = parameters.DidParameterChange(nameof(PageSize), PageSize);
await base.SetParametersAsync(parameters);
if (pageSizeChanged && !firstRender)
{
await InvokeAsync(Reload);
}
}
protected override Task OnParametersSetAsync()
{
if (Visible && !LoadData.HasDelegate)
@@ -111,8 +126,10 @@ namespace Radzen
return base.OnParametersSetAsync();
}
bool firstRender = true;
protected override Task OnAfterRenderAsync(bool firstRender)
{
this.firstRender = firstRender;
if (firstRender && Visible && (LoadData.HasDelegate && Data == null))
{
InvokeAsync(Reload);
@@ -134,15 +151,23 @@ namespace Radzen
await InvokeAsync(Reload);
}
protected async Task OnPageSizeChanged(int value)
{
PageSize = value;
await InvokeAsync(Reload);
}
protected void CalculatePager()
{
if (topPager != null)
{
bottomPager.SetCount(Count);
topPager.SetCurrentPage(CurrentPage);
}
if (bottomPager != null)
{
bottomPager.SetCount(Count);
bottomPager.SetCurrentPage(CurrentPage);
}
}

View File

@@ -19,7 +19,8 @@ namespace Radzen
{"ge", ">="},
{"startswith", "StartsWith"},
{"endswith", "EndsWith"},
{"contains", "Contains"}
{"contains", "Contains"},
{"DoesNotContain", "Contains"}
};
internal static readonly IDictionary<FilterOperator, string> LinqFilterOperators = new Dictionary<FilterOperator, string>
@@ -32,7 +33,8 @@ namespace Radzen
{FilterOperator.GreaterThanOrEquals, ">="},
{FilterOperator.StartsWith, "StartsWith"},
{FilterOperator.EndsWith, "EndsWith"},
{FilterOperator.Contains, "Contains"}
{FilterOperator.Contains, "Contains"},
{FilterOperator.DoesNotContain, "DoesNotContain"}
};
internal static readonly IDictionary<FilterOperator, string> ODataFilterOperators = new Dictionary<FilterOperator, string>
@@ -45,7 +47,8 @@ namespace Radzen
{FilterOperator.GreaterThanOrEquals, "ge"},
{FilterOperator.StartsWith, "startswith"},
{FilterOperator.EndsWith, "endswith"},
{FilterOperator.Contains, "contains"}
{FilterOperator.Contains, "contains"},
{FilterOperator.DoesNotContain, "DoesNotContain"}
};
public static IList ToList(IQueryable query)
@@ -114,8 +117,27 @@ namespace Radzen
var whereList = new List<string>();
foreach (var column in columns.Where(canFilter))
{
var value = (string)Convert.ChangeType(column.GetFilterValue(), typeof(string));
var secondValue = (string)Convert.ChangeType(column.GetSecondFilterValue(), typeof(string));
string value = "";
string secondValue = "";
if (PropertyAccess.IsDate(column.FilterPropertyType))
{
var v = column.GetFilterValue();
var sv = column.GetSecondFilterValue();
if (v != null)
{
value = v is DateTime ? ((DateTime)v).ToString("yyyy-MM-ddTHH:mm:ss.fffZ") : v is DateTimeOffset ? ((DateTimeOffset)v).UtcDateTime.ToString("yyyy-MM-ddTHH:mm:ss.fffZ") : "";
}
if (sv != null)
{
secondValue = sv is DateTime ? ((DateTime)sv).ToString("yyyy-MM-ddTHH:mm:ss.fffZ") : sv is DateTimeOffset ? ((DateTimeOffset)sv).UtcDateTime.ToString("yyyy-MM-ddTHH:mm:ss.fffZ") : "";
}
}
else
{
value = (string)Convert.ChangeType(column.GetFilterValue(), typeof(string));
secondValue = (string)Convert.ChangeType(column.GetSecondFilterValue(), typeof(string));
}
if (!string.IsNullOrEmpty(value))
{
@@ -129,11 +151,11 @@ namespace Radzen
if (string.IsNullOrEmpty(secondValue))
{
whereList.Add(GetColumnFilter(column));
whereList.Add(GetColumnFilter(column, value));
}
else
{
whereList.Add($"({GetColumnFilter(column)} {booleanOperator} {GetColumnFilter(column, true)})");
whereList.Add($"({GetColumnFilter(column, value)} {booleanOperator} {GetColumnFilter(column, secondValue, true)})");
}
}
}
@@ -196,6 +218,10 @@ namespace Radzen
{
return $@"({property} == null ? """" : {property}){filterCaseSensitivityOperator}.Contains(""{value}""{filterCaseSensitivityOperator})";
}
else if (!string.IsNullOrEmpty(value) && columnFilterOperator == "DoesNotContain")
{
return $@"({property} == null ? """" : !{property}){filterCaseSensitivityOperator}.Contains(""{value}""{filterCaseSensitivityOperator})";
}
else if (!string.IsNullOrEmpty(value) && columnFilterOperator == "startswith")
{
return $@"({property} == null ? """" : {property}){filterCaseSensitivityOperator}.StartsWith(""{value}""{filterCaseSensitivityOperator})";
@@ -206,7 +232,11 @@ namespace Radzen
}
else if (!string.IsNullOrEmpty(value) && columnFilterOperator == "eq")
{
return $@"{property} == null ? """" : {property}{filterCaseSensitivityOperator} == {value}{filterCaseSensitivityOperator}";
return $@"({property} == null ? """" : {property}){filterCaseSensitivityOperator} == ""{value}""{filterCaseSensitivityOperator}";
}
else if (!string.IsNullOrEmpty(value) && columnFilterOperator == "ne")
{
return $@"({property} == null ? """" : {property}){filterCaseSensitivityOperator} != ""{value}""{filterCaseSensitivityOperator}";
}
}
else if (columnType == "number" || columnType == "integer")
@@ -221,7 +251,7 @@ namespace Radzen
return "";
}
private static string GetColumnFilter<T>(RadzenDataGridColumn<T> column, bool second = false)
private static string GetColumnFilter<T>(RadzenDataGridColumn<T> column, string value, bool second = false)
{
var property = PropertyAccess.GetProperty(column.GetFilterProperty());
@@ -230,11 +260,6 @@ namespace Radzen
property = $"({property})";
}
if (column.FilterPropertyType == typeof(string))
{
property = $@"({property} == null ? """" : {property})";
}
var columnFilterOperator = !second ? column.GetFilterOperator() : column.GetSecondFilterOperator();
var linqOperator = LinqFilterOperators[columnFilterOperator];
@@ -243,9 +268,6 @@ namespace Radzen
linqOperator = "==";
}
var value = !second ? (string)Convert.ChangeType(column.GetFilterValue(), typeof(string)) :
(string)Convert.ChangeType(column.GetSecondFilterValue(), typeof(string));
if (column.FilterPropertyType == typeof(string))
{
string filterCaseSensitivityOperator = column.Grid.FilterCaseSensitivity == FilterCaseSensitivity.CaseInsensitive ? ".ToLower()" : "";
@@ -254,6 +276,10 @@ namespace Radzen
{
return $@"({property} == null ? """" : {property}){filterCaseSensitivityOperator}.Contains(""{value}""{filterCaseSensitivityOperator})";
}
else if (!string.IsNullOrEmpty(value) && columnFilterOperator == FilterOperator.DoesNotContain)
{
return $@"!({property} == null ? """" : {property}){filterCaseSensitivityOperator}.Contains(""{value}""{filterCaseSensitivityOperator})";
}
else if (!string.IsNullOrEmpty(value) && columnFilterOperator == FilterOperator.StartsWith)
{
return $@"({property} == null ? """" : {property}){filterCaseSensitivityOperator}.StartsWith(""{value}""{filterCaseSensitivityOperator})";
@@ -264,7 +290,11 @@ namespace Radzen
}
else if (!string.IsNullOrEmpty(value) && columnFilterOperator == FilterOperator.Equals)
{
return $@"{property} == null ? """" : {property}{filterCaseSensitivityOperator} == {value}{filterCaseSensitivityOperator}";
return $@"({property} == null ? """" : {property}){filterCaseSensitivityOperator} == ""{value}""{filterCaseSensitivityOperator}";
}
else if (!string.IsNullOrEmpty(value) && columnFilterOperator == FilterOperator.NotEquals)
{
return $@"({property} == null ? """" : {property}){filterCaseSensitivityOperator} != ""{value}""{filterCaseSensitivityOperator}";
}
}
else if (PropertyAccess.IsNumeric(column.FilterPropertyType))
@@ -279,8 +309,9 @@ namespace Radzen
var dateTimeValue = DateTime.Parse(value, null, System.Globalization.DateTimeStyles.RoundtripKind);
var finalDate = dateTimeValue.TimeOfDay == TimeSpan.Zero ? dateTimeValue.Date : dateTimeValue;
var dateFormat = dateTimeValue.TimeOfDay == TimeSpan.Zero ? "yyyy-MM-dd" : "yyyy-MM-ddTHH:mm:ssZ";
var dateFunction = column.FilterPropertyType == typeof(DateTimeOffset) || column.FilterPropertyType == typeof(DateTimeOffset?) ? "DateTimeOffset" : "DateTime";
return $@"{property} {linqOperator} DateTime(""{finalDate.ToString(dateFormat)}"")";
return $@"{property} {linqOperator} {dateFunction}(""{finalDate.ToString(dateFormat)}"")";
}
else if (column.FilterPropertyType == typeof(bool) || column.FilterPropertyType == typeof(bool?))
{
@@ -331,6 +362,12 @@ namespace Radzen
$"contains({property}, tolower('{value}'))" :
$"contains({property}, '{value}')";
}
else if (!string.IsNullOrEmpty(value) && columnFilterOperator == "DoesNotContain")
{
return column.Grid.FilterCaseSensitivity == FilterCaseSensitivity.CaseInsensitive ?
$"not(contains({property}, tolower('{value}')))" :
$"not(contains({property}, '{value}'))";
}
else if (!string.IsNullOrEmpty(value) && columnFilterOperator == "startswith")
{
return column.Grid.FilterCaseSensitivity == FilterCaseSensitivity.CaseInsensitive ?
@@ -345,7 +382,15 @@ namespace Radzen
}
else if (!string.IsNullOrEmpty(value) && columnFilterOperator == "eq")
{
return $"{property} eq {value}";
return column.Grid.FilterCaseSensitivity == FilterCaseSensitivity.CaseInsensitive ?
$"{property} eq tolower('{value}')" :
$"{property} eq '{value}'";
}
else if (!string.IsNullOrEmpty(value) && columnFilterOperator == "ne")
{
return column.Grid.FilterCaseSensitivity == FilterCaseSensitivity.CaseInsensitive ?
$"{property} ne tolower('{value}')" :
$"{property} ne '{value}'";
}
}
else if (columnType == "number" || columnType == "integer")
@@ -382,6 +427,12 @@ namespace Radzen
$"contains({property}, tolower('{value}'))" :
$"contains({property}, '{value}')";
}
else if (!string.IsNullOrEmpty(value) && columnFilterOperator == FilterOperator.DoesNotContain)
{
return column.Grid.FilterCaseSensitivity == FilterCaseSensitivity.CaseInsensitive ?
$"not(contains({property}, tolower('{value}')))" :
$"not(contains({property}, '{value}'))";
}
else if (!string.IsNullOrEmpty(value) && columnFilterOperator == FilterOperator.StartsWith)
{
return column.Grid.FilterCaseSensitivity == FilterCaseSensitivity.CaseInsensitive ?
@@ -396,7 +447,15 @@ namespace Radzen
}
else if (!string.IsNullOrEmpty(value) && columnFilterOperator == FilterOperator.Equals)
{
return $"{property} eq {value}";
return column.Grid.FilterCaseSensitivity == FilterCaseSensitivity.CaseInsensitive ?
$"{property} eq tolower('{value}')" :
$"{property} eq '{value}'";
}
else if (!string.IsNullOrEmpty(value) && columnFilterOperator == FilterOperator.NotEquals)
{
return column.Grid.FilterCaseSensitivity == FilterCaseSensitivity.CaseInsensitive ?
$"{property} ne tolower('{value}')" :
$"{property} ne '{value}'";
}
}
else if (PropertyAccess.IsNumeric(column.FilterPropertyType))
@@ -555,6 +614,11 @@ namespace Radzen
whereList.Add($@"{property}{filterCaseSensitivityOperator}.{comparison}(@{index}{filterCaseSensitivityOperator})", new object[] { column.FilterValue });
index++;
}
else if (comparison == "DoesNotContain")
{
whereList.Add($@"!{property}{filterCaseSensitivityOperator}.Contains(@{index}{filterCaseSensitivityOperator})", new object[] { column.FilterValue });
index++;
}
else
{
whereList.Add($@"{property}{filterCaseSensitivityOperator} {comparison} @{index}{filterCaseSensitivityOperator}", new object[] { column.FilterValue });
@@ -565,12 +629,14 @@ namespace Radzen
{
var firstFilter = comparison == "StartsWith" || comparison == "EndsWith" || comparison == "Contains" ?
$@"{property}{filterCaseSensitivityOperator}.{comparison}(@{index}{filterCaseSensitivityOperator})" :
comparison == "DoesNotContain" ? $@"!{property}{filterCaseSensitivityOperator}.Contains(@{index}{filterCaseSensitivityOperator})" :
$@"{property}{filterCaseSensitivityOperator} {comparison} @{index}{filterCaseSensitivityOperator}";
index++;
var secondComparison = FilterOperators[column.SecondFilterOperator];
var secondFilter = secondComparison == "StartsWith" || secondComparison == "EndsWith" || secondComparison == "Contains" ?
$@"{property}{filterCaseSensitivityOperator}.{secondComparison}(@{index}{filterCaseSensitivityOperator})" :
secondComparison == "DoesNotContain" ? $@"!{property}{filterCaseSensitivityOperator}.Contains(@{index}{filterCaseSensitivityOperator})" :
$@"{property}{filterCaseSensitivityOperator} {secondComparison} @{index}{filterCaseSensitivityOperator}";
index++;
@@ -624,6 +690,11 @@ namespace Radzen
whereList.Add($@"{property}{filterCaseSensitivityOperator}.{comparison}(@{index}{filterCaseSensitivityOperator})", new object[] { column.GetFilterValue() });
index++;
}
else if (comparison == "DoesNotContain")
{
whereList.Add($@"!{property}{filterCaseSensitivityOperator}.Contains(@{index}{filterCaseSensitivityOperator})", new object[] { column.GetFilterValue() });
index++;
}
else
{
whereList.Add($@"{property}{filterCaseSensitivityOperator} {comparison} @{index}{filterCaseSensitivityOperator}", new object[] { column.GetFilterValue() });
@@ -634,12 +705,14 @@ namespace Radzen
{
var firstFilter = comparison == "StartsWith" || comparison == "EndsWith" || comparison == "Contains" ?
$@"{property}{filterCaseSensitivityOperator}.{comparison}(@{index}{filterCaseSensitivityOperator})" :
comparison == "DoesNotContain" ? $@"!{property}{filterCaseSensitivityOperator}.Contains(@{index}{filterCaseSensitivityOperator})" :
$@"{property}{filterCaseSensitivityOperator} {comparison} @{index}{filterCaseSensitivityOperator}";
index++;
var secondComparison = LinqFilterOperators[column.GetSecondFilterOperator()];
var secondFilter = secondComparison == "StartsWith" || secondComparison == "EndsWith" || secondComparison == "Contains" ?
$@"{property}{filterCaseSensitivityOperator}.{secondComparison}(@{index}{filterCaseSensitivityOperator})" :
secondComparison == "DoesNotContain" ? $@"!{property}{filterCaseSensitivityOperator}.Contains(@{index}{filterCaseSensitivityOperator})" :
$@"{property}{filterCaseSensitivityOperator} {secondComparison} @{index}{filterCaseSensitivityOperator}";
index++;
@@ -657,5 +730,15 @@ namespace Radzen
{
return new ODataEnumerable<T>(source);
}
public static IEnumerable<T> SelectManyRecursive<T>(this IEnumerable<T> source, Func<T, IEnumerable<T>> selector)
{
var result = source.SelectMany(selector);
if (!result.Any())
{
return result;
}
return result.Concat(result.SelectManyRecursive(selector));
}
}
}

View File

@@ -8,7 +8,7 @@
<IsPackable>true</IsPackable>
<PackageId>Radzen.Blazor</PackageId>
<Product>Radzen.Blazor</Product>
<Version>3.3.2</Version>
<Version>3.9.4</Version>
<Copyright>Radzen Ltd.</Copyright>
<Authors>Radzen Ltd.</Authors>
<Description>Native Blazor UI components by Radzen Ltd.</Description>

View File

@@ -191,7 +191,10 @@
{
base.Dispose();
JSRuntime.InvokeVoidAsync("Radzen.destroyPopup", PopupID);
if (IsJSRuntimeAvailable)
{
JSRuntime.InvokeVoidAsync("Radzen.destroyPopup", PopupID);
}
}
private bool firstRender = true;

View File

@@ -0,0 +1,42 @@
@inherits RadzenComponent
@if (Visible)
{
<span @ref="@Element" style="@Style" @attributes="Attributes" class="@GetCssClass()" id="@GetId()">
@if (ChildContent != null)
{
@ChildContent
}
else
{
@Text
}
</span>
}
@code {
protected override string GetComponentCssClass()
{
var classList = new List<string>();
classList.Add("rz-badge");
classList.Add($"rz-badge-{BadgeStyle.ToString().ToLower()}");
if (IsPill)
{
classList.Add("rz-badge-pill");
}
return string.Join(" ", classList);
}
[Parameter]
public RenderFragment ChildContent { get; set; }
[Parameter]
public string Text { get; set; }
[Parameter]
public BadgeStyle BadgeStyle { get; set; }
[Parameter]
public bool IsPill { get; set; }
}

View File

@@ -245,17 +245,27 @@
RenderFragment tooltip;
object tooltipData;
double mouseX;
double mouseY;
[JSInvokable]
public void MouseMove(double x, double y)
{
mouseX = x;
mouseY = y;
DisplayTooltip();
}
internal void DisplayTooltip()
{
if (Tooltip.Visible)
{
foreach (var series in Series)
{
if (series.Visible && series.Contains(x - MarginLeft, y - MarginTop))
if (series.Visible && series.Contains(mouseX - MarginLeft, mouseY - MarginTop))
{
var data = series.DataAt(x - MarginLeft, y - MarginTop);
var data = series.DataAt(mouseX - MarginLeft, mouseY - MarginTop);
if (data != tooltipData)
{
@@ -301,6 +311,8 @@
protected override async Task OnAfterRenderAsync(bool firstRender)
{
await base.OnAfterRenderAsync(firstRender);
this.firstRender = firstRender;
if (firstRender || visibleChanged)
@@ -417,7 +429,7 @@
{
base.Dispose();
if (Visible)
if (Visible && IsJSRuntimeAvailable)
{
JSRuntime.InvokeVoidAsync("Radzen.destroyChart", Element);
}

View File

@@ -420,8 +420,12 @@
SaturationHandleTop = 1 - HSV.Value;
HSV.Saturation = 1;
HSV.Value = 1;
HueHandleLeft = HSV.Hue;
if (value.StartsWith("rgba"))
{
AlphaHandleLeft = HSV.Alpha;
}
}
}

View File

@@ -79,6 +79,8 @@ namespace Radzen
[Inject]
protected IJSRuntime JSRuntime { get; set; }
protected bool IsJSRuntimeAvailable { get; set; }
protected override void OnInitialized()
{
@@ -120,6 +122,8 @@ namespace Radzen
protected override async Task OnAfterRenderAsync(bool firstRender)
{
IsJSRuntimeAvailable = true;
this.firstRender = firstRender;
if (firstRender || visibleChanged)
@@ -178,19 +182,22 @@ namespace Radzen
reference?.Dispose();
reference = null;
if (ContextMenu.HasDelegate)
if (IsJSRuntimeAvailable)
{
JSRuntime.InvokeVoidAsync("Radzen.removeContextMenu", UniqueID);
}
if (ContextMenu.HasDelegate)
{
JSRuntime.InvokeVoidAsync("Radzen.removeContextMenu", UniqueID);
}
if (MouseEnter.HasDelegate)
{
JSRuntime.InvokeVoidAsync("Radzen.removeMouseEnter", UniqueID);
}
if (MouseEnter.HasDelegate)
{
JSRuntime.InvokeVoidAsync("Radzen.removeMouseEnter", UniqueID);
}
if (MouseLeave.HasDelegate)
{
JSRuntime.InvokeVoidAsync("Radzen.removeMouseLeave", UniqueID);
if (MouseLeave.HasDelegate)
{
JSRuntime.InvokeVoidAsync("Radzen.removeMouseLeave", UniqueID);
}
}
}

View File

@@ -40,8 +40,12 @@
await InvokeAsync(() => { StateHasChanged(); });
}
private bool IsJSRuntimeAvailable { get; set; }
protected override async Task OnAfterRenderAsync(bool firstRender)
{
IsJSRuntimeAvailable = true;
var menu = menus.LastOrDefault();
if (menu != null)
{
@@ -66,7 +70,10 @@
public void Dispose()
{
JSRuntime.InvokeVoidAsync("Radzen.destroyPopup", UniqueID);
if (IsJSRuntimeAvailable)
{
JSRuntime.InvokeVoidAsync("Radzen.destroyPopup", UniqueID);
}
Service.OnOpen -= OnOpen;
Service.OnClose -= OnClose;

View File

@@ -16,15 +16,41 @@
{
var visibleColumns = columns.Where(c => c.Visible).ToList();
<div style="@Style" @attributes="Attributes" class="rz-data-grid @GetCssClass()" id="@GetId()">
<div @ref=@Element style="@Style" @attributes="Attributes" class="rz-data-grid @GetCssClass()" id="@GetId()">
@if(AllowGrouping)
{
<div class="rz-group-header" @onmouseup=@(args => EndColumnDropToGroup())>
@if(groups.Any())
{
@foreach(var gd in groups)
{
<div class="rz-group-header-item">
<span class="rz-group-header-item-title">@gd.GetTitle()</span>
<a href="javascript:void(0)" @onclick=@(args => { groups.Remove(gd); _groupedPagedView = null; }) role="button" class="rz-dialog-titlebar-icon rz-dialog-titlebar-close">
<span class="rzi rzi-times"></span>
</a>
</div>
}
}
else
{
<div class="rz-group-header-drop">@GroupPanelText</div>
}
</div>
}
@if (AllowPaging && (PagerPosition == PagerPosition.Top || PagerPosition == PagerPosition.TopAndBottom))
{
<RadzenPager @ref="topPager" Count="@Count" PageSize="@PageSize" PageNumbersCount="@PageNumbersCount" PageChanged="@OnPageChanged" />
<RadzenPager @ref="topPager" Count="@Count" PageSize="@PageSize" PageNumbersCount="@PageNumbersCount" PageChanged="@OnPageChanged" PageSizeChanged="@OnPageSizeChanged" PageSizeOptions="@PageSizeOptions" />
}
<div class="rz-data-grid-data">
<table class="rz-grid-table rz-grid-table-fixed">
<colgroup>
@foreach(var g in groups)
{
<col>
}
@if (Template != null)
{
<col>
@@ -36,6 +62,12 @@
</colgroup>
<thead>
<tr>
@foreach(var g in groups)
{
<th class="rz-col-icon rz-unselectable-text" scope="col">
<span class="rz-column-title"></span>
</th>
}
@if (Template != null)
{
<th class="rz-col-icon rz-unselectable-text" scope="col">
@@ -44,9 +76,16 @@
}
@foreach (var column in visibleColumns)
{
var columnIndex = visibleColumns.IndexOf(column);
var sortableClass = AllowSorting && column.Sortable ? "rz-sortable-column" : "";
<th class="@($"rz-unselectable-text {sortableClass} {column.HeaderCssClass} {getFrozenColumnClass(column, visibleColumns)}")" scope="col" style="@column.GetStyle(true, true)">
<th class="@($"rz-unselectable-text {sortableClass} {column.HeaderCssClass} {getFrozenColumnClass(column, visibleColumns)}")" scope="col" style="@column.GetStyle(true, true)" @onmouseup=@(args => EndColumnReorder(args, columnIndex))>
<div @onclick='@((args) => OnSort(args, column))' style="width:100%">
@if (AllowColumnReorder && column.Reorderable || AllowGrouping)
{
<span id="@getColumnResizerId(columnIndex)" class="rz-column-drag"
@onclick:preventDefault="true" @onclick:stopPropagation="true"
@onmousedown=@(args => StartColumnReorder(args, columnIndex))>&nbsp;</span>
}
<span class="rz-column-title">
@if (column.HeaderTemplate != null)
{
@@ -72,9 +111,8 @@
<span class="rz-sortable-column-icon rzi-grid-sort rzi-sort"></span>
}
}
@if (AllowColumnResize)
@if (AllowColumnResize && column.Resizable)
{
var columnIndex = visibleColumns.IndexOf(column);
<div id="@getColumnResizerId(columnIndex)" style="cursor:col-resize;float:right;"
@onclick:preventDefault="true" @onclick:stopPropagation="true"
@onmousedown=@(args => StartColumnResize(args, columnIndex))>&nbsp;</div>
@@ -99,8 +137,7 @@
{
@(DrawNumericFilter(column, false))
}
else if (column.FilterPropertyType == typeof(DateTime) || column.FilterPropertyType == typeof(DateTime?) ||
column.FilterPropertyType == typeof(DateTimeOffset) || column.FilterPropertyType == typeof(DateTimeOffset?))
else if (PropertyAccess.IsDate(column.FilterPropertyType))
{
<RadzenDatePicker TValue="@object" ShowTime="true" ShowTimeOkButton="true" DateFormat="@getFilterDateFormat(column)"
Value="@column.GetFilterValue()" Change="@(args => column.SetFilterValue(args.Value))" />
@@ -108,7 +145,7 @@
}
else if (column.FilterPropertyType == typeof(bool) || column.FilterPropertyType == typeof(bool?))
{
<RadzenCheckBox TriState="true" TValue="@object" Value="@column.GetFilterValue()" Change="@((args) => OnFilter(new ChangeEventArgs() { Value = args }, column))" />
<RadzenCheckBox TriState="true" TValue="@object" Value="@column.GetFilterValue()" Change="@(args => column.SetFilterValue(args))" />
}
else
{
@@ -123,8 +160,7 @@
{
@(DrawNumericFilter(column, false, false))
}
else if (column.FilterPropertyType == typeof(DateTime) || column.FilterPropertyType == typeof(DateTime?) ||
column.FilterPropertyType == typeof(DateTimeOffset) || column.FilterPropertyType == typeof(DateTimeOffset?))
else if (PropertyAccess.IsDate(column.FilterPropertyType))
{
<RadzenDatePicker TValue="@object"
ShowTime="true" ShowTimeOkButton="true" DateFormat="@getFilterDateFormat(column)"
@@ -133,7 +169,7 @@
}
else if (column.FilterPropertyType == typeof(bool) || column.FilterPropertyType == typeof(bool?))
{
<RadzenCheckBox TriState="true" TValue="@object" Value="@column.GetSecondFilterValue()" Change="@((args) => OnFilter(new ChangeEventArgs() { Value = args }, column, false))" />
<RadzenCheckBox TriState="true" TValue="@object" Value="@column.GetSecondFilterValue()" Change="@(args => column.SetFilterValue(args, false))"/>
}
else
{
@@ -157,6 +193,12 @@
@if (AllowFiltering && FilterMode == FilterMode.Simple && columns.Where(column => column.Filterable && (!string.IsNullOrEmpty(column.GetFilterProperty()) || column.FilterTemplate != null)).Any())
{
<tr>
@foreach(var g in groups)
{
<th class="rz-col-icon rz-unselectable-text" scope="col">
<span class="rz-column-title"></span>
</th>
}
@if (Template != null)
{
<th class="rz-col-icon rz-unselectable-text" scope="col">
@@ -241,7 +283,9 @@
}
else if (column.FilterPropertyType == typeof(bool) || column.FilterPropertyType == typeof(bool?))
{
<div style="@(column.TextAlign == TextAlign.Center ? "width:100%;text-align:center" : column.TextAlign == TextAlign.Right ? "width:100%;text-align:right" : "")">
<RadzenCheckBox TriState="true" TValue="@object" Value="@column.GetFilterValue()" Change="@((args) => OnFilter(new ChangeEventArgs() { Value = args }, column))" />
</div>
}
else
{
@@ -269,7 +313,14 @@
{
<tr class=" rz-datatable-emptymessage-row">
<td class="rz-datatable-emptymessage" colspan="@visibleColumns.Count">
<span>@EmptyText</span>
@if (EmptyTemplate != null)
{
@EmptyTemplate
}
else
{
<span>@EmptyText</span>
}
</td>
</tr>
}
@@ -279,6 +330,12 @@
{
<tfoot class="rz-datatable-tfoot">
<tr class="">
@foreach(var g in groups)
{
<td class="rz-col-icon rz-unselectable-text" scope="col">
<span class="rz-column-title"></span>
</td>
}
@if (Template != null)
{
<td class="rz-col-icon rz-unselectable-text" scope="col">
@@ -312,20 +369,30 @@
@if (AllowPaging && (PagerPosition == PagerPosition.Bottom || PagerPosition == PagerPosition.TopAndBottom))
{
<RadzenPager @ref="topPager" Count="@Count" PageSize="@PageSize" PageNumbersCount="@PageNumbersCount" PageChanged="@OnPageChanged" />
<RadzenPager @ref="bottomPager" Count="@Count" PageSize="@PageSize" PageNumbersCount="@PageNumbersCount" PageChanged="@OnPageChanged" PageSizeChanged="@OnPageSizeChanged" PageSizeOptions="@PageSizeOptions" />
}
</div>
}
@code {
#if NET5
Microsoft.AspNetCore.Components.Web.Virtualization.Virtualize<TItem> virtualize;
#if NET5
internal void SetAllowVirtualization(bool allowVirtualization)
{
AllowVirtualization = allowVirtualization;
}
internal Microsoft.AspNetCore.Components.Web.Virtualization.Virtualize<TItem> virtualize;
private async ValueTask<Microsoft.AspNetCore.Components.Web.Virtualization.ItemsProviderResult<TItem>> LoadItems(Microsoft.AspNetCore.Components.Web.Virtualization.ItemsProviderRequest request)
{
var view = AllowPaging ? PagedView : View;
var totalItemsCount = LoadData.HasDelegate ? Count : view.Count();
var top = Math.Min(request.Count, totalItemsCount - request.StartIndex);
var top = totalItemsCount > request.Count ? Math.Min(request.Count, totalItemsCount - request.StartIndex) : PageSize;
if(top <= 0)
{
top = PageSize;
}
if (LoadData.HasDelegate)
{
@@ -341,7 +408,7 @@
await LoadData.InvokeAsync(new Radzen.LoadDataArgs() { Skip = request.StartIndex, Top = top, OrderBy = orderBy, Filter = IsOData() ? columns.ToODataFilterString<TItem>() : filterString });
}
return new Microsoft.AspNetCore.Components.Web.Virtualization.ItemsProviderResult<TItem>(LoadData.HasDelegate ? Data : view.Skip(request.StartIndex).Take(top), totalItemsCount);
return new Microsoft.AspNetCore.Components.Web.Virtualization.ItemsProviderResult<TItem>(LoadData.HasDelegate ? Data : itemToInsert != null ? (new[] { itemToInsert }).Concat(view.Skip(request.StartIndex).Take(top)) : view.Skip(request.StartIndex).Take(top), totalItemsCount);
}
#endif
RenderFragment DrawRows(IList<RadzenDataGridColumn<TItem>> visibleColumns)
@@ -363,6 +430,12 @@
b.AddAttribute(6, "TItem", typeof(TItem));
b.AddAttribute(7, "Item", context);
b.AddAttribute(8, "InEditMode", IsRowInEditMode(context));
if (editContexts.ContainsKey(context))
{
b.AddAttribute(9, nameof(RadzenDataGridRow<TItem>.EditContext), editContexts[context]);
}
b.SetKey(context);
b.CloseComponent();
});
@@ -374,35 +447,63 @@
}
else
{
int i = 0;
foreach (var item in LoadData.HasDelegate ? Data : PagedView)
{
builder.OpenComponent(0, typeof(RadzenDataGridRow<TItem>));
builder.AddAttribute(1, "Columns", visibleColumns);
builder.AddAttribute(2, "Index", i);
builder.AddAttribute(3, "Grid", this);
builder.AddAttribute(4, "TItem", typeof(TItem));
builder.AddAttribute(5, "Item", item);
builder.AddAttribute(6, "InEditMode", IsRowInEditMode(item));
builder.CloseComponent();
i++;
}
DrawGroupOrDataRows(builder, visibleColumns);
}
#else
int i = 0;
foreach (var item in LoadData.HasDelegate ? Data : PagedView)
DrawGroupOrDataRows(builder, visibleColumns);
#endif
});
}
internal void DrawGroupOrDataRows(Microsoft.AspNetCore.Components.Rendering.RenderTreeBuilder builder, IList<RadzenDataGridColumn<TItem>> visibleColumns)
{
if (groups.Any())
{
foreach (var group in GroupedPagedView)
{
builder.OpenComponent(0, typeof(RadzenDataGridRow<TItem>));
builder.OpenComponent(0, typeof(RadzenDataGridGroupRow<TItem>));
builder.AddAttribute(1, "Columns", visibleColumns);
builder.AddAttribute(3, "Grid", this);
builder.AddAttribute(5, "GroupResult", group);
builder.AddAttribute(6, "Builder", builder);
builder.CloseComponent();
}
}
else
{
int i = 0;
foreach (var item in PagedView)
{
builder.OpenComponent<RadzenDataGridRow<TItem>>(0);
builder.AddAttribute(1, "Columns", visibleColumns);
builder.AddAttribute(2, "Index", i);
builder.AddAttribute(3, "Grid", this);
builder.AddAttribute(4, "TItem", typeof(TItem));
builder.AddAttribute(5, "Item", item);
builder.AddAttribute(6, "InEditMode", IsRowInEditMode(item));
if (editContexts.ContainsKey(item))
{
builder.AddAttribute(7, nameof(RadzenDataGridRow<TItem>.EditContext), editContexts[item]);
}
builder.CloseComponent();
i++;
}
#endif
});
}
}
IEnumerable<GroupResult> _groupedPagedView;
public IEnumerable<GroupResult> GroupedPagedView
{
get
{
if(_groupedPagedView == null)
{
_groupedPagedView = PagedView.GroupByMany(groups.Select(g => g.Property).ToArray()).ToList();
}
return _groupedPagedView;
}
}
internal string getFrozenColumnClass(RadzenDataGridColumn<TItem> column, IList<RadzenDataGridColumn<TItem>> visibleColumns)
@@ -446,6 +547,13 @@
if (!columns.Contains(column))
{
columns.Add(column);
var descriptor = sorts.Where(d => d.Property == column?.GetSortProperty()).FirstOrDefault();
if (descriptor == null && column.SortOrder.HasValue)
{
descriptor = new SortDescriptor() { Property = column.Property, SortOrder = column.SortOrder.Value };
sorts.Add(descriptor);
}
}
}
@@ -535,6 +643,14 @@
builder.AddAttribute(3, "Change", eventCallbackGenericCreate.Invoke(this,
new object[] { this, eventCallbackGenericAction.Invoke(this, new object[] { action }) }));
if(FilterMode == FilterMode.Advanced)
{
builder.AddAttribute(4, "oninput", EventCallback.Factory.Create<ChangeEventArgs>(this, args => {
var value = $"{args.Value}";
column.SetFilterValue(!string.IsNullOrWhiteSpace(value) ? Convert.ChangeType(value, Nullable.GetUnderlyingType(type)) : null, isFirst);
} ));
}
builder.CloseComponent();
});
}
@@ -694,6 +810,9 @@
[Parameter]
public string ContainsText { get; set; } = "Contains";
[Parameter]
public string DoesNotContainText { get; set; } = "Does not contain";
[Parameter]
public string StartsWithText { get; set; } = "Starts with";
@@ -733,10 +852,13 @@
{
_emptyText = value;
ChangeState();
ChangeState().Wait();
}
}
}
[Parameter]
public RenderFragment EmptyTemplate { get; set; }
#if NET5
[Parameter]
public bool AllowVirtualization { get; set; }
@@ -756,6 +878,18 @@
[Parameter]
public bool AllowColumnResize { get; set; }
[Parameter]
public bool AllowColumnReorder { get; set; }
[Parameter]
public bool AllowGrouping { get; set; }
[Parameter]
public RenderFragment<Group> GroupHeaderTemplate { get; set; }
[Parameter]
public string GroupPanelText { get; set; } = "Drag a column header here and drop it to group by that column";
internal string getColumnResizerId(int columnIndex)
{
return string.Join("", $"{UniqueID}".Split('.')) + columnIndex;
@@ -766,6 +900,40 @@
await JSRuntime.InvokeVoidAsync("Radzen.startColumnResize", getColumnResizerId(columnIndex), Reference, columnIndex, args.ClientX);
}
int? indexOfColumnToReoder;
internal async Task StartColumnReorder(MouseEventArgs args, int columnIndex)
{
indexOfColumnToReoder = columnIndex;
await JSRuntime.InvokeVoidAsync("Radzen.startColumnReorder", getColumnResizerId(columnIndex));
}
internal async Task EndColumnReorder(MouseEventArgs args, int columnIndex)
{
if (indexOfColumnToReoder != null)
{
var visibleColumns = columns.Where(c => c.Visible).ToList();
var columnToReorder = visibleColumns.ElementAtOrDefault(indexOfColumnToReoder.Value);
var columnToReorderTo = visibleColumns.ElementAtOrDefault(columnIndex);
if (columnToReorder != null && columnToReorderTo != null)
{
var actualColumnIndex = columns.IndexOf(columnToReorderTo);
columns.Remove(columnToReorder);
columns.Insert(actualColumnIndex, columnToReorder);
await ColumnReordered.InvokeAsync(new DataGridColumnReorderedEventArgs<TItem>
{
Column = columnToReorder,
OldIndex = indexOfColumnToReoder.Value,
NewIndex = actualColumnIndex
});
}
indexOfColumnToReoder = null;
}
}
[JSInvokable("RadzenGrid.OnColumnResized")]
public async Task OnColumnResized(int columnIndex, double value)
{
@@ -780,12 +948,15 @@
internal string GetOrderBy()
{
return string.Join(",", columns.Where(c => c.GetSortOrder() != null).Select(c => c.GetSortOrderAsString(IsOData())));
return string.Join(",", sorts.Select(d => columns.Where(c => c.GetSortProperty() == d.Property).FirstOrDefault()).Where(c => c != null).Select(c => c.GetSortOrderAsString(IsOData())));
}
[Parameter]
public EventCallback<DataGridColumnResizedEventArgs<TItem>> ColumnResized { get; set; }
[Parameter]
public EventCallback<DataGridColumnReorderedEventArgs<TItem>> ColumnReordered { get; set; }
public override IQueryable<TItem> View
{
get
@@ -815,6 +986,12 @@
if (count != Count)
{
Count = count;
if (skip >= Count && Count > PageSize)
{
skip = Count - PageSize;
}
StateHasChanged();
}
}
@@ -883,8 +1060,9 @@
Reset(!IsOData() && !LoadData.HasDelegate);
}
public void Reset(bool resetColumnFilters = true, bool resetRowState = false)
public void Reset(bool resetColumnState = true, bool resetRowState = false)
{
_groupedPagedView = null;
_view = null;
_value = new List<TItem>();
@@ -894,14 +1072,17 @@
expandedItems.Clear();
}
if (resetColumnFilters)
if (resetColumnState)
{
columns.ForEach(c => { c.SetFilterValue(null); c.SetSecondFilterOperator(FilterOperator.Equals); });
}
columns.ForEach(c => { c.ResetSortOrder(); });
sorts.Clear();
}
}
public async override Task Reload()
{
_groupedPagedView = null;
_view = null;
if (Data != null && !LoadData.HasDelegate)
@@ -909,9 +1090,16 @@
Count = 1;
}
#if NET5
if (AllowVirtualization && virtualize != null && !LoadData.HasDelegate)
if (AllowVirtualization && virtualize != null)
{
await virtualize.RefreshDataAsync();
if(!LoadData.HasDelegate)
{
await virtualize.RefreshDataAsync();
}
else
{
Data = null;
}
}
#endif
var orderBy = GetOrderBy();
@@ -940,21 +1128,28 @@
SecondFilterOperator = c.GetSecondFilterOperator(),
LogicalFilterOperator = c.GetLogicalFilterOperator()
}),
Sorts = columns.Where(c => c.Sortable && c.Visible && c.GetSortOrder() != null).Select(c => new SortDescriptor()
{
Property = c.GetSortProperty(),
SortOrder = c.GetSortOrder().Value,
})
Sorts = sorts
}); ;
}
var v = PagedView;
CalculatePager();
if (!LoadData.HasDelegate)
{
StateHasChanged();
}
}
else
{
#if NET5
if (AllowVirtualization && virtualize != null)
{
await virtualize.RefreshDataAsync();
}
#endif
}
}
internal async Task ChangeState()
{
@@ -975,6 +1170,16 @@
return Task.CompletedTask;
}
internal Dictionary<Group, bool> collapsedGroupItems = new Dictionary<Group, bool>();
internal string ExpandedGroupItemStyle(Group item)
{
return collapsedGroupItems.Keys.Contains(item) ? "rz-row-toggler rzi-grid-sort rzi-chevron-circle-right" : "rz-row-toggler rzi-grid-sort rzi-chevron-circle-down";
}
internal bool IsGroupItemExpanded(Group item)
{
return !collapsedGroupItems.Keys.Contains(item) ;
}
internal Dictionary<TItem, bool> expandedItems = new Dictionary<TItem, bool>();
internal string ExpandedItemStyle(TItem item)
@@ -1094,6 +1299,22 @@
expandedItems.Remove(item);
await RowCollapse.InvokeAsync(item);
}
await InvokeAsync(StateHasChanged);
}
internal async System.Threading.Tasks.Task ExpandGroupItem(Group item)
{
if (!collapsedGroupItems.Keys.Contains(item))
{
collapsedGroupItems.Add(item, true);
}
else
{
collapsedGroupItems.Remove(item);
}
await InvokeAsync(StateHasChanged);
}
[Parameter]
@@ -1183,6 +1404,16 @@
internal Dictionary<TItem, EditContext> editContexts = new Dictionary<TItem, EditContext>();
public async System.Threading.Tasks.Task EditRow(TItem item)
{
if(itemToInsert != null)
{
CancelEditRow(itemToInsert);
}
await EditRowInternal(item);
}
async System.Threading.Tasks.Task EditRowInternal(TItem item)
{
if (EditMode == DataGridEditMode.Single && editedItems.Keys.Any())
{
@@ -1237,12 +1468,25 @@
{
if (object.Equals(itemToInsert, item))
{
var list = this.PagedView.ToList();
list.Remove(item);
this._view = list.AsQueryable();
this.Count = this.View.Count();
itemToInsert = default(TItem);
StateHasChanged();
if(!IsVirtualizationAllowed())
{
var list = this.PagedView.ToList();
list.Remove(item);
this._view = list.AsQueryable();
this.Count--;
itemToInsert = default(TItem);
StateHasChanged();
}
else
{
#if NET5
itemToInsert = default(TItem);
if (virtualize != null)
{
virtualize.RefreshDataAsync();
}
#endif
}
}
else
{
@@ -1267,18 +1511,38 @@
public async System.Threading.Tasks.Task InsertRow(TItem item)
{
itemToInsert = item;
var list = this.PagedView.ToList();
list.Insert(0, item);
this._view = list.AsQueryable();
this.Count = this._view.Count();
await EditRow(item);
if(!IsVirtualizationAllowed())
{
var list = this.PagedView.ToList();
list.Insert(0, item);
this._view = list.AsQueryable();
this.Count++;
}
else
{
#if NET5
if (virtualize != null)
{
await virtualize.RefreshDataAsync();
}
#endif
}
await EditRowInternal(item);
}
bool? isOData;
internal bool IsOData()
{
return Data != null && typeof(ODataEnumerable<TItem>).IsAssignableFrom(Data.GetType());
if(isOData == null && Data != null)
{
isOData = typeof(ODataEnumerable<TItem>).IsAssignableFrom(Data.GetType());
}
return isOData != null ? isOData.Value : false;
}
internal List<SortDescriptor> sorts = new List<SortDescriptor>();
internal void SetColumnSortOrder(RadzenDataGridColumn<TItem> column)
{
if (!AllowMultiColumnSorting)
@@ -1287,20 +1551,74 @@
{
c.SetSortOrder(null);
}
sorts.Clear();
}
var descriptor = sorts.Where(d => d.Property == column?.GetSortProperty()).FirstOrDefault();
if (descriptor == null)
{
descriptor = new SortDescriptor() { Property = column.GetSortProperty() };
}
if (column.GetSortOrder() == null)
{
column.SetSortOrder(SortOrder.Ascending);
descriptor.SortOrder = SortOrder.Ascending;
}
else if (column.GetSortOrder() == SortOrder.Ascending)
{
column.SetSortOrder(SortOrder.Descending);
descriptor.SortOrder = SortOrder.Descending;
}
else if (column.GetSortOrder() == SortOrder.Descending)
{
column.SetSortOrder(null);
if (sorts.Where(d => d.Property == column?.GetSortProperty()).Any())
{
sorts.Remove(descriptor);
}
descriptor = null;
}
if (descriptor != null && !sorts.Where(d => d.Property == column?.GetSortProperty()).Any())
{
sorts.Add(descriptor);
}
}
public List<GroupDescriptor> Groups
{
get
{
return groups;
}
set
{
groups = value;
}
}
internal List<GroupDescriptor> groups = new List<GroupDescriptor>();
internal void EndColumnDropToGroup()
{
if(indexOfColumnToReoder != null)
{
var column = columns.Where(c => c.Visible).ElementAtOrDefault(indexOfColumnToReoder.Value);
if(column != null && column.Groupable && !string.IsNullOrEmpty(column.GetGroupProperty()))
{
var descriptor = groups.Where(d => d.Property == column.GetGroupProperty()).FirstOrDefault();
if (descriptor == null)
{
descriptor = new GroupDescriptor() { Property = column.GetGroupProperty(), Title = column.Title };
groups.Add(descriptor);
_groupedPagedView = null;
}
}
indexOfColumnToReoder = null;
}
}
public void OrderBy(string property)
@@ -1372,9 +1690,12 @@
disposed = true;
foreach (var column in columns.Where(c => c.Visible))
if (IsJSRuntimeAvailable)
{
JSRuntime.InvokeVoidAsync("Radzen.destroyPopup", $"{PopupID}{column.GetFilterProperty()}");
foreach (var column in columns.Where(c => c.Visible))
{
JSRuntime.InvokeVoidAsync("Radzen.destroyPopup", $"{PopupID}{column.GetFilterProperty()}");
}
}
}
}

View File

@@ -1,5 +1,5 @@
@typeparam TItem
<td style="@Style" @attributes="@Attributes" class="@GetCssClass()" @onclick="@OnClick" @ondblclick="@OnDblClick" >
<td @attributes="@Attributes" style="@GetStyle()" class="@GetCssClass()" @onclick="@OnClick" @ondblclick="@OnDblClick" >
<CascadingValue Value=this>
@ChildContent
</CascadingValue>
@@ -118,6 +118,16 @@
return $"{CssClass} {@class}".Trim();
}
return CssClass;
return String.IsNullOrWhiteSpace(CssClass) ? null : CssClass;
}
string GetStyle()
{
if (Attributes != null && Attributes.TryGetValue("style", out var style) == true && !string.IsNullOrEmpty(Convert.ToString(style)))
{
return String.IsNullOrEmpty(Style) ? $"{style}" : $"{Style.TrimEnd(';')};{style}";
}
return Style;
}
}

View File

@@ -10,25 +10,28 @@
{
Grid.AddColumn(this);
var property = GetFilterProperty();
if (!string.IsNullOrEmpty(property))
if (!string.IsNullOrEmpty(FilterProperty) || Type == null)
{
_filterPropertyType = PropertyAccess.GetPropertyType(typeof(TItem), property);
var property = GetFilterProperty();
if (_filterPropertyType == null)
if (!string.IsNullOrEmpty(property))
{
_filterPropertyType = Type;
}
else
{
propertyValueGetter = PropertyAccess.Getter<TItem, object>(Property);
_filterPropertyType = PropertyAccess.GetPropertyType(typeof(TItem), property);
}
}
if (_filterPropertyType == null)
{
_filterPropertyType = Type;
}
else
{
propertyValueGetter = PropertyAccess.Getter<TItem, object>(Property);
}
if (_filterPropertyType == typeof(string))
{
FilterOperator = FilterOperator.Contains;
}
if (_filterPropertyType == typeof(string))
{
FilterOperator = FilterOperator.Contains;
}
}
}
@@ -48,6 +51,9 @@
[Parameter]
public string SortProperty { get; set; }
[Parameter]
public string GroupProperty { get; set; }
[Parameter]
public string FilterProperty { get; set; }
@@ -81,6 +87,15 @@
[Parameter]
public bool Frozen { get; set; }
[Parameter]
public bool Resizable { get; set; } = true;
[Parameter]
public bool Reorderable { get; set; } = true;
[Parameter]
public bool Groupable { get; set; } = true;
[Parameter]
public TextAlign TextAlign { get; set; } = TextAlign.Left;
@@ -109,7 +124,9 @@
public object GetValue(TItem item)
{
return propertyValueGetter != null ? propertyValueGetter(item) : !string.IsNullOrEmpty(Property) ? PropertyAccess.GetValue(item, Property) : "";
var value = propertyValueGetter != null && !string.IsNullOrEmpty(Property) && !Property.Contains('.') ? propertyValueGetter(item) : !string.IsNullOrEmpty(Property) ? PropertyAccess.GetValue(item, Property) : "";
return !string.IsNullOrEmpty(FormatString) ? string.Format(FormatString, value) : value;
}
internal object GetHeader()
@@ -154,15 +171,20 @@
.TakeWhile((c, i) => Grid.ColumnsCollection.IndexOf(this) > i && c.Frozen)
.Sum(c => {
var w = !string.IsNullOrEmpty(c.GetWidth()) ? c.GetWidth() : Grid.ColumnWidth;
return !string.IsNullOrEmpty(w) && w.Contains("px") ? int.Parse(w.Replace("px", "")) : 200;
var cw = 200;
if (!string.IsNullOrEmpty(w) && w.Contains("px"))
{
int.TryParse(w.Replace("px", ""), out cw);
}
return cw;
});
style.Add($"left:{left}px");
}
if (isHeaderOrFooterCell && !Frozen && Grid.ColumnsCollection.Where(c => c.Visible && c.Frozen).Any())
if ((isHeaderOrFooterCell && Frozen || isHeaderOrFooterCell && !Frozen || !isHeaderOrFooterCell && Frozen) && Grid.ColumnsCollection.Where(c => c.Visible && c.Frozen).Any())
{
style.Add("z-index:0");
style.Add($"z-index:{(isHeaderOrFooterCell && Frozen ? 2 : 1)}");
}
return string.Join(";", style);
@@ -194,6 +216,24 @@
sortOrder = new SortOrder?[] { order };
}
internal void ResetSortOrder()
{
sortOrder = Enumerable.Empty<SortOrder?>();
SortOrder = null;
}
public string GetGroupProperty()
{
if (!string.IsNullOrEmpty(GroupProperty))
{
return GroupProperty;
}
else
{
return Property;
}
}
public string GetFilterProperty()
{
if (!string.IsNullOrEmpty(FilterProperty))
@@ -236,7 +276,7 @@
if (parameters.DidParameterChange(nameof(SortOrder), SortOrder))
{
sortOrder = new SortOrder?[] { parameters.GetValueOrDefault<SortOrder>(nameof(SortOrder)) };
sortOrder = new SortOrder?[] { parameters.GetValueOrDefault<SortOrder?>(nameof(SortOrder)) };
}
if (parameters.DidParameterChange(nameof(FilterValue), FilterValue))
@@ -299,7 +339,7 @@
internal void SetFilterValue(object value, bool isFirst = true)
{
if (FilterPropertyType == typeof(DateTimeOffset) && value != null && value is DateTime?)
if ((FilterPropertyType == typeof(DateTimeOffset) || FilterPropertyType == typeof(DateTimeOffset?)) && value != null && value is DateTime?)
{
DateTimeOffset? offset = DateTime.SpecifyKind((DateTime)value, DateTimeKind.Utc);
value = offset;
@@ -350,7 +390,7 @@
internal IEnumerable<FilterOperator> GetFilterOperators()
{
return Enum.GetValues(typeof(FilterOperator)).Cast<FilterOperator>().Where(o => {
var isStringOperator = o == FilterOperator.Contains || o == FilterOperator.StartsWith || o == FilterOperator.EndsWith;
var isStringOperator = o == FilterOperator.Contains || o == FilterOperator.DoesNotContain || o == FilterOperator.StartsWith || o == FilterOperator.EndsWith;
return FilterPropertyType == typeof(string) ? isStringOperator || o == FilterOperator.Equals || o == FilterOperator.NotEquals : !isStringOperator;
});
}
@@ -361,6 +401,8 @@
{
case FilterOperator.Contains:
return Grid?.ContainsText;
case FilterOperator.DoesNotContain:
return Grid?.DoesNotContainText;
case FilterOperator.EndsWith:
return Grid?.EndsWithText;
case FilterOperator.Equals:

View File

@@ -0,0 +1,121 @@
@typeparam TItem
@using System.Linq.Dynamic.Core
<tr>
@for(var i = 0; i < GetLevel(); i++)
{
<td class="rz-col-icon">
<span class="rz-column-title"></span>
</td>
}
<td class="rz-col-icon">
<span class="rz-column-title"></span>
<a href="javascript:void(0)" @onclick="@(_ => Grid.ExpandGroupItem(Group))">
<span class="@(Grid.ExpandedGroupItemStyle(Group))"></span>
</a>
</td>
<td colspan="@(Columns.Count + Grid.groups.Count - 1 - Group.Level)">
<span class="rz-cell-data">
@if (Grid.GroupHeaderTemplate != null)
{
@Grid.GroupHeaderTemplate(Group)
}
else
{
@(Group.GroupDescriptor.GetTitle() + ": " + Group.Data.Key)
}
</span>
</td>
</tr>
@if(Grid != null && Grid.IsGroupItemExpanded(Group))
{
@DrawDataRows()
}
@code {
[Parameter]
public IList<RadzenDataGridColumn<TItem>> Columns { get; set; }
GroupResult _groupResult;
[Parameter]
public GroupResult GroupResult
{
get
{
return _groupResult;
}
set
{
if(_groupResult != value)
{
_groupResult = value;
var level = GetLevel();
Group = new Group()
{
Level = level,
GroupDescriptor = Grid.groups[level],
Data = _groupResult
};
}
}
}
[Parameter]
public RadzenDataGrid<TItem> Grid { get; set; }
[Parameter]
public RadzenDataGridGroupRow<TItem> Parent { get; set; }
[Parameter]
public Microsoft.AspNetCore.Components.Rendering.RenderTreeBuilder Builder { get; set; }
RenderFragment DrawDataRows()
{
return new RenderFragment(builder =>
{
if(GroupResult.Subgroups != null)
{
foreach(var g in GroupResult.Subgroups)
{
builder.OpenComponent(0, typeof(RadzenDataGridGroupRow<TItem>));
builder.AddAttribute(1, "Columns", Columns);
builder.AddAttribute(3, "Grid", Grid);
builder.AddAttribute(3, "Parent", this);
builder.AddAttribute(5, "GroupResult", g);
builder.AddAttribute(6, "Builder", builder);
builder.CloseComponent();
}
}
else
{
int i = 0;
foreach(var item in GroupResult.Items)
{
builder.OpenComponent(0, typeof(RadzenDataGridRow<TItem>));
builder.AddAttribute(1, "Columns", Columns);
builder.AddAttribute(2, "Index", i);
builder.AddAttribute(3, "Grid", Grid);
builder.AddAttribute(4, "TItem", typeof(TItem));
builder.AddAttribute(5, "Item", item);
builder.AddAttribute(6, "InEditMode", Grid.IsRowInEditMode((TItem)item));
builder.CloseComponent();
i++;
}
}
});
}
public Group Group { get; set; }
int GetLevel()
{
int i = 0;
var p = Parent;
while(p != null)
{
p = p.Parent;
i++;
}
return i;
}
}

View File

@@ -1,8 +1,15 @@
@using Microsoft.AspNetCore.Components.Forms
@typeparam TItem
@implements IRadzenForm
@implements IDisposable
@{var rowArgs = Grid?.RowAttributes(Item); }
<tr class="@(Grid.RowStyle(Item, Index))" @attributes="@rowArgs.Item2">
@foreach(var g in Grid.groups)
{
<td class="rz-col-icon">
<span class="rz-column-title"></span>
</td>
}
@if (Grid.Template != null)
{
<td class="rz-col-icon">
@@ -15,6 +22,7 @@
}
</td>
}
<CascadingValue Value=@EditContext>
<CascadingValue Value=this>
@for (var j = 0; j < Columns.Count; j++)
{
@@ -51,62 +59,29 @@
Grid.rowSpans.Add(j, (int)Convert.ChangeType(rowspan, TypeCode.Int32));
}
if (Grid.IsRowInEditMode(Item))
{
<CascadingValue Value=Grid.editContexts[Item]>
<td style="@column.GetStyle(true)" @attributes="@(cellAttr)" class="@Grid.getFrozenColumnClass(column, Columns)">
<span class="rz-cell-data">
@if (column.EditTemplate != null)
{
@column.EditTemplate(Item)
}
else if (column.Template != null)
{
@column.Template(Item)
}
else if (!string.IsNullOrEmpty(column.Property))
{
@if (!string.IsNullOrEmpty(column.FormatString))
{
@(String.Format(column.FormatString, PropertyAccess.GetValue(Item, column.Property)));
}
else if (!string.IsNullOrEmpty(column.Property))
{
@(PropertyAccess.GetValue(Item, column.Property));
}
}
</span>
</td>
</CascadingValue>
}
else
{
<RadzenDataGridCell Grid="@this.Grid" Item="@Item"
Style="@column.GetStyle(true)" CssClass="@(column.CssClass + " " + Grid.getFrozenColumnClass(column, Columns))" Attributes="@(cellAttr)">
<span class="rz-cell-data">
@if (Item != null)
<RadzenDataGridCell Grid="@this.Grid" Item="@Item"
Style="@column.GetStyle(true)" CssClass="@(column.CssClass + " " + Grid.getFrozenColumnClass(column, Columns))" Attributes="@(cellAttr)">
<span class="rz-cell-data" title="@(column.Template == null ? column.GetValue(Item) : "")">
@if (Item != null)
{
@if (Grid.IsRowInEditMode(Item) && column.EditTemplate != null)
{
@if (column.Template != null)
{
@column.Template(Item)
}
else if (!string.IsNullOrEmpty(column.Property))
{
@if (!string.IsNullOrEmpty(column.FormatString))
{
@(String.Format(column.FormatString, PropertyAccess.GetValue(Item, column.Property)));
}
else if (!string.IsNullOrEmpty(column.Property))
{
@(PropertyAccess.GetValue(Item, column.Property));
}
}
@column.EditTemplate(Item)
}
else if (column.Template != null)
{
@column.Template(Item)
}
</span>
</RadzenDataGridCell>
}
else
{
@column.GetValue(Item)
}
}
</span>
</RadzenDataGridCell>
}
</CascadingValue>
</CascadingValue>
</tr>
@if (Grid.Template != null && Grid.expandedItems.Keys.Contains(Item))
{
@@ -143,6 +118,9 @@
[Parameter]
public bool InEditMode { get; set; }
[Parameter]
public EditContext EditContext { get; set; }
List<IRadzenFormComponent> components;
public void AddComponent(IRadzenFormComponent component)
@@ -175,11 +153,8 @@
return components.Where(component => component.Name == name).FirstOrDefault();
}
Tuple<Radzen.RowRenderEventArgs<TItem>, IReadOnlyDictionary<string, object>> rowArgs;
protected override void OnInitialized()
{
rowArgs = Grid.RowAttributes(Item);
if (Grid.IsVirtualizationAllowed() && Item != null)
{
Index = Grid.GetItemIndex(Item);

View File

@@ -6,7 +6,7 @@
<div @ref="@Element" @attributes="Attributes" class="@GetCssClass()" style="@Style" id="@GetId()">
@if (AllowPaging && (PagerPosition == PagerPosition.Top || PagerPosition == PagerPosition.TopAndBottom))
{
<RadzenPager @ref="topPager" Count="@Count" PageSize="@PageSize" PageNumbersCount="@PageNumbersCount" PageChanged="@OnPageChanged" />
<RadzenPager @ref="topPager" Count="@Count" PageSize="@PageSize" PageNumbersCount="@PageNumbersCount" PageChanged="@OnPageChanged" PageSizeChanged="@OnPageSizeChanged" PageSizeOptions="@PageSizeOptions" />
}
@if (Data != null)
{
@@ -47,7 +47,7 @@
}
@if (AllowPaging && (PagerPosition == PagerPosition.Bottom || PagerPosition == PagerPosition.TopAndBottom))
{
<RadzenPager @ref="bottomPager" Count="@Count" PageSize="@PageSize" PageNumbersCount="@PageNumbersCount" PageChanged="@OnPageChanged" class="rz-paginator-bottom" />
<RadzenPager @ref="bottomPager" Count="@Count" PageSize="@PageSize" PageNumbersCount="@PageNumbersCount" PageChanged="@OnPageChanged" PageSizeChanged="@OnPageSizeChanged" PageSizeOptions="@PageSizeOptions" class="rz-paginator-bottom" />
}
</div>
}

View File

@@ -13,7 +13,7 @@
@if (!Inline)
{
<span class="@($"rz-calendar rz-calendar-w-btn{(Disabled ? " rz-state-disabled" : "")}")" style="width:100%">
<input @ref="@input" disabled="@Disabled" readonly="@ReadOnly" value="@FormattedValue" tabindex="@TabIndex"
<input @ref="@input" disabled="@Disabled" readonly="@IsReadonly" value="@FormattedValue" tabindex="@TabIndex"
@onchange="@ParseDate" autocomplete="off" type="text"
class="rz-inputtext" id="@Name" placeholder="@Placeholder" />
<button onclick="@getOpenPopup()" class="@($"rz-datepicker-trigger rz-calendar-button rz-button rz-button-icon-only{(Disabled ? " rz-state-disabled" : "")}")" tabindex="-1" type="button">
@@ -92,86 +92,30 @@
@if (ShowTime)
{
<div class="rz-timepicker">
<RadzenNumeric Disabled="@Disabled" Value="@(HourFormat == "12" ? ((CurrentDate.Hour + 11) % 12) + 1 : CurrentDate.Hour)" TValue="double" Step="@HoursStep"
Change="@(async v => {
var step = getStep(StepType.Hours);
if (v == CurrentDate.Hour - step || v == CurrentDate.Hour + step)
{
if (v > CurrentDate.Hour)
{
Value = CurrentDate.AddHours(step);
}
else
{
Value = CurrentDate.AddHours(-step);
}
}
else
{
Value = CurrentDate.AddHours(v - CurrentDate.Hour);
}
await OnChange();
} )" class="rz-hour-picker" />
<RadzenNumeric TValue="int" Disabled="@Disabled" Value="@(HourFormat == "12" ? ((CurrentDate.Hour + 11) % 12) + 1 : CurrentDate.Hour)"
Min="@(HourFormat == "12" ? 1 : -1)" Max="@(HourFormat == "12" ? 12 : 24)" TValue="double" Step="@HoursStep"
Change="@UpdateHour" class="rz-hour-picker" @oninput=@OnUpdateHourInput />
<div class="rz-separator">
<span>:</span>
</div>
<RadzenNumeric Disabled="@Disabled" Value="CurrentDate.Minute" TValue="double" Step="@MinutesStep"
Change="@(async v => {
var step = getStep(StepType.Minutes);
if (v == CurrentDate.Minute - step || v == CurrentDate.Minute + step)
{
if (v > CurrentDate.Minute)
{
Value = CurrentDate.AddMinutes(step);
}
else
{
Value = CurrentDate.AddMinutes(-step);
}
}
else
{
Value = CurrentDate.AddMinutes(v - CurrentDate.Minute);
}
await OnChange();
} )" class="rz-minute-picker" />
<RadzenNumeric TValue="int" Disabled="@Disabled" Value="CurrentDate.Minute" TValue="double" Step="@MinutesStep" Min="0" Max="59"
Change="@UpdateMinutes" class="rz-minute-picker" @oninput=@OnUpdateHourMinutes />
@if (ShowSeconds)
{
<div class="rz-separator">
<span>:</span>
</div>
<RadzenNumeric Disabled="@Disabled" Value="CurrentDate.Second" TValue="double" Step="@SecondsStep"
Change="@(async v => {
var step = getStep(StepType.Seconds);
if (v == CurrentDate.Second - step || v == CurrentDate.Second + step)
{
if (v > CurrentDate.Second)
{
Value = CurrentDate.AddSeconds(step);
}
else
{
Value = CurrentDate.AddSeconds(-step);
}
}
else
{
Value = CurrentDate.AddSeconds(v - CurrentDate.Second);
}
await OnChange();
} )" class="rz-second-picker" />
<RadzenNumeric TValue="int" Disabled="@Disabled" Value="CurrentDate.Second" TValue="double" Step="@SecondsStep" Min="0" Max="59"
Change="@UpdateSeconds" class="rz-second-picker" @oninput=@OnUpdateHourSeconds />
}
@if (HourFormat == "12")
{
<div class="rz-ampm-picker">
<a href="javascript:void(0)" @onclick="@(async() => { if (amPm == "am" && !Disabled) { Value = CurrentDate.AddDays(1).AddHours(-12); amPm = "pm"; await OnChange(); } })">
<a href="javascript:void(0)" @onclick="@AmToPm">
<span class="rzi rzi-chevron-up"></span>
</a>
<span>@CurrentDate.ToString("tt")</span>
<a href="javascript:void(0)" @onclick="@(async() => { if (amPm == "pm" && !Disabled) { Value = CurrentDate.AddDays(-1).AddHours(12); amPm = "am"; await OnChange(); } })">
<a href="javascript:void(0)" @onclick="@PmToAm">
<span class="rzi rzi-chevron-down"></span>
</a>
</div>
@@ -179,7 +123,7 @@
@if (ShowTimeOkButton)
{
<button type="button" class="rz-button rz-button-md btn-secondary" style="width:60px;padding:0px;margin-left:10px;"
@onclick="@(async() => { if (!Disabled) { Value = CurrentDate; await OnChange(); await monthDropDown?.ClosePopup(); await yearDropDown?.ClosePopup(); } })"
@onclick="@OkClick"
onmouseup="@($"Radzen.closePopup('{PopupID}')")">
<span class="rz-button-text">Ok</span>
</button>
@@ -193,6 +137,162 @@
RadzenDropDown<int> monthDropDown;
RadzenDropDown<int> yearDropDown;
async Task AmToPm()
{
if (amPm == "am" && !Disabled)
{
amPm = "pm";
var currentHour = ((CurrentDate.Hour + 11) % 12) + 1;
var newHour = currentHour - 12;
if(newHour < 1)
{
newHour = currentHour;
}
var newValue = new DateTime(CurrentDate.Year, CurrentDate.Month, CurrentDate.Day, newHour, CurrentDate.Minute, CurrentDate.Second);
if(!object.Equals(newValue, Value))
{
Value = newValue;
await OnChange();
}
}
}
async Task PmToAm()
{
if (amPm == "pm" && !Disabled)
{
amPm = "am";
var currentHour = ((CurrentDate.Hour + 11) % 12) + 1;
var newHour = currentHour + 12;
if(newHour > 23)
{
newHour = 0;
}
var newValue = new DateTime(CurrentDate.Year, CurrentDate.Month, CurrentDate.Day, newHour, CurrentDate.Minute, CurrentDate.Second);
if(!object.Equals(newValue, Value))
{
Value = newValue;
await OnChange();
}
}
}
int? hour;
void OnUpdateHourInput(ChangeEventArgs args)
{
var value = $"{args.Value}";
if(!string.IsNullOrWhiteSpace(value))
{
hour = (int)Convert.ChangeType(value, typeof(int));
}
}
int? minutes;
void OnUpdateHourMinutes(ChangeEventArgs args)
{
var value = $"{args.Value}";
if(!string.IsNullOrWhiteSpace(value))
{
minutes = (int)Convert.ChangeType(value, typeof(int));
}
}
int? seconds;
void OnUpdateHourSeconds(ChangeEventArgs args)
{
var value = $"{args.Value}";
if(!string.IsNullOrWhiteSpace(value))
{
seconds = (int)Convert.ChangeType(value, typeof(int));
}
}
async Task UpdateHour(int v)
{
var newHour = HourFormat == "12" && CurrentDate.Hour > 12 ? v + 12 : v;
var newValue = new DateTime(CurrentDate.Year, CurrentDate.Month, CurrentDate.Day, newHour > 23 || newHour < 0 ? 0 : newHour, CurrentDate.Minute, CurrentDate.Second);
if(!object.Equals(newValue, Value))
{
hour = newValue.Hour;
Value = newValue;
await OnChange();
}
}
async Task UpdateMinutes(int v)
{
var newValue = new DateTime(CurrentDate.Year, CurrentDate.Month, CurrentDate.Day, CurrentDate.Hour, v, CurrentDate.Second);
if(!object.Equals(newValue, Value))
{
minutes = newValue.Minute;
Value = newValue;
await OnChange();
}
}
async Task UpdateSeconds(int v)
{
var newValue = new DateTime(CurrentDate.Year, CurrentDate.Month, CurrentDate.Day, CurrentDate.Hour, CurrentDate.Minute, v);
if(!object.Equals(newValue, Value))
{
seconds = newValue.Second;
Value = newValue;
await OnChange();
}
}
async Task OkClick()
{
if (!Disabled)
{
DateTime date = CurrentDate;
if(CurrentDate.Hour != hour && hour != null)
{
var newHour = HourFormat == "12" && CurrentDate.Hour > 12 ? hour.Value + 12 : hour.Value;
date = new DateTime(CurrentDate.Year, CurrentDate.Month, CurrentDate.Day, newHour > 23 || newHour < 0 ? 0 : newHour, CurrentDate.Minute, CurrentDate.Second);
}
if(CurrentDate.Minute != minutes && minutes != null)
{
date = new DateTime(CurrentDate.Year, CurrentDate.Month, CurrentDate.Day, CurrentDate.Hour, minutes.Value, CurrentDate.Second);
}
if(CurrentDate.Second != seconds && seconds != null)
{
date = new DateTime(CurrentDate.Year, CurrentDate.Month, CurrentDate.Day, CurrentDate.Hour, CurrentDate.Minute, seconds.Value);
}
Value = date;
await OnChange();
if(monthDropDown != null)
{
await monthDropDown.ClosePopup();
}
if(yearDropDown != null)
{
await yearDropDown.ClosePopup();
}
}
}
class NameValue
{
public string Name { get; set; }
@@ -449,6 +549,11 @@
[Parameter]
public bool ReadOnly { get; set; }
[Parameter]
public bool AllowInput { get; set; } = true;
private bool IsReadonly => ReadOnly || !AllowInput;
[Parameter]
public bool Disabled { get; set; }
@@ -689,7 +794,10 @@
Form?.RemoveComponent(this);
JSRuntime.InvokeVoidAsync("Radzen.destroyPopup", PopupID);
if (IsJSRuntimeAvailable)
{
JSRuntime.InvokeVoidAsync("Radzen.destroyPopup", PopupID);
}
}
public object GetValue()

View File

@@ -20,7 +20,7 @@
await InvokeAsync(() => { StateHasChanged(); });
await JSRuntime.InvokeAsync<string>("Radzen.openDialog");
await JSRuntime.InvokeAsync<string>("Radzen.openDialog", options);
}
public async Task Close(dynamic result)

View File

@@ -1,17 +1,19 @@
@using Radzen
@using System.Linq
@using System.Linq.Dynamic.Core
@using Microsoft.AspNetCore.Components.Forms
@using Microsoft.JSInterop
@using Microsoft.AspNetCore.Components.Rendering
@typeparam TValue
@inherits DropDownBase<TValue>
@if (Visible)
{
<div @ref="@Element" @attributes="Attributes" class="@GetCssClass()" @onmousedown="@(args => OpenPopup("ArrowDown", false, true))" style="@Style" tabindex="@TabIndex"
@onkeydown="@((args) => OnKeyPress(args))" id="@GetId()">
<div @ref="@Element" @attributes="Attributes" class="@GetCssClass()" @onmousedown="@(args => OpenPopup("ArrowDown", false, true))" style="@Style" tabindex="@TabIndex"
@onkeydown="@((args) => OnKeyPress(args))" id="@GetId()">
<div class="rz-helper-hidden-accessible">
<input disabled="@Disabled" style="width:100%" aria-haspopup="listbox" readonly="" type="text" tabindex="-1"
name="@Name" value="@(Value != null ? Value : "")"
name="@Name" value="@(Value != null ? Value : "")"
aria-label="@(!Multiple && Value != null ? PropertyAccess.GetItemOrValueFromProperty(Value, TextProperty) : "")" />
</div>
@@ -39,7 +41,7 @@
else
{
foreach (var item in selectedItems)
{
{
@Template(item)@(",")
}
}
@@ -72,7 +74,7 @@
@if (AllowFiltering && !Multiple)
{
<div class="rz-dropdown-filter-container">
<input id="@SearchID" @ref="@search" tabindex="@TabIndex" class="rz-dropdown-filter rz-inputtext " autocomplete="off" type="text"
<input id="@SearchID" @ref="@search" tabindex="@TabIndex" class="rz-dropdown-filter rz-inputtext " autocomplete="off" type="text"
@onchange="@((ChangeEventArgs args) => OnFilter(args))" @onkeydown="@((args) => OnFilterKeyPress(args))" value="@searchText" />
<span class="rz-dropdown-filter-icon rzi rzi-search"></span>
</div>
@@ -89,7 +91,7 @@
</div>
</div>
@if (!AllowFiltering && !string.IsNullOrEmpty(SelectAllText))
{
{
@SelectAllText
}
@if (AllowFiltering)
@@ -111,45 +113,7 @@
<ul @ref="list" class="@(Multiple ? "rz-multiselect-items rz-multiselect-list " : "rz-dropdown-items rz-dropdown-list ")" role="listbox">
@if (View != null)
{
@foreach (var item in View)
{
@if (Multiple)
{
<li class="@(isSelected(item) ? "rz-multiselect-item rz-state-highlight" : "rz-multiselect-item ")"
aria-label="@PropertyAccess.GetItemOrValueFromProperty(item, TextProperty)" style="display: block;white-space: nowrap;" @onclick:preventDefault @onclick="@(() => OnSelectItem(item))">
<div class="rz-chkbox ">
<div class="@(isSelected(item) ? "rz-chkbox-box rz-state-active" : "rz-chkbox-box ")">
<span class="@(isSelected(item) ? "rz-chkbox-icon rzi rzi-check" : "rz-chkbox-icon ")"></span>
</div>
</div>
<span>
@if (Template != null)
{
@Template(item)
}
else
{
@PropertyAccess.GetItemOrValueFromProperty(item, TextProperty)
}
</span>
</li>
}
else
{
<li role="option" class="@(isSelected(item) ? "rz-dropdown-item rz-state-highlight" : "rz-dropdown-item ")" aria-label=">@PropertyAccess.GetItemOrValueFromProperty(item, TextProperty)" @onclick:preventDefault @onclick="@(() => OnSelectItem(item))">
<span>
@if (Template != null)
{
@Template(item)
}
else
{
@PropertyAccess.GetItemOrValueFromProperty(item, TextProperty)
}
</span>
</li>
}
}
@RenderItems()
}
</ul>
</div>
@@ -161,6 +125,15 @@
</div>
}
@code {
internal override void RenderItem(RenderTreeBuilder builder, object item)
{
builder.OpenComponent(0, typeof(RadzenDropDownItem<TValue>));
builder.AddAttribute(1, "DropDown", this);
builder.AddAttribute(2, "Item", item);
builder.SetKey(item);
builder.CloseComponent();
}
[Parameter]
public int MaxSelectedLabels { get; set; } = 4;
@@ -206,7 +179,7 @@
bool reload = false;
if (LoadData.HasDelegate && Data == null)
{
await LoadData.InvokeAsync(new Radzen.LoadDataArgs() { });
await LoadData.InvokeAsync(await GetLoadDataArgs());
reload = true;
}
@@ -234,6 +207,11 @@
await SelectItem(item);
}
internal async System.Threading.Tasks.Task OnSelectItemInternal(object item, bool isFromKey = false)
{
await OnSelectItem(item, isFromKey);
}
protected override string GetComponentCssClass()
{
var classList = new List<string>();
@@ -272,7 +250,10 @@
{
base.Dispose();
JSRuntime.InvokeVoidAsync("Radzen.destroyPopup", PopupID);
if (IsJSRuntimeAvailable)
{
JSRuntime.InvokeVoidAsync("Radzen.destroyPopup", PopupID);
}
}
internal async System.Threading.Tasks.Task ClosePopup()

View File

@@ -74,7 +74,7 @@
<div class="rz-dropdown-trigger rz-corner-right" onclick="@OpenPopupScript()">
<span class="rz-dropdown-trigger-icon rzi rzi-chevron-down"></span>
</div>
<div id="@PopupID" class="@(Multiple ? "rz-multiselect-panel " : "rz-dropdown-panel ")"
<div id="@PopupID" class="@(Multiple ? "rz-multiselect-panel" : "rz-dropdown-panel")"
style="display:none;min-width:320px;padding:0px;">
<div class="rz-lookup-panel">
@if (AllowFiltering)
@@ -92,33 +92,48 @@
}
@if (Template != null)
{
<RadzenGrid Responsive="@Responsive" ColumnWidth="@ColumnWidth" @ref="grid" Data="@(LoadData.HasDelegate ? (Data != null ? Data.Cast<object>() : Enumerable.Empty<object>()) : pagedData)" Count="@(LoadData.HasDelegate ? Count : count)" LoadData="@OnLoadData"
TItem="object" PageSize="@PageSize" PageNumbersCount="@PageNumbersCount" AllowPaging="true" AllowSorting="@AllowSorting" RowSelect="@OnRowSelect">
<RadzenDataGrid ColumnWidth="@ColumnWidth" @ref="grid" Data="@(LoadData.HasDelegate ? (Data != null ? Data.Cast<object>() : Enumerable.Empty<object>()) : pagedData)" Count="@(LoadData.HasDelegate ? Count : count)" LoadData="@OnLoadData"
TItem="object" PageSize="@PageSize" PageNumbersCount="@PageNumbersCount" AllowPaging="@(!IsVirtualizationAllowed())" AllowSorting="@AllowSorting" RowSelect="@OnRowSelect" Style="@(IsVirtualizationAllowed() ? "height:285px" : "")">
<Columns>
<RadzenGridColumn TItem="object" Property="@TextProperty" Title="@TextProperty" Type="string">
<RadzenDataGridColumn TItem="object" Property="@TextProperty" Title="@TextProperty" Type="typeof(string)">
<Template>
@Template(context)
</Template>
</RadzenGridColumn>
</RadzenDataGridColumn>
</Columns>
</RadzenGrid>
</RadzenDataGrid>
}
else
{
<RadzenGrid Responsive="@Responsive" ColumnWidth="@ColumnWidth" EmptyText="@EmptyText" @ref="grid" Data="@(LoadData.HasDelegate ? (Data != null ? Data.Cast<object>() : Enumerable.Empty<object>()) : pagedData)" Count="@(LoadData.HasDelegate ? Count : count)" LoadData="@OnLoadData"
TItem="object" PageSize="@PageSize" PageNumbersCount="@PageNumbersCount" AllowPaging="true" AllowSorting="@AllowSorting" RowSelect="@OnRowSelect">
<Columns>
@if (Columns != null)
{
@Columns
}
else
{
<RadzenGridColumn TItem="object" Property="@TextProperty" Title="@TextProperty" Type="string">
</RadzenGridColumn>
}
</Columns>
</RadzenGrid>
if (!string.IsNullOrEmpty(TextProperty) || Columns != null)
{
<RadzenDataGrid ColumnWidth="@ColumnWidth" EmptyText="@EmptyText" @ref="grid" Data="@(LoadData.HasDelegate ? (Data != null ? Data.Cast<object>() : Enumerable.Empty<object>()) : pagedData)" Count="@(LoadData.HasDelegate ? Count : count)" LoadData="@OnLoadData"
TItem="object" PageSize="@PageSize" PageNumbersCount="@PageNumbersCount" AllowPaging="@(!IsVirtualizationAllowed())" AllowSorting="@AllowSorting" RowSelect="@OnRowSelect" Style="@(IsVirtualizationAllowed() ? "height:285px" : "")">
<Columns>
@if (Columns != null)
{
@Columns
}
else
{
<RadzenDataGridColumn TItem="object" Property="@TextProperty" Title="@TextProperty" Type="typeof(string)" />
}
</Columns>
</RadzenDataGrid>
}
else
{
<RadzenDataGrid ColumnWidth="@ColumnWidth" EmptyText="@EmptyText" @ref="grid" Data="@(LoadData.HasDelegate ? (Data != null ? Data.Cast<object>() : Enumerable.Empty<object>()) : pagedData)" Count="@(LoadData.HasDelegate ? Count : count)" LoadData="@OnLoadData"
TItem="object" PageSize="@PageSize" PageNumbersCount="@PageNumbersCount" AllowPaging="@(!IsVirtualizationAllowed())" AllowSorting="@AllowSorting" RowSelect="@OnRowSelect" Style="@(IsVirtualizationAllowed() ? "height:285px" : "")">
<Columns>
<RadzenDataGridColumn TItem="object" Property="it" Title="Item" Type="typeof(string)">
<Template>
@context
</Template>
</RadzenDataGridColumn>
</Columns>
</RadzenDataGrid>
}
}
</div>
</div>
@@ -150,13 +165,10 @@
[Parameter]
public object SelectedValue { get; set; }
[Parameter]
public int Count { get; set; }
[Parameter]
public RenderFragment Columns { get; set; }
RadzenGrid<object> grid;
RadzenDataGrid<object> grid;
IEnumerable<object> pagedData;
int count;
@@ -164,6 +176,14 @@
[Parameter]
public int MaxSelectedLabels { get; set; } = 4;
#if !NET5
[Parameter]
public int PageSize { get; set; } = 5;
[Parameter]
public int Count { get; set; }
#endif
[Parameter]
public string SelectedItemsText { get; set; } = "items selected";
@@ -171,9 +191,19 @@
protected override Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender && Visible && (LoadData.HasDelegate && Data == null))
if (firstRender)
{
LoadData.InvokeAsync(new Radzen.LoadDataArgs() { Skip = 0, Top = PageSize });
#if NET5
if (grid != null)
{
grid.SetAllowVirtualization(AllowVirtualization);
}
#endif
if(Visible && LoadData.HasDelegate && Data == null)
{
LoadData.InvokeAsync(new Radzen.LoadDataArgs() { Skip = 0, Top = PageSize });
}
StateHasChanged();
}
@@ -199,11 +229,15 @@
private string GetPropertyFilterExpression(string property, string filterCaseSensitivityOperator)
{
if (property == null)
{
property = "it";
}
var p = $@"({property} == null ? """" : {property})";
return $"{p}{filterCaseSensitivityOperator}.{Enum.GetName(typeof(StringFilterOperator), FilterOperator)}(@0)";
}
private bool IsColumnFilterPropertyTypeString(RadzenGridColumn<object> column)
private bool IsColumnFilterPropertyTypeString(RadzenDataGridColumn<object> column)
{
var property = column.GetFilterProperty();
var itemType = Data != null ? Data.AsQueryable().ElementType : typeof(object);
@@ -247,7 +281,7 @@
count = query.Count();
pagedData = QueryableExtension.ToList(query.Skip(args.Skip.HasValue ? args.Skip.Value : 0).Take(PageSize)).Cast<object>();
pagedData = QueryableExtension.ToList(query.Skip(args.Skip.HasValue ? args.Skip.Value : 0).Take(args.Top.HasValue ? args.Top.Value : PageSize)).Cast<object>();
}
else
{
@@ -400,22 +434,35 @@
await InvokeAsync(() =>
{
StateHasChanged();
grid.FirstPage(true).Wait();
#if NET5
if (grid?.virtualize != null)
{
if(string.IsNullOrEmpty(searchText))
{
if(LoadData.HasDelegate)
{
Data = null;
}
else
{
pagedData = null;
StateHasChanged();
}
}
grid.virtualize.RefreshDataAsync().Wait();
}
#endif
StateHasChanged();
grid.FirstPage(true).Wait();
JSRuntime.InvokeAsync<string>("Radzen.repositionPopup", Element, PopupID);
});
}
}
protected override async Task OnFilter(ChangeEventArgs args)
{
searchText = await JSRuntime.InvokeAsync<string>("Radzen.getInputValue", search);
if (searchText != previousSearch)
{
previousSearch = searchText;
_view = null;
StateHasChanged();
await grid.FirstPage(true);
}
await DebounceFilter();
}
[Parameter]
@@ -427,10 +474,6 @@
[Parameter]
public bool AllowFilteringByAllStringColumns { get; set; }
[Parameter]
public int PageSize { get; set; } = 5;
async Task OnRowSelect(object item)
{
await SelectItem(item);
@@ -468,6 +511,9 @@
{
base.Dispose();
JSRuntime.InvokeVoidAsync("Radzen.destroyPopup", PopupID);
if (IsJSRuntimeAvailable)
{
JSRuntime.InvokeVoidAsync("Radzen.destroyPopup", PopupID);
}
}
}

View File

@@ -1 +1 @@
@inherits RadzenGridColumn<dynamic>
@inherits RadzenDataGridColumn<dynamic>

View File

@@ -0,0 +1,49 @@
@using Radzen
@using System.Linq.Dynamic.Core
@using Microsoft.AspNetCore.Components.Forms
@using Microsoft.JSInterop
@typeparam TValue
@if (DropDown.Multiple)
{
<li class="@(DropDown.isSelected(Item) ? "rz-multiselect-item rz-state-highlight" : "rz-multiselect-item ")"
aria-label="@PropertyAccess.GetItemOrValueFromProperty(Item, DropDown.TextProperty)" style="display: block;white-space: nowrap;" @onclick:preventDefault @onclick="@(() => DropDown.OnSelectItemInternal(Item))">
<div class="rz-chkbox ">
<div class="@(DropDown.isSelected(Item) ? "rz-chkbox-box rz-state-active" : "rz-chkbox-box ")">
<span class="@(DropDown.isSelected(Item) ? "rz-chkbox-icon rzi rzi-check" : "rz-chkbox-icon ")"></span>
</div>
</div>
<span>
@if (DropDown.Template != null)
{
@DropDown.Template(Item)
}
else
{
@PropertyAccess.GetItemOrValueFromProperty(Item, DropDown.TextProperty)
}
</span>
</li>
}
else
{
<li role="option" class="@(DropDown.isSelected(Item) ? "rz-dropdown-item rz-state-highlight" : "rz-dropdown-item ")" aria-label=">@PropertyAccess.GetItemOrValueFromProperty(Item, DropDown.TextProperty)" @onclick:preventDefault @onclick="@(() => DropDown.OnSelectItemInternal(Item))">
<span>
@if (DropDown.Template != null)
{
@DropDown.Template(Item)
}
else
{
@PropertyAccess.GetItemOrValueFromProperty(Item, DropDown.TextProperty)
}
</span>
</li>
}
@code {
[Parameter]
public RadzenDropDown<TValue> DropDown { get; set; }
[Parameter]
public object Item { get; set; }
}

View File

@@ -46,6 +46,14 @@
@ChildContent
</div>
</div>
@if (SummaryTemplate != null)
{
<div class="rz-fieldset-content-wrapper" role="region" aria-hidden="false" style="@summaryContentStyle">
<div class="rz-fieldset-content rz-fieldset-content-summary">
@SummaryTemplate
</div>
</div>
}
</fieldset>
}
@code {
@@ -73,6 +81,9 @@
[Parameter]
public RenderFragment ChildContent { get; set; }
[Parameter]
public RenderFragment SummaryTemplate { get; set; } = null;
[Parameter]
public EventCallback Expand { get; set; }
@@ -80,11 +91,13 @@
public EventCallback Collapse { get; set; }
string contentStyle = "";
string summaryContentStyle = "display: none";
async System.Threading.Tasks.Task Toggle(EventArgs args)
{
collapsed = !collapsed;
contentStyle = collapsed ? "display: none;" : "";
summaryContentStyle = !collapsed ? "display: none" : "";
if (collapsed)
{
@@ -116,6 +129,7 @@
protected override Task OnParametersSetAsync()
{
contentStyle = collapsed ? "display: none;" : "";
summaryContentStyle = !collapsed ? "display: none" : "";
return base.OnParametersSetAsync();
}

View File

@@ -21,7 +21,7 @@
<div>
@if (IsImage)
{
<img style="width:100px;" src="@Value">
<img style="@ImageStyle" src="@Value">
}
</div>
<div>
@@ -152,4 +152,7 @@
[Parameter]
public int MaxFileSize { get; set; } = 5 * 1024 * 1024;
[Parameter]
public string ImageStyle { get; set; } = "width:100px;";
}

View File

@@ -75,6 +75,8 @@
protected override async Task OnAfterRenderAsync(bool firstRender)
{
await base.OnAfterRenderAsync(firstRender);
var data = Data != null ? Data : markers;
if (firstRender)
@@ -93,6 +95,9 @@
{
base.Dispose();
JSRuntime.InvokeVoidAsync("Radzen.destroyMap", UniqueID);
if (IsJSRuntimeAvailable)
{
JSRuntime.InvokeVoidAsync("Radzen.destroyMap", UniqueID);
}
}
}

View File

@@ -20,7 +20,7 @@
<div @ref="@Element" style="@Style" @attributes="Attributes" class="@GetCssClass()" id="@GetId()">
@if (AllowPaging && (PagerPosition == PagerPosition.Top || PagerPosition == PagerPosition.TopAndBottom))
{
<RadzenPager @ref="topPager" Count="@Count" PageSize="@PageSize" PageNumbersCount="@PageNumbersCount" PageChanged="@OnPageChanged" />
<RadzenPager @ref="topPager" Count="@Count" PageSize="@PageSize" PageNumbersCount="@PageNumbersCount" PageChanged="@OnPageChanged" PageSizeChanged="@OnPageSizeChanged" PageSizeOptions="@PageSizeOptions" />
}
<div class="rz-datatable-scrollable-wrapper rz-helper-clearfix" style="">
<div class="rz-datatable-scrollable-view">
@@ -64,11 +64,11 @@
</span>
@if (AllowSorting && column.Sortable)
{
@if (!string.IsNullOrEmpty(orderBy) && orderBy.Contains($"{column.GetSortProperty()} asc"))
@if (column.SortOrder == SortOrder.Ascending)
{
<span class="rz-sortable-column-icon rzi-grid-sort rzi-sort rzi-sort-asc"></span>
}
else if (!string.IsNullOrEmpty(orderBy) && orderBy.Contains($"{column.GetSortProperty()} desc"))
else if (column.SortOrder == SortOrder.Descending)
{
<span class="rz-sortable-column-icon rzi-grid-sort rzi-sort rzi-sort-desc"></span>
}
@@ -423,7 +423,14 @@
{
<tr class=" rz-datatable-emptymessage-row">
<td class="rz-datatable-emptymessage" colspan="@visibleColumns.Count">
<span>@EmptyText</span>
@if (EmptyTemplate != null)
{
@EmptyTemplate
}
else
{
<span>@EmptyText</span>
}
</td>
</tr>
}
@@ -477,7 +484,7 @@
@if (AllowPaging && (PagerPosition == PagerPosition.Bottom || PagerPosition == PagerPosition.TopAndBottom))
{
<RadzenPager @ref="bottomPager" Count="@Count" PageSize="@PageSize" PageNumbersCount="@PageNumbersCount" PageChanged="@OnPageChanged" class="rz-paginator-bottom" />
<RadzenPager @ref="bottomPager" Count="@Count" PageSize="@PageSize" PageNumbersCount="@PageNumbersCount" PageChanged="@OnPageChanged" PageSizeChanged="@OnPageSizeChanged" PageSizeOptions="@PageSizeOptions" class="rz-paginator-bottom" />
}
</div>
}
@@ -633,12 +640,14 @@
if (value != _emptyText)
{
_emptyText = value;
ChangeState();
ChangeState().Wait();
}
}
}
[Parameter]
public RenderFragment EmptyTemplate { get; set; }
[Parameter]
public bool AllowSorting { get; set; }
@@ -1106,6 +1115,16 @@
Dictionary<TItem, EditContext> editContexts = new Dictionary<TItem, EditContext>();
public async System.Threading.Tasks.Task EditRow(TItem item)
{
if(itemToInsert != null)
{
CancelEditRow(itemToInsert);
}
await EditRowInternal(item);
}
async System.Threading.Tasks.Task EditRowInternal(TItem item)
{
if (EditMode == DataGridEditMode.Single && editedItems.Keys.Any())
{
@@ -1194,7 +1213,7 @@
list.Insert(0, item);
this._view = list.AsQueryable();
this.Count = this._view.Count();
await EditRow(item);
await EditRowInternal(item);
}
protected void OnSort(EventArgs args, RadzenGridColumn<TItem> column)
@@ -1267,6 +1286,7 @@
public void OrderBy(string property)
{
SetColumnSortOrder(property);
var p = IsOData() ? property.Replace('.', '/') : PropertyAccess.GetProperty(property);
orderBy = orderBy == $"{p} desc" || orderBy == null || orderBy.IndexOf(p) == -1 ? $"{p} asc" : $"{p} desc";
InvokeAsync(Reload);
@@ -1274,11 +1294,32 @@
public void OrderByDescending(string property)
{
SetColumnSortOrder(property);
var p = IsOData() ? property.Replace('.', '/') : PropertyAccess.GetProperty(property);
orderBy = $"{p} desc";
InvokeAsync(Reload);
}
internal void SetColumnSortOrder(string property)
{
var column = columns.Where(c => c.GetSortProperty() == property).FirstOrDefault();
if(column != null)
{
if (column.SortOrder == null)
{
column.SortOrder = SortOrder.Ascending;
}
else if (column.SortOrder == SortOrder.Ascending)
{
column.SortOrder = SortOrder.Descending;
}
else if (column.SortOrder == SortOrder.Descending)
{
column.SortOrder = null;
}
}
}
protected override string GetComponentCssClass()
{
var additionalClasses = new List<string>();

View File

@@ -31,7 +31,9 @@
_title = value;
if (Grid != null)
Grid.ChangeState();
{
Grid.ChangeState().Wait();
}
}
}
}
@@ -279,6 +281,8 @@
}
}
internal SortOrder? SortOrder { get; set; }
public string GetFilterProperty()
{
if (!string.IsNullOrEmpty(FilterProperty))

View File

@@ -138,6 +138,8 @@
protected override async Task OnAfterRenderAsync(bool firstRender)
{
await base.OnAfterRenderAsync(firstRender);
this.firstRender = firstRender;
if (firstRender || visibleChanged)
@@ -214,7 +216,7 @@
{
base.Dispose();
if (Visible)
if (Visible && IsJSRuntimeAvailable)
{
JSRuntime.InvokeVoidAsync("Radzen.destroyEditor", ContentEditable);
}

View File

@@ -2,6 +2,7 @@
@using System.Linq.Dynamic.Core
@using Microsoft.AspNetCore.Components.Forms
@using Microsoft.JSInterop
@using Microsoft.AspNetCore.Components.Rendering
@typeparam TValue
@inherits DropDownBase<TValue>
@if (Visible)
@@ -24,7 +25,7 @@
</div>
</div>
@if (!AllowFiltering && !string.IsNullOrEmpty(Placeholder))
{
{
<label for="@($"{UniqueID}sa")" class="rz-dropdown-label rz-inputtext " style="width:100%;">@Placeholder</label>
}
}
@@ -42,35 +43,23 @@
{
<div class="rz-listbox-list-wrapper">
<ul @ref="list" class="rz-listbox-list">
@foreach (var item in View)
{
<li class="@(isSelected(item) ? "rz-multiselect-item rz-state-highlight" : "rz-multiselect-item ")" aria-label="@PropertyAccess.GetItemOrValueFromProperty(item, TextProperty)" style="display: block;" @onclick="@(async () => { if (!Disabled) { await SelectItem(item); } })">
@if (Multiple)
{
<div class="rz-chkbox ">
<div class="@(isSelected(item) ? "rz-chkbox-box rz-state-active" : "rz-chkbox-box ")">
<span class="@(isSelected(item) ? "rz-chkbox-icon rzi rzi-check" : "rz-chkbox-icon ")"></span>
</div>
</div>
}
<span>
@if (Template != null)
{
@Template(item)
}
else
{
@PropertyAccess.GetItemOrValueFromProperty(item, TextProperty)
}
</span>
</li>
}
@RenderItems()
</ul>
</div>
}
</div>
}
@code {
internal override void RenderItem(RenderTreeBuilder builder, object item)
{
builder.OpenComponent(0, typeof(RadzenListBoxItem<TValue>));
builder.AddAttribute(1, "ListBox", this);
builder.AddAttribute(2, "Item", item);
builder.SetKey(item);
builder.CloseComponent();
}
protected async System.Threading.Tasks.Task OnKeyDown(Microsoft.AspNetCore.Components.Web.KeyboardEventArgs args)
{
if (Disabled)
@@ -123,7 +112,7 @@
bool reload = false;
if (LoadData.HasDelegate && Data == null)
{
await LoadData.InvokeAsync(new Radzen.LoadDataArgs() { });
await LoadData.InvokeAsync(await GetLoadDataArgs());
reload = true;
}

View File

@@ -0,0 +1,34 @@
@using Radzen
@using System.Linq.Dynamic.Core
@using Microsoft.AspNetCore.Components.Forms
@using Microsoft.JSInterop
@typeparam TValue
<li class="@(ListBox.isSelected(Item) ? "rz-multiselect-item rz-state-highlight" : "rz-multiselect-item ")" aria-label="@PropertyAccess.GetItemOrValueFromProperty(Item, ListBox.TextProperty)" style="display: block;" @onclick="@(async () => { if (!ListBox.Disabled) { await ListBox.SelectItemInternal(Item); } })">
@if (ListBox.Multiple)
{
<div class="rz-chkbox ">
<div class="@(ListBox.isSelected(Item) ? "rz-chkbox-box rz-state-active" : "rz-chkbox-box ")">
<span class="@(ListBox.isSelected(Item) ? "rz-chkbox-icon rzi rzi-check" : "rz-chkbox-icon ")"></span>
</div>
</div>
}
<span>
@if (ListBox.Template != null)
{
@ListBox.Template(Item)
}
else
{
@PropertyAccess.GetItemOrValueFromProperty(Item, ListBox.TextProperty)
}
</span>
</li>
@code {
[Parameter]
public RadzenListBox<TValue> ListBox { get; set; }
[Parameter]
public object Item { get; set; }
}

View File

@@ -7,14 +7,14 @@
<div class="row form-group">
<label class="col-sm-3 col-form-label" for="username">@UserText</label>
<div class="col">
<RadzenTextBox style="display: block" Name="Username" @bind-Value=@Username />
<RadzenTextBox AutoComplete=@AutoComplete style="display: block" Name="Username" @bind-Value=@Username />
<RadzenRequiredValidator Component="Username" Text=@UserRequired style="position: absolute" />
</div>
</div>
<div class="row form-group">
<label class="col-sm-3 col-form-label" for="password">@PasswordText</label>
<div class="col">
<RadzenPassword style="display: block" Name="Password" @bind-Value=@Password />
<RadzenPassword AutoComplete=@AutoComplete style="display: block" Name="Password" @bind-Value=@Password />
<RadzenRequiredValidator Component="Password" Text=@PasswordRequired style="position: absolute" />
</div>
</div>
@@ -37,7 +37,10 @@
}
</div>
}
@code {
@code {
[Parameter]
public bool AutoComplete { get; set; } = true;
protected override string GetComponentCssClass()
{
return "login";

View File

@@ -7,7 +7,7 @@
{
<input @ref="@Element" disabled="@Disabled" readonly="@ReadOnly" name="@Name" style="@Style" @attributes="Attributes" class="@GetCssClass()" tabindex="@TabIndex"
placeholder="@Placeholder" maxlength="@MaxLength" autocomplete="@(AutoComplete ? "on" : "off")" value="@Value" @onchange="@OnChange" id="@GetId()"
onkeyup="Radzen.mask('@GetId()', '@Mask', '@Pattern')"/>
oninput="Radzen.mask('@GetId()', '@Mask', '@Pattern')"/>
}
@code {
[Parameter]

View File

@@ -15,7 +15,14 @@
{
<img class="rz-navigation-item-icon" src="@Image" />
}
<span class="rz-navigation-item-text">@Text</span>
@if(Template != null)
{
@Template
}
else
{
<span class="rz-navigation-item-text">@Text</span>
}
@if (ChildContent != null)
{
<i class="rzi rz-navigation-item-icon-children">keyboard_arrow_down</i>
@@ -33,7 +40,14 @@
{
<img class="rz-navigation-item-icon" src="@Image" />
}
<span class="rz-navigation-item-text">@Text</span>
@if(Template != null)
{
@Template
}
else
{
<span class="rz-navigation-item-text">@Text</span>
}
@if (ChildContent != null)
{
<i class="rzi rz-navigation-item-icon-children">keyboard_arrow_down</i>
@@ -73,6 +87,9 @@
[Parameter]
public string Image { get; set; }
[Parameter]
public RenderFragment Template { get; set; }
[Parameter]
public RenderFragment ChildContent { get; set; }

View File

@@ -152,10 +152,20 @@
await InternalValueChanged(args.Value);
}
private string RemoveNonNumericCharacters(object value)
{
string valueStr = value as string;
if (valueStr == null)
{
valueStr = value.ToString();
}
return new string(valueStr.Where(c => char.IsDigit(c) || char.IsPunctuation(c)).ToArray());
}
private async System.Threading.Tasks.Task InternalValueChanged(object value)
{
TValue newValue;
BindConverter.TryConvertTo<TValue>($"{value}", System.Globalization.CultureInfo.CurrentCulture, out newValue);
BindConverter.TryConvertTo<TValue>(RemoveNonNumericCharacters(value), System.Globalization.CultureInfo.CurrentCulture, out newValue);
decimal? newValueAsDecimal = newValue == null ? default(decimal?) : (decimal)ConvertType.ChangeType(newValue, typeof(decimal));
@@ -191,4 +201,30 @@
[Parameter]
public decimal? Max { get; set; }
public override async Task SetParametersAsync(ParameterView parameters)
{
bool minChanged = parameters.DidParameterChange(nameof(Min), Min);
bool maxChanged = parameters.DidParameterChange(nameof(Max), Max);
await base.SetParametersAsync(parameters);
if (minChanged && Min.HasValue && Value != null && IsJSRuntimeAvailable)
{
decimal decimalValue = (decimal)Convert.ChangeType(Value, typeof(decimal));
if (decimalValue < Min.Value)
{
await InternalValueChanged(Min.Value);
}
}
if (maxChanged && Max.HasValue && Value != null && IsJSRuntimeAvailable)
{
decimal decimalValue = (decimal)Convert.ChangeType(Value, typeof(decimal));
if (decimalValue > Max.Value)
{
await InternalValueChanged(Max.Value);
}
}
}
}

View File

@@ -1,22 +1,22 @@
@inherits RadzenComponent
@if (Visible && Count > PageSize)
@if (GetVisible())
{
<div @ref="@Element" @attributes="Attributes" class="@GetCssClass()" style="@Style" id="@GetId()">
@if (skip > 0)
{
<a class="rz-paginator-first rz-paginator-element" href="javascript:void(0)" tabindex="-1" @onclick="@(() => FirstPage())">
<a class="rz-paginator-first rz-paginator-element" href="javascript:void(0)" tabindex="-1" @onclick:preventDefault="true" @onclick="@(() => FirstPage())">
<span class="rz-paginator-icon rzi rzi-step-backward"></span>
</a>
<a class="rz-paginator-prev rz-paginator-element" href="javascript:void(0)" tabindex="-1" @onclick="@(() => PrevPage())">
<a class="rz-paginator-prev rz-paginator-element" href="javascript:void(0)" tabindex="-1" @onclick:preventDefault="true" @onclick="@(() => PrevPage())">
<span class="rz-paginator-icon rzi rzi-caret-left"></span>
</a>
}
else
{
<a class="rz-paginator-first rz-paginator-element rz-state-disabled" href="javascript:void(0)" tabindex="-1" @onclick="@(() => FirstPage())">
<a class="rz-paginator-first rz-paginator-element rz-state-disabled" href="javascript:void(0)" tabindex="-1" @onclick:preventDefault="true" @onclick="@(() => FirstPage())">
<span class="rz-paginator-icon rzi rzi-step-backward"></span>
</a>
<a class="rz-paginator-prev rz-paginator-element rz-state-disabled" href="javascript:void(0)" tabindex="-1" @onclick="@(() => PrevPage())">
<a class="rz-paginator-prev rz-paginator-element rz-state-disabled" href="javascript:void(0)" tabindex="-1" @onclick:preventDefault="true" @onclick="@(() => PrevPage())">
<span class="rz-paginator-icon rzi rzi-caret-left"></span>
</a>
}
@@ -25,32 +25,36 @@
{
@if (i == CurrentPage)
{
<a class="rz-paginator-page rz-paginator-element rz-state-active" href="javascript:void(0)" @onclick="@(() => GoToPage(i))">@(i + 1)</a>
<a class="rz-paginator-page rz-paginator-element rz-state-active" href="javascript:void(0)" @onclick:preventDefault="true" @onclick="@(() => GoToPage(i))">@(i + 1)</a>
}
else
{
<a class="rz-paginator-page rz-paginator-element" href="javascript:void(0)" @onclick="@(() => GoToPage(i))">@(i + 1)</a>
<a class="rz-paginator-page rz-paginator-element" href="javascript:void(0)" @onclick:preventDefault="true" @onclick="@(() => GoToPage(i))">@(i + 1)</a>
}
}
</span>
@if (CurrentPage != numberOfPages - 1)
{
<a class="rz-paginator-next rz-paginator-element" href="javascript:void(0)" tabindex="0" @onclick="@(() => NextPage())">
<a class="rz-paginator-next rz-paginator-element" href="javascript:void(0)" tabindex="0" @onclick:preventDefault="true" @onclick="@(() => NextPage())">
<span class="rz-paginator-icon rzi rzi-caret-right"></span>
</a>
<a class="rz-paginator-last rz-paginator-element" href="javascript:void(0)" tabindex="0" @onclick="@(() => LastPage())">
<a class="rz-paginator-last rz-paginator-element" href="javascript:void(0)" tabindex="0" @onclick:preventDefault="true" @onclick="@(() => LastPage())">
<span class="rz-paginator-icon rzi rzi-step-forward"></span>
</a>
}
else
{
<a class="rz-paginator-next rz-paginator-element rz-state-disabled" href="javascript:void(0)" tabindex="0" @onclick="@(() => NextPage())">
<a class="rz-paginator-next rz-paginator-element rz-state-disabled" href="javascript:void(0)" tabindex="0" @onclick:preventDefault="true" @onclick="@(() => NextPage())">
<span class="rz-paginator-icon rzi rzi-caret-right"></span>
</a>
<a class="rz-paginator-last rz-paginator-element rz-state-disabled" href="javascript:void(0)" tabindex="0" @onclick="@(() => LastPage())">
<a class="rz-paginator-last rz-paginator-element rz-state-disabled" href="javascript:void(0)" tabindex="0" @onclick:preventDefault="true" @onclick="@(() => LastPage())">
<span class="rz-paginator-icon rzi rzi-step-forward"></span>
</a>
}
@if(PageSizeOptions != null && PageSizeOptions.Any())
{
<RadzenDropDown TValue="int" Data="@PageSizeOptions" Value="@PageSize" Change="@OnPageSizeChanged" />
}
</div>
}
@code {
@@ -62,6 +66,12 @@
[Parameter]
public int PageSize { get; set; } = 10;
[Parameter]
public EventCallback<int> PageSizeChanged { get; set; }
[Parameter]
public IEnumerable<int> PageSizeOptions { get; set; }
[Parameter]
public int PageNumbersCount { get; set; } = 5;
@@ -74,8 +84,13 @@
{
return GetPage();
}
}
}
protected bool GetVisible()
{
return Visible && (Count > PageSize || (PageSizeOptions != null && PageSizeOptions.Any()));
}
[Parameter]
public EventCallback<PagerEventArgs> PageChanged { get; set; }
@@ -86,7 +101,7 @@
protected override Task OnParametersSetAsync()
{
if (Visible)
if (GetVisible())
{
InvokeAsync(Reload);
}
@@ -94,6 +109,25 @@
return base.OnParametersSetAsync();
}
protected async Task OnPageSizeChanged(object value)
{
bool isFirstPage = CurrentPage == 0;
bool isLastPage = CurrentPage == numberOfPages - 1;
int prevSkip = skip;
PageSize = (int)value;
await InvokeAsync(Reload);
await PageSizeChanged.InvokeAsync((int)value);
if (isLastPage)
{
await LastPage();
}
else if (!isFirstPage)
{
int newPage = (int)Math.Floor((decimal)(prevSkip / (PageSize > 0 ? PageSize : 10)));
await GoToPage(newPage, true);
}
}
protected int skip;
protected int numberOfPageLinks = 5;
protected int startPage;
@@ -129,9 +163,9 @@
return (int)Math.Floor((decimal)(skip / (PageSize > 0 ? PageSize : 10)));
}
public async Task GoToPage(int page)
public async Task GoToPage(int page, bool forceReload = false)
{
if (CurrentPage != page)
if (CurrentPage != page || forceReload)
{
skip = page * PageSize;
await InvokeAsync(Reload);
@@ -139,7 +173,7 @@
}
}
internal async void SetCurrentPage(int page)
internal void SetCurrentPage(int page)
{
if (CurrentPage != page)
{
@@ -147,6 +181,12 @@
}
}
internal void SetCount(int count)
{
Count = count;
CalculatePager();
}
public async Task FirstPage(bool forceReload = false)
{
if (CurrentPage != 0 || forceReload)

View File

@@ -38,6 +38,14 @@
</div>
}
</div>
@if (SummaryTemplate != null)
{
<div class="rz-panel-content-wrapper" role="region" aria-hidden="false" style="@summaryContentStyle">
<div class="rz-panel-content rz-panel-content-summary">
@SummaryTemplate
</div>
</div>
}
</div>
}
@code {
@@ -63,6 +71,9 @@
[Parameter]
public RenderFragment HeaderTemplate { get; set; }
[Parameter]
public RenderFragment SummaryTemplate { get; set; } = null;
[Parameter]
public RenderFragment FooterTemplate { get; set; }
@@ -73,11 +84,13 @@
public EventCallback Collapse { get; set; }
string contentStyle = "display: block;";
string summaryContentStyle = "display: none";
async System.Threading.Tasks.Task Toggle(MouseEventArgs args)
{
collapsed = !collapsed;
contentStyle = collapsed ? "display: none;" : "display: block;";
summaryContentStyle = !collapsed ? "display: none" : "display: block";
if (collapsed)
{
@@ -109,6 +122,7 @@
protected override Task OnParametersSetAsync()
{
contentStyle = collapsed ? "display: none;" : "display: block;";
summaryContentStyle = !collapsed ? "display: none" : "display: block";
return base.OnParametersSetAsync();
}

View File

@@ -15,7 +15,14 @@
{
<img class="rz-navigation-item-icon" src="@Image" />
}
<span class="rz-navigation-item-text" @onclick="@Toggle">@Text</span>
@if(Template != null)
{
@Template
}
else
{
<span class="rz-navigation-item-text" @onclick="@Toggle">@Text</span>
}
@if (items.Any())
{
<i class="rzi rz-navigation-item-icon-children" style="@getStyle()" @onclick="@Toggle">keyboard_arrow_down</i>
@@ -33,7 +40,14 @@
{
<img class="rz-navigation-item-icon" src="@Image" />
}
<span class="rz-navigation-item-text">@Text</span>
@if(Template != null)
{
@Template
}
else
{
<span class="rz-navigation-item-text">@Text</span>
}
@if (items.Any())
{
<i class="rzi rz-navigation-item-icon-children" style="@getStyle()">keyboard_arrow_down</i>
@@ -78,6 +92,9 @@
[Parameter]
public string Image { get; set; }
[Parameter]
public RenderFragment Template { get; set; }
[Parameter]
public bool Expanded { get; set; } = false;

View File

@@ -3,73 +3,73 @@
@inherits FormComponent<int>
@if (Visible)
{
@if (Disabled)
{
<div @ref="@Element" @attributes="Attributes" class="@GetCssClass()" id="@GetId()">
<a href="javascript:void(0)" class="rz-rating-cancel">
<span class="rz-rating-icon rzi rzi-ban"></span>
</a>
@foreach (var index in Enumerable.Range(1, Stars))
{
@if (index <= Value)
{
<a href="javascript:void(0)">
<span class="rz-rating-icon rzi rzi-star"></span>
</a>
}
else
{
<a href="javascript:void(0)">
<span class="rz-rating-icon rzi rzi-star-o"></span>
</a>
}
}
</div>
}
else
{
<div @ref="@Element" @attributes="Attributes" class="@GetCssClass()" id="@GetId()">
<div @ref="@Element" @attributes="Attributes" class="@GetCssClass()" id="@GetId()">
@if (!ReadOnly)
{
<a href="javascript:void(0)" class="rz-rating-cancel" tabindex="@TabIndex" @onclick="@(args => SetValue(0))" @onkeypress="@(async args => { if (args.Code == "Space") { await SetValue(0); } })">
<span class="rz-rating-icon rzi rzi-ban"></span>
</a>
@foreach (var index in Enumerable.Range(1, Stars))
}
@foreach (var index in Enumerable.Range(1, Stars))
{
@if (index <= Value)
{
@if (index <= Value)
{
<a href="javascript:void(0)" tabindex="@TabIndex" @onclick="@(args => SetValue(index))" @onkeypress="@(async args => { if (args.Code == "Space") { await SetValue(index); } })">
<span class="rz-rating-icon rzi rzi-star"></span>
</a>
}
else
{
<a href="javascript:void(0)" tabindex="@TabIndex" @onclick="@(args => SetValue(index))" @onkeypress="@(async args => { if (args.Code == "Space") { await SetValue(index); } })">
<span class="rz-rating-icon rzi rzi-star-o"></span>
</a>
}
<a href="javascript:void(0)" tabindex="@TabIndex" @onclick="@(args => SetValue(index))" @onkeypress="@(async args => { if (args.Code == "Space") { await SetValue(index); } })">
<span class="rz-rating-icon rzi rzi-star"></span>
</a>
}
</div>
}
else
{
<a href="javascript:void(0)" tabindex="@TabIndex" @onclick="@(args => SetValue(index))" @onkeypress="@(async args => { if (args.Code == "Space") { await SetValue(index); } })">
<span class="rz-rating-icon rzi rzi-star-o"></span>
</a>
}
}
</div>
}
@code {
protected override string GetComponentCssClass()
{
var fieldCssClass = FieldIdentifier.FieldName != null ? EditContext?.FieldCssClass(FieldIdentifier) : "";
return $"rz-rating {(Disabled ? "rz-state-disabled" : "")} {fieldCssClass}";
var classList = new List<string>();
classList.Add("rz-rating");
if (Disabled)
{
classList.Add("rz-state-disabled");
}
if (ReadOnly)
{
classList.Add("rz-state-readonly");
}
if (!string.IsNullOrEmpty(fieldCssClass))
{
classList.Add(fieldCssClass);
}
return string.Join(" ", classList);
}
[Parameter]
public int Stars { get; set; } = 5;
[Parameter]
public bool ReadOnly { get; set; }
private async System.Threading.Tasks.Task SetValue(int value)
{
Value = value;
if (!Disabled && !ReadOnly)
{
Value = value;
await ValueChanged.InvokeAsync(value);
if (FieldIdentifier.FieldName != null) { EditContext?.NotifyFieldChanged(FieldIdentifier); }
await Change.InvokeAsync(value);
await ValueChanged.InvokeAsync(value);
if (FieldIdentifier.FieldName != null) { EditContext?.NotifyFieldChanged(FieldIdentifier); }
await Change.InvokeAsync(value);
}
}
}

View File

@@ -307,6 +307,8 @@
protected override async Task OnAfterRenderAsync(bool firstRender)
{
await base.OnAfterRenderAsync(firstRender);
if (firstRender)
{
var rect = await JSRuntime.InvokeAsync<Rect>("Radzen.createScheduler", Element, Reference);
@@ -339,7 +341,11 @@
public override void Dispose()
{
base.Dispose();
JSRuntime.InvokeVoidAsync("Radzen.destroyScheduler", Element);
if (IsJSRuntimeAvailable)
{
JSRuntime.InvokeVoidAsync("Radzen.destroyScheduler", Element);
}
}
private bool heightIsSet = false;

View File

@@ -99,7 +99,11 @@
public override void Dispose()
{
base.Dispose();
JSRuntime.InvokeVoidAsync("Radzen.destroySlider", UniqueID, Element);
if (IsJSRuntimeAvailable)
{
JSRuntime.InvokeVoidAsync("Radzen.destroySlider", UniqueID, Element);
}
}
[JSInvokable("RadzenSlider.OnValueChange")]

View File

@@ -0,0 +1,218 @@
@using Microsoft.JSInterop
@using System.Globalization
@inherits RadzenComponent
@if (Visible)
{
<div @ref="@Element" @attributes="Attributes" class="@GetCssClass()" id="@GetId()" style="@Style">
<CascadingValue Value=this>
@ChildContent
</CascadingValue>
</div>
}
@code {
private int _sizeautopanes = 0;
[Parameter]
public RenderFragment ChildContent { get; set; }
[Parameter]
public Orientation Orientation { get; set; } = Orientation.Horizontal;
internal List<RadzenSplitterPane> Panes = new List<RadzenSplitterPane>();
public void AddPane(RadzenSplitterPane pane)
{
if (Panes.IndexOf(pane) != -1 || !pane.Visible)
return;
if (string.IsNullOrWhiteSpace(pane.Size))
{
//no size defined
pane.SizeAuto = true;
_sizeautopanes++;
}
pane.Index = Panes.Count;
Panes.Add(pane);
foreach (var iPane in Panes)
{
if (!iPane.SizeAuto)
continue;
iPane.SizeRuntine = (100 / _sizeautopanes) + "%";
}
}
public void RemovePane(RadzenSplitterPane pane)
{
if (Panes.Contains(pane))
{
Panes.Remove(pane);
try
{
InvokeAsync(StateHasChanged);
}
catch
{
}
}
}
public void Refresh()
{
try
{
InvokeAsync(StateHasChanged);
}
catch
{
}
}
internal Task ResizeExec(MouseEventArgs args, int paneIndex)
{
var pane = Panes[paneIndex];
if (!pane.Resizable)
return Task.CompletedTask;
var paneNextResizable = Panes.Skip(paneIndex + 1).FirstOrDefault(o => o.Resizable && !o.Collapsed);
return JSRuntime.InvokeVoidAsync("Radzen.startSplitterResize",
UniqueID,
Reference,
pane.UniqueID,
paneNextResizable?.UniqueID,
Orientation.ToString(), Orientation == Orientation.Horizontal ? args.ClientX : args.ClientY,
pane.Min,
pane.Max,
paneNextResizable?.Min,
paneNextResizable?.Max).AsTask();
}
[JSInvokable("RadzenSplitter.OnPaneResized")]
public async Task OnPaneResized(int paneIndex, double sizeNew, int? paneNextIndex, double? sizeNextNew)
{
var pane = Panes[paneIndex];
if (Resize.HasDelegate)
{
var arg = new RadzenSplitterResizeEventArgs {PaneIndex = pane.Index, Pane = pane, NewSize = sizeNew};
await Resize.InvokeAsync(arg);
if (arg.Cancel)
{
var oldSize = pane.SizeRuntine;
pane.SizeRuntine = "0";
await InvokeAsync(StateHasChanged);
pane.SizeRuntine = oldSize;
await InvokeAsync(StateHasChanged);
return;
}
}
pane.SizeRuntine = sizeNew.ToString("0.##", CultureInfo.InvariantCulture) + "%";
if (paneNextIndex.HasValue)
{
var paneNext = Panes[paneNextIndex.Value];
if (Expand.HasDelegate)
{
var arg = new RadzenSplitterResizeEventArgs {PaneIndex = paneNext.Index, Pane = paneNext, NewSize = sizeNextNew.Value};
await Resize.InvokeAsync(arg);
//cancel omitted because it is managed by the parent panel
}
paneNext.SizeRuntine = sizeNextNew.Value.ToString("0.##", CultureInfo.InvariantCulture) + "%";
}
}
internal async Task CollapseExec(object args, int paneIndex, string paneId)
{
var pane = Panes[paneIndex];
var paneNext = pane.Next();
if (paneNext != null && paneNext.Collapsible && paneNext.IsLast && paneNext.Collapsed)
{
if (Expand.HasDelegate)
{
var arg = new RadzenSplitterEventArgs {PaneIndex = paneNext.Index, Pane = paneNext};
await Expand.InvokeAsync(arg);
if (arg.Cancel)
return;
}
paneNext.Collapsed = false;
}
else
{
if (Collapse.HasDelegate)
{
var arg = new RadzenSplitterEventArgs {PaneIndex = pane.Index, Pane = pane};
await Collapse.InvokeAsync(arg);
if (arg.Cancel)
return;
}
pane.Collapsed = true;
}
await InvokeAsync(StateHasChanged);
}
internal async Task ExpandExec(MouseEventArgs args, int paneIndex, string paneId)
{
var pane = Panes[paneIndex];
var paneNext = pane.Next();
if (paneNext != null && paneNext.Collapsible && paneNext.IsLast && !pane.Collapsed)
{
if (Collapse.HasDelegate)
{
var arg = new RadzenSplitterEventArgs {PaneIndex = paneNext.Index, Pane = paneNext};
await Collapse.InvokeAsync(arg);
if (arg.Cancel)
return;
}
paneNext.Collapsed = true;
}
else
{
if (Expand.HasDelegate)
{
var arg = new RadzenSplitterEventArgs {PaneIndex = pane.Index, Pane = pane};
await Expand.InvokeAsync(arg);
if (arg.Cancel)
return;
}
pane.Collapsed = false;
}
await InvokeAsync(StateHasChanged);
}
protected override string GetComponentCssClass()
{
return $"rz-splitter rz-splitter-{Enum.GetName(typeof(Orientation), Orientation).ToLower()}";
}
[Parameter]
public EventCallback<RadzenSplitterEventArgs> Collapse { get; set; }
[Parameter]
public EventCallback<RadzenSplitterEventArgs> Expand { get; set; }
[Parameter]
public EventCallback<RadzenSplitterResizeEventArgs> Resize { get; set; }
}

View File

@@ -0,0 +1,188 @@
@using System.Diagnostics
@inherits RadzenComponent
@if (Visible)
{
<div id="@GetId()" class="@GetComponentCssClass()" style="flex-basis: @Size;" data-index="@Index">
@ChildContent
</div>
@if (!IsLast)
{
<div class="@GetComponentBarCssClass()"
@onclick:preventDefault="true"
@onclick:stopPropagation="true"
@onmousedown=@(args => Splitter.ResizeExec(args, Index))>
@if (IsCollapsible)
{
<span class="rz-collapse" @onmousedown:preventDefault="true" @onmousedown:stopPropagation="true" @onmousedown=@(args => Splitter.CollapseExec(args, Index, UniqueID))>
</span>
}
@if (IsResizable)
{
<span class="rz-resize">
</span>
}
@if (IsExpandable)
{
<span class="rz-expand" @onmousedown:preventDefault="true" @onmousedown:stopPropagation="true" @onmousedown=@(args => Splitter.ExpandExec(args, Index, UniqueID))>
</span>
}
</div>
}
}
@code {
RadzenSplitter _splitter;
private string _size;
internal string SizeRuntine { get; set; }
internal bool SizeAuto { get; set; }
internal int Index { get; set; }
internal bool IsLastResizable
{
get { return Splitter.Panes.Last(o => o.Resizable && !o.Collapsed) == this; }
}
internal bool IsLast => Splitter.Panes.Count - 1 == Index;
internal RadzenSplitterPane Next()
{
return Index <= Splitter.Panes.Count - 2
? Splitter.Panes[Index + 1]
: null;
}
internal bool IsResizable
{
get
{
var paneNext = Next();
if (Collapsed
|| (Index == Splitter.Panes.Count - 2 && !paneNext.IsResizable)
|| (IsLastResizable && paneNext != null && paneNext.Collapsed)
)
return false;
return Resizable;
}
}
internal bool IsCollapsible
{
get
{
if (Collapsible && !Collapsed)
return true;
var paneNext = Next();
if (paneNext == null)
return false;
return paneNext.IsLast && paneNext.Collapsible && paneNext.Collapsed;
}
}
internal bool IsExpandable
{
get
{
if (Collapsed)
return true;
var paneNext = Next();
if (paneNext == null)
return false;
return paneNext.IsLast && paneNext.Collapsible && !paneNext.Collapsed;
}
}
internal string ClassName
{
get
{
if (Collapsed)
return "collapsed";
if (IsLastResizable)
return "lastresizable";
if (IsResizable)
return "resizable";
return "locked";
}
}
[Parameter]
public RenderFragment ChildContent { get; set; }
[Parameter]
public bool Collapsible { get; set; } = true;
[Parameter]
public bool Collapsed { get; set; }
[Parameter]
public bool Resizable { get; set; } = true;
[Parameter]
public string Max { get; set; }
[Parameter]
public string Min { get; set; }
[Parameter]
public string Size
{
get => SizeRuntine ?? _size;
set => _size = value;
}
[CascadingParameter]
public RadzenSplitter Splitter
{
get => _splitter;
set
{
if (_splitter != value)
{
_splitter = value;
_splitter.AddPane(this);
}
}
}
public override void Dispose()
{
base.Dispose();
Splitter?.RemovePane(this);
}
protected override string GetComponentCssClass()
{
return $"rz-splitter-pane rz-splitter-pane-{ClassName}";
}
protected string GetComponentBarCssClass()
{
return $"rz-splitter-bar rz-splitter-bar-{ClassName}";
}
}

View File

@@ -3,7 +3,7 @@
@inherits FormComponent<bool>
@if (Visible)
{
<div @ref="@Element" @attributes="Attributes" class="@GetCssClass()"
<div @ref="@Element" @attributes="Attributes" class="@GetCssClass()" id="@GetId()"
@onmouseup="@OnMouseUp" @onkeypress="@(async (args) => { if (args.Code == "Space") { await Toggle(); } })" style="outline: 0 none;@Style" tabindex="@TabIndex">
<div class="rz-helper-hidden-accessible">
<input type="checkbox" name="@Name" value="@Value" tabindex="-1">

View File

@@ -9,11 +9,23 @@
@Tabs
</ul>
<div class="rz-tabview-panels">
@if (SelectedTab?.Visible == true)
@if(RenderMode == TabRenderMode.Client)
{
<div class="rz-tabview-panel" role="tabpanel" id="@($"{Id}-tabpanel-{selectedIndex}")" aria-hidden="false" aria-labelledby="@($"{Id}-tabpanel-{selectedIndex}-label")">
@SelectedTab.ChildContent
</div>
for (var i = 0; i < tabs.Count; i++)
{
<div class="rz-tabview-panel" role="tabpanel" id="@($"{Id}-tabpanel-{i}")" style="@(tabs[i] == SelectedTab ? "" : "display:none")" aria-hidden="@(tabs[i] == SelectedTab ? "false" : "true")" aria-labelledby="@($"{Id}-tabpanel-{i}-label")">
@tabs[i].ChildContent
</div>
}
}
else
{
@if (SelectedTab?.Visible == true)
{
<div class="rz-tabview-panel" role="tabpanel" id="@($"{Id}-tabpanel-{selectedIndex}")" aria-hidden="false" aria-labelledby="@($"{Id}-tabpanel-{selectedIndex}-label")">
@SelectedTab.ChildContent
</div>
}
}
</div>
</div>
@@ -21,6 +33,9 @@
</CascadingValue>
@code {
[Parameter]
public TabRenderMode RenderMode { get; set; } = TabRenderMode.Server;
[Parameter]
public int SelectedIndex { get; set; } = -1;

View File

@@ -40,13 +40,14 @@
await InvokeAsync(() => { StateHasChanged(); });
}
bool firstRender = true;
bool IsJSRuntimeAvailable { get; set; }
protected override async Task OnAfterRenderAsync(bool firstRender)
{
this.firstRender = firstRender;
IsJSRuntimeAvailable = true;
var tooltip = tooltips.LastOrDefault();
if (tooltip != null)
{
await JSRuntime.InvokeVoidAsync("Radzen.openTooltip",
@@ -71,7 +72,7 @@
public void Dispose()
{
if (!firstRender)
if (IsJSRuntimeAvailable)
{
JSRuntime.InvokeVoidAsync("Radzen.destroyPopup", UniqueID);
}

View File

@@ -48,7 +48,52 @@
[Parameter]
public EventCallback<object> ValueChanged { get; set; }
void RenderTreeItem(RenderTreeBuilder builder, object data, RenderFragment<RadzenTreeItem> template, Func<object,
[Parameter]
public bool AllowCheckBoxes { get; set; }
[Parameter]
public bool AllowCheckChildren { get; set; } = true;
[Parameter]
public bool AllowCheckParents { get; set; } = true;
[Parameter]
public IEnumerable<object> CheckedValues { get; set; } = Enumerable.Empty<object>();
internal List<RadzenTreeItem> items = new List<RadzenTreeItem>();
internal void AddItem(RadzenTreeItem item)
{
if (items.IndexOf(item) == -1)
{
items.Add(item);
}
}
internal void RemoveItem(RadzenTreeItem item)
{
if (items.IndexOf(item) != -1)
{
items.Remove(item);
}
}
internal async Task SetCheckedValues(IEnumerable<object> values)
{
CheckedValues = values.ToList();
await CheckedValuesChanged.InvokeAsync(CheckedValues);
}
internal IEnumerable<object> UncheckedValues { get; set; } = Enumerable.Empty<object>();
internal void SetUncheckedValues(IEnumerable<object> values)
{
UncheckedValues = values.ToList();
}
[Parameter]
public EventCallback<IEnumerable<object>> CheckedValuesChanged { get; set; }
void RenderTreeItem(RadzenTreeItem parent, RenderTreeBuilder builder, object data, RenderFragment<RadzenTreeItem> template, Func<object,
string> text,
Func<object, bool> hasChildren, Func<object, bool> expanded, Func<object, bool> selected)
{
@@ -59,6 +104,12 @@
builder.AddAttribute(4, nameof(RadzenTreeItem.Template), template);
builder.AddAttribute(5, nameof(RadzenTreeItem.Expanded), expanded(data));
builder.AddAttribute(6, nameof(RadzenTreeItem.Selected), Value == data || selected(data));
if (parent != null)
{
builder.AddAttribute(7, nameof(RadzenTreeItem.ParentItem), parent);
}
builder.SetKey(data);
}
@@ -77,7 +128,7 @@
text = level.Text ?? Getter<string>(data, level.TextProperty);
}
RenderTreeItem(builder, data, level.Template, text, level.HasChildren, level.Expanded, level.Selected);
RenderTreeItem(null, builder, data, level.Template, text, level.HasChildren, level.Expanded, level.Selected);
var hasChildren = level.HasChildren(data);
@@ -144,12 +195,24 @@
text = children.Text ?? Getter<string>(data, children.TextProperty);
}
RenderTreeItem(builder, data, children.Template, text, children.HasChildren, children.Expanded, children.Selected);
RenderTreeItem(item, builder, data, children.Template, text, children.HasChildren, children.Expanded, children.Selected);
builder.CloseComponent();
}
});
item.RenderChildContent(childContent);
if(AllowCheckBoxes && AllowCheckChildren && args.Children.Data != null)
{
if (CheckedValues != null && CheckedValues.Contains(item.Value))
{
await SetCheckedValues(CheckedValues.Union(args.Children.Data.Cast<object>().Except(UncheckedValues)));
}
else
{
await SetCheckedValues(CheckedValues.Except(args.Children.Data.Cast<object>()));
}
}
}
}

View File

@@ -1,11 +1,15 @@
@using Radzen
@implements IDisposable
<li class="rz-treenode">
<div class="@($"rz-treenode-content {(selected ? "rz-treenode-content-selected" : "")}")" @onclick="@Select">
@if (ChildContent != null || HasChildren)
{
<span class="@($"rz-tree-toggler rzi {(expanded ? "rzi-caret-down" : "rzi-caret-right")}")" @onclick="@Toggle" @onclick:stopPropagation></span>
}
@if(Tree != null && Tree.AllowCheckBoxes)
{
<RadzenCheckBox TValue="bool?" Value="@IsChecked()" Change="@CheckedChange" Style="@(ParentItem != null && !HasChildren ? "margin-left:25px;margin-right:5px;" : "margin-right:5px;")" />
}
@if (Template != null)
{
@Template(this)
@@ -51,6 +55,59 @@
[CascadingParameter]
public RadzenTree Tree { get; set; }
RadzenTreeItem _parentItem;
[Parameter]
public RadzenTreeItem ParentItem
{
get
{
return _parentItem;
}
set
{
if (_parentItem != value)
{
_parentItem = value;
if (_parentItem != null)
{
_parentItem.AddItem(this);
}
}
}
}
internal List<RadzenTreeItem> items = new List<RadzenTreeItem>();
internal void AddItem(RadzenTreeItem item)
{
if (items.IndexOf(item) == -1)
{
items.Add(item);
}
}
internal void RemoveItem(RadzenTreeItem item)
{
if (items.IndexOf(item) != -1)
{
items.Remove(item);
}
}
public void Dispose()
{
if (ParentItem != null)
{
ParentItem.RemoveItem(this);
}
else if(Tree != null)
{
Tree.RemoveItem(this);
}
}
async Task Toggle()
{
expanded = !expanded;
@@ -93,6 +150,11 @@
{
Tree?.SelectItem(this);
}
if (Tree != null && ParentItem == null)
{
Tree.AddItem(this);
}
}
public override async Task SetParametersAsync(ParameterView parameters)
@@ -130,4 +192,123 @@
await base.SetParametersAsync(parameters);
}
async Task CheckedChange(bool? value)
{
if (Tree != null)
{
var checkedValues = GetCheckedValues();
if (Tree.AllowCheckChildren)
{
if (value == true)
{
var valueAndChildren = GetValueAndAllChildValues();
checkedValues = checkedValues.Union(valueAndChildren);
Tree.SetUncheckedValues(Tree.UncheckedValues.Except(valueAndChildren));
}
else
{
var valueAndChildren = GetValueAndAllChildValues();
checkedValues = checkedValues.Except(valueAndChildren);
Tree.SetUncheckedValues(valueAndChildren.Union(Tree.UncheckedValues));
}
}
else
{
if (value == true)
{
var valueWithoutChildren = new[] { Value };
checkedValues = checkedValues.Union(valueWithoutChildren);
Tree.SetUncheckedValues(Tree.UncheckedValues.Except(valueWithoutChildren));
}
else
{
var valueWithoutChildren = new[] { Value };
checkedValues = checkedValues.Except(valueWithoutChildren);
Tree.SetUncheckedValues(valueWithoutChildren.Union(Tree.UncheckedValues));
}
}
if (Tree.AllowCheckParents)
{
checkedValues = UpdateCheckedValuesWithParents(checkedValues, value);
}
await Tree.SetCheckedValues(checkedValues);
}
}
bool? IsChecked()
{
var checkedValues = GetCheckedValues();
if(HasChildren && IsOneChildUnchecked() && IsOneChildChecked())
{
return null;
}
return checkedValues.Contains(Value);
}
IEnumerable<object> GetCheckedValues()
{
return Tree.CheckedValues != null ? Tree.CheckedValues : Enumerable.Empty<object>();
}
IEnumerable<object> GetAllChildValues(Func<object, bool> predicate = null)
{
var children = items.Concat(items.SelectManyRecursive(i => i.items)).Select(i => i.Value);
return predicate != null ? children.Where(predicate) : children;
}
IEnumerable<object> GetValueAndAllChildValues()
{
return new object[] { Value }.Concat(GetAllChildValues());
}
bool AreAllChildrenChecked(Func<object, bool> predicate = null)
{
var checkedValues = GetCheckedValues();
return GetAllChildValues(predicate).All(i => checkedValues.Contains(i));
}
bool AreAllChildrenUnchecked(Func<object, bool> predicate = null)
{
var checkedValues = GetCheckedValues();
return GetAllChildValues(predicate).All(i => !checkedValues.Contains(i));
}
bool IsOneChildUnchecked()
{
var checkedValues = GetCheckedValues();
return GetAllChildValues().Any(i => !checkedValues.Contains(i));
}
bool IsOneChildChecked()
{
var checkedValues = GetCheckedValues();
return GetAllChildValues().Any(i => checkedValues.Contains(i));
}
IEnumerable<object> UpdateCheckedValuesWithParents(IEnumerable<object> checkedValues, bool? value)
{
var p = ParentItem;
while (p != null)
{
if (value == false && p.AreAllChildrenUnchecked(i => !object.Equals(i, Value)))
{
checkedValues = checkedValues.Except(new object[] { p.Value });
}
else if (value == true && p.AreAllChildrenChecked(i => !object.Equals(i, Value)))
{
checkedValues = checkedValues.Union(new object[] { p.Value });
}
p = p.ParentItem;
}
return checkedValues;
}
}

View File

@@ -4,6 +4,7 @@
<div class="rz-events">
@{
var eventGroups = AppointmentGroups();
var lefts = new Dictionary<AppointmentData, double>();
}
@for (var date = StartDate; date < EndDate; date = date.AddMinutes(30))
{
@@ -11,11 +12,19 @@
var end = start.AddMinutes(30);
var appointments = AppointmentsInSlot(start, end);
var existingLefts = ExistingLefts(lefts, appointments);
@foreach (var item in appointments)
{
var width = 90.0 / appointments.Max(data => eventGroups[Appointments.IndexOf(data)]);
var left = Array.IndexOf(appointments, item) * width;
if (!lefts.TryGetValue(item, out var left))
{
left = DetermineLeft(existingLefts, width);
lefts.Add(item, left);
existingLefts.Add(left);
}
var eventStart = item.Start < StartDate ? StartDate : item.Start;
var eventEnd = item.End > EndDate ? EndDate : item.End;
var length = eventStart.Subtract(StartDate).TotalMinutes / 30;
@@ -62,6 +71,32 @@
return Appointments.Where(item => Scheduler.IsAppointmentInRange(item, start, end)).OrderBy(item => item.Start).ThenByDescending(item => item.End).ToArray();
}
double DetermineLeft(HashSet<double> existingLefts, double width)
{
double left = 0;
while (existingLefts.Contains(left))
{
left += width;
}
return left;
}
HashSet<double> ExistingLefts(IDictionary<AppointmentData, double> lefts, IEnumerable<AppointmentData> appointments)
{
var existingLefts = new HashSet<double>();
foreach (var appointment in appointments)
{
if (lefts.TryGetValue(appointment, out var existingLeft))
{
existingLefts.Add(existingLeft);
}
}
return existingLefts;
}
private IDictionary<int, int> AppointmentGroups()
{
var groups = new Dictionary<int, int>();

View File

@@ -1,5 +1,3 @@
@implements IDisposable
<div class="rz-dialog-wrapper">
<div class="rz-dialog" role="dialog" aria-labelledby="rz-dialog-0-label" style=@Style>
@if (Dialog.Options.ShowTitle)
@@ -32,11 +30,6 @@
[Parameter]
public Dialog Dialog { get; set; }
public void Dispose()
{
Service.DidCloseDialog();
}
RenderFragment ChildContent => new RenderFragment(builder =>
{
builder.OpenComponent(0, Dialog.Type);

View File

@@ -44,6 +44,9 @@
{
base.Dispose();
JSRuntime.InvokeVoidAsync("Radzen.destroyPopup", GetId());
if (IsJSRuntimeAvailable)
{
JSRuntime.InvokeVoidAsync("Radzen.destroyPopup", GetId());
}
}
}

View File

@@ -2,6 +2,7 @@
@import 'components/blazor/icons';
@import 'components/blazor/common';
@import 'components/blazor/button';
@import 'components/blazor/badge';
@import 'components/blazor/input';
@import 'components/blazor/header';
@import 'components/blazor/footer';
@@ -56,4 +57,5 @@
@import 'components/blazor/link';
@import 'components/blazor/editor';
@import 'components/blazor/colorpicker';
@import 'components/blazor/splitter';

View File

@@ -0,0 +1,57 @@
$badge-pill-border-radius: $border-radius !default;
$badge-styles: () !default;
$badge-styles: map-merge(
(
primary: (
background-color: $primary
),
light: (
background-color: $light,
color: $charcoal-grey
),
secondary: (
background-color: $secondary
),
info: (
background-color: $info
),
warning: (
background-color: $warning
),
error: (
background-color: $danger
),
danger: (
background-color: $danger
),
success: (
background-color: $success
)
),
$badge-styles
);
.rz-badge {
color: $white;
display: inline-block;
padding: .25em .4em;
font-size: 75%;
font-weight: 700;
line-height: 1;
text-align: center;
white-space: nowrap;
}
@each $style, $badge in $badge-styles {
.rz-badge-#{$style} {
@each $name, $value in $badge {
#{$name}: #{$value};
}
}
}
.rz-badge-pill {
border-radius: $badge-pill-border-radius;
}

View File

@@ -113,7 +113,7 @@ $dialog-border-radius: $border-radius !default;
height: 100%;
top: 0;
bottom: 0;
z-index: 1000;
z-index: 1001;
align-items: center;
justify-content: center;

View File

@@ -612,7 +612,7 @@ $grid-button-line-height: $grid-button-height !default;
right: 0;
bottom: 0;
background-color: $grid-loading-indicator-background-color;
z-index: 1;
z-index: 2;
}
.rz-datatable-loading-content {
@@ -712,7 +712,6 @@ $grid-button-line-height: $grid-button-height !default;
}
.rz-data-grid {
border: 1px solid #ccc;
display: flex;
flex-direction: column;
}
@@ -776,6 +775,43 @@ $grid-button-line-height: $grid-button-height !default;
}
}
.rz-grid-table tbody > ::deep div {
.rz-grid-table tbody > div {
display: table-row;
}
.rz-column-drag {
@extend .rzi;
cursor: grab;
font-size: small;
&:after {
content: 'more_vert';
}
&:active {
cursor: grabbing;
}
}
.rz-column-draggable {
background-color: $grid-header-background-color;
}
.rz-group-header {
background-color: $grid-header-background-color;
padding: 15px;
border-bottom: $grid-cell-border;
}
.rz-group-header-item {
border: $grid-cell-border;
padding: 10px;
margin:5px;
width: fit-content;
float:left;
}
.rz-group-header-item-title {
margin-right: 5px;
}

View File

@@ -14,6 +14,7 @@ $rating-disabled-color: $cool-grey !default;
a {
text-decoration: none;
cursor: default;
outline: none;
}
@@ -44,8 +45,9 @@ $rating-disabled-color: $cool-grey !default;
}
}
.rz-rating:not(.rz-state-disabled) {
.rz-rating:not(.rz-state-disabled):not(.rz-state-readonly) {
.rzi-star-o {
cursor: pointer;
&:hover {
color: $rating-selected-color;

View File

@@ -0,0 +1,148 @@
$splitter-bar-color: #6A6A6A !default;
$splitter-bar-color-active: #fff !default;
$splitter-bar-background-color: #E6ECEF !default;
$splitter-bar-background-color-active: #479CC8 !default;
$splitter-bar-hover-opacity: 1 !default;
.rz-splitter {
display: flex;
flex-wrap: nowrap;
width: 100%;
height: 100%;
> .rz-splitter-bar {
flex: 0 0 auto;
position: relative;
text-align: center;
display: inline-flex;
align-items: center;
justify-content: center;
color: $splitter-bar-color;
background-color: $splitter-bar-background-color;
opacity: 0.4;
user-select: none;
> .rz-collapse {
display: table;
&:before {
font-family: 'Material Icons';
line-height: normal;
display: table-cell;
}
&:hover {
cursor: pointer;
}
}
> .rz-resize {
border: 1px solid $splitter-bar-color;
border-radius: 1px;
}
> .rz-expand {
display: table;
&:before {
font-family: 'Material Icons';
line-height: normal;
display: table-cell;
}
&:hover {
cursor: pointer;
}
}
&-resizable:hover {
background-color: $splitter-bar-background-color;
opacity: $splitter-bar-hover-opacity;
}
&-resizable:active {
background-color: $splitter-bar-background-color-active;
opacity: $splitter-bar-hover-opacity;
> .rz-expand, > .rz-resize, > .rz-collapse {
color: $splitter-bar-color-active;
}
> .rz-resize {
border: 1px solid $splitter-bar-color-active;
}
}
&-resizable:disabled {
opacity: 0.2;
}
}
&-horizontal {
flex-direction: row;
> .rz-splitter-bar {
flex-direction: column;
width: 8px;
> .rz-collapse:before {
content: 'arrow_left';
}
> .rz-resize {
height: 16px;
margin: 2px 0;
}
> .rz-expand:before {
content: 'arrow_right';
}
&-resizable:hover {
cursor: col-resize;
}
}
}
&-vertical {
flex-direction: column;
> .rz-splitter-bar {
flex-direction: row;
height: 8px;
> .rz-collapse:before {
content: 'arrow_drop_up'
}
> .rz-resize {
width: 16px;
margin: 0 2px;
}
> .rz-expand:before {
content: 'arrow_drop_down'
}
&-resizable:hover {
cursor: row-resize;
}
}
}
&-pane {
overflow: hidden;
position: relative;
flex: 0 0 auto;
&-collapsed {
flex: 0 1 0% !important;
overflow: hidden !important;
display: block !important;
}
&-lastresizable {
flex: 1 1 auto;
}
}
}

View File

@@ -258,6 +258,11 @@ $editor-button-background-color: $default-background-color !default;
$editor-button-selected-color: $white !default;
$editor-separator-background-color: $body-color !default;
// Splitter
$splitter-bar-color: #fff !default;
$splitter-bar-background-color: #4A5A63 !default;
$splitter-bar-hover-opacity: 0.8 !default;
@import 'fonts';
@import 'typography';
@import 'components';

View File

@@ -258,6 +258,11 @@ $editor-button-background-color: $default-background-color !default;
$editor-button-selected-color: $white !default;
$editor-separator-background-color: $body-color !default;
// Splitter
$splitter-bar-color: #fff !default;
$splitter-bar-background-color: #4A5A63 !default;
$splitter-bar-hover-opacity: 0.8 !default;
@import 'bootstrap';
@import 'fonts';
@import 'typography';

View File

@@ -56,6 +56,9 @@ $slider-handle-hover-background-color: $secondary-hover;
$dropdown-item-hover-background-color: $secondary-hover;
$radio-checked-hover-background-color: $secondary-hover;
// Splitter
$splitter-bar-background-color-active: #3BA5FC !default;
@import 'fonts';
@import 'typography';
@import 'components';

View File

@@ -56,6 +56,9 @@ $slider-handle-hover-background-color: $secondary-hover;
$dropdown-item-hover-background-color: $secondary-hover;
$radio-checked-hover-background-color: $secondary-hover;
// Splitter
$splitter-bar-background-color-active: #3BA5FC !default;
@import 'bootstrap';
@import 'fonts';
@import 'typography';

View File

@@ -59,6 +59,9 @@ $radio-checked-hover-background-color: $secondary-hover;
// SplitButton
$splitbutton-menu-button-border: 1px solid #475359;
// Splitter
$splitter-bar-background-color-active: #598087 !default;
@import 'fonts';
@import 'typography';
@import 'components';

View File

@@ -59,6 +59,9 @@ $radio-checked-hover-background-color: $secondary-hover;
// SplitButton
$splitbutton-menu-button-border: 1px solid #475359;
// Splitter
$splitter-bar-background-color-active: #598087 !default;
@import 'bootstrap';
@import 'fonts';
@import 'typography';

View File

@@ -129,7 +129,9 @@ window.Radzen = {
return false;
}
};
el.addEventListener('keydown', preventDefault, false);
if (el) {
el.addEventListener('keydown', preventDefault, false);
}
},
loadGoogleMaps: function (defaultView, apiKey, resolve, reject) {
resolveCallbacks.push(resolve);
@@ -590,10 +592,33 @@ window.Radzen = {
}
return popups;
},
repositionPopup: function (parent, id) {
var popup = document.getElementById(id);
if (!popup) return;
var rect = popup.getBoundingClientRect();
var parentRect = parent ? parent.getBoundingClientRect() : { top: 0, bottom: 0, left: 0, right: 0, width: 0, height: 0 };
if (/Edge/.test(navigator.userAgent)) {
var scrollTop = document.body.scrollTop;
} else {
var scrollTop = document.documentElement.scrollTop;
}
var top = parentRect.bottom + scrollTop;
if (top + rect.height > window.innerHeight && parentRect.top > rect.height) {
top = parentRect.top - rect.height + scrollTop;
}
popup.style.top = top + 'px';
},
openPopup: function (parent, id, syncWidth, position, x, y, instance, callback) {
var popup = document.getElementById(id);
if (!popup) return;
Radzen.activeElement = document.activeElement;
var parentRect = parent ? parent.getBoundingClientRect() : { top: y || 0, bottom: 0, left: x || 0, right: 0, width: 0, height: 0 };
if (/Edge/.test(navigator.userAgent)) {
@@ -604,8 +629,8 @@ window.Radzen = {
var scrollTop = document.documentElement.scrollTop;
}
var top = y ? y + scrollTop: parentRect.bottom + scrollTop;
var left = x ? x + scrollLeft: parentRect.left + scrollLeft;
var top = y ? y : parentRect.bottom;
var left = x ? x : parentRect.left;
if (syncWidth) {
popup.style.width = parentRect.width + 'px';
@@ -620,12 +645,8 @@ window.Radzen = {
var smartPosition = !position || position == 'bottom';
if (
smartPosition &&
top + rect.height > window.innerHeight &&
parentRect.top > rect.height
) {
top = parentRect.top - rect.height + scrollTop;
if (smartPosition && top + rect.height > window.innerHeight && parentRect.top > rect.height) {
top = parentRect.top - rect.height;
if (position) {
top = top - 40;
@@ -638,12 +659,8 @@ window.Radzen = {
}
}
if (
smartPosition &&
left + rect.width - scrollLeft > window.innerWidth &&
window.innerWidth > rect.width
) {
left = window.innerWidth - rect.width + scrollLeft;
if (smartPosition && left + rect.width > window.innerWidth && window.innerWidth > rect.width) {
left = window.innerWidth - rect.width;
if (position) {
var tooltipContent = popup.children[0];
@@ -651,8 +668,8 @@ window.Radzen = {
if (tooltipContent.classList.contains(tooltipContentClassName)) {
tooltipContent.classList.remove(tooltipContentClassName);
tooltipContent.classList.add('rz-left-tooltip-content');
left = parentRect.left - rect.width - 5 + scrollLeft;
top = parentRect.top - parentRect.height + scrollTop;
left = parentRect.left - rect.width - 5;
top = parentRect.top - parentRect.height;
}
}
}
@@ -661,30 +678,26 @@ window.Radzen = {
if (position) {
top = top + 20;
}
popup.style.top = top + 'px';
}
if (smartPosition) {
popup.style.left = left + 'px';
}
if (position == 'left') {
popup.style.left = parentRect.left - rect.width - 5 + 'px';
popup.style.top = parentRect.top + scrollTop + 'px';
left = parentRect.left - rect.width - 5;
top = parentRect.top;
}
if (position == 'right') {
popup.style.left = parentRect.right + 10 + 'px';
popup.style.top = parentRect.top + scrollTop + 'px';
left = parentRect.right + 10;
top = parentRect.top;
}
if (position == 'top') {
popup.style.top = parentRect.top + scrollTop - rect.height + 5 + 'px';
popup.style.left = parentRect.left + scrollLeft + 'px';
top = parentRect.top - rect.height + 5;
left = parentRect.left;
}
popup.style.zIndex = 1000;
popup.style.zIndex = 2000;
popup.style.left = left + scrollLeft + 'px';
popup.style.top = top + scrollTop + 'px';
if (!popup.classList.contains('rz-overlaypanel')) {
popup.classList.add('rz-popup');
@@ -693,7 +706,7 @@ window.Radzen = {
Radzen[id] = function (e) {
if (!e.defaultPrevented) {
if (parent) {
if (!parent.contains(e.target) && !popup.contains(e.target)) {
if (e.type == 'click' && !parent.contains(e.target) && !popup.contains(e.target)) {
Radzen.closePopup(id, instance, callback);
}
} else {
@@ -704,10 +717,32 @@ window.Radzen = {
}
};
if (!Radzen.closePopupsOnScroll) {
Radzen.closePopupsOnScroll = function (e) {
for (var i = 0; i < Radzen.popups.length; i++) {
var p = Radzen.popups[i];
Radzen.closePopup(p.id, p.instance, p.callback);
}
Radzen.popups = [];
};
Radzen.popups = [];
}
Radzen.popups.push({id, instance, callback});
document.body.appendChild(popup);
document.removeEventListener('click', Radzen[id]);
document.addEventListener('click', Radzen[id]);
var p = parent;
while (p && p != document.body) {
if (p.scrollWidth > p.clientWidth || p.scrollHeight > p.clientHeight) {
p.removeEventListener('scroll', Radzen.closePopupsOnScroll);
p.addEventListener('scroll', Radzen.closePopupsOnScroll);
}
p = p.parentElement;
}
if (!parent) {
document.removeEventListener('contextmenu', Radzen[id]);
document.addEventListener('contextmenu', Radzen[id]);
@@ -715,6 +750,9 @@ window.Radzen = {
},
closePopup: function (id, instance, callback) {
var popup = document.getElementById(id);
if (!popup) return;
if (popup.style.display == 'none') return;
if (popup) {
popup.style.display = 'none';
}
@@ -724,6 +762,11 @@ window.Radzen = {
if (instance) {
instance.invokeMethodAsync(callback);
}
if (Radzen.activeElement && Radzen.activeElement == document.activeElement || Radzen.activeElement && document.activeElement == document.body) {
Radzen.activeElement.focus();
Radzen.activeElement = null;
}
},
togglePopup: function (parent, id, syncWidth, instance, callback) {
var popup = document.getElementById(id);
@@ -761,13 +804,29 @@ window.Radzen = {
}
}
},
openDialog: function () {
openDialog: function (options) {
if (
document.documentElement.scrollHeight >
document.documentElement.clientHeight
) {
document.body.classList.add('no-scroll');
}
if (options.autoFocusFirstElement) {
setTimeout(function () {
var dialogs = document.querySelectorAll('.rz-dialog-content');
if (dialogs.length == 0) return;
var lastDialog = dialogs[dialogs.length - 1];
if (lastDialog) {
var focusable = lastDialog.querySelectorAll('button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])');
var firstFocusable = focusable[0];
if (firstFocusable) {
firstFocusable.focus();
}
}
}, 500);
}
},
closeDialog: function () {
document.body.classList.remove('no-scroll');
@@ -1115,6 +1174,43 @@ window.Radzen = {
document.removeEventListener('touchmove', ref.touchMoveHandler)
document.removeEventListener('touchend', ref.mouseUpHandler);
},
startColumnReorder: function(id) {
var el = document.getElementById(id);
var cell = el.parentNode.parentNode;
var visual = document.createElement("th");
visual.className = cell.className + ' rz-column-draggable';
visual.style = cell.style;
visual.style.display = 'none';
visual.style.position = 'absolute';
visual.style.height = cell.offsetHeight + 'px';
visual.style.width = cell.offsetWidth + 'px';
visual.style.zIndex = 2000;
visual.innerHTML = cell.innerHTML;
visual.id = id + 'visual';
document.body.appendChild(visual);
Radzen[id + 'end'] = function (e) {
var el = document.getElementById(id + 'visual');
if (el) {
document.body.removeChild(el);
Radzen[id + 'end'] = null;
Radzen[id + 'move'] = null;
}
}
document.removeEventListener('click', Radzen[id + 'end']);
document.addEventListener('click', Radzen[id + 'end']);
Radzen[id + 'move'] = function (e) {
var el = document.getElementById(id + 'visual');
if (el) {
el.style.display = 'block';
el.style.top = e.clientY + 10 + 'px';
el.style.left = e.clientX + 10 + 'px';
}
}
document.removeEventListener('mousemove', Radzen[id + 'move']);
document.addEventListener('mousemove', Radzen[id + 'move']);
},
startColumnResize: function(id, grid, columnIndex, clientX) {
var el = document.getElementById(id);
var cell = el.parentNode.parentNode;
@@ -1165,5 +1261,140 @@ window.Radzen = {
document.addEventListener('mouseup', Radzen[el].mouseUpHandler);
document.addEventListener('touchmove', Radzen[el].touchMoveHandler, { passive: true })
document.addEventListener('touchend', Radzen[el].mouseUpHandler, { passive: true });
}
},
startSplitterResize: function(id,
splitter,
paneId,
paneNextId,
orientation,
clientPos,
minValue,
maxValue,
minNextValue,
maxNextValue) {
var el = document.getElementById(id);
var pane = document.getElementById(paneId);
var paneNext = document.getElementById(paneNextId);
var paneLength;
var paneNextLength;
var panePerc;
var paneNextPerc;
var isHOrientation=orientation == 'Horizontal';
var totalLength = 0.0;
Array.from(el.children).forEach(element => {
totalLength += isHOrientation
? element.getBoundingClientRect().width
: element.getBoundingClientRect().height;
});
if (pane) {
paneLength = isHOrientation
? pane.getBoundingClientRect().width
: pane.getBoundingClientRect().height;
panePerc = (paneLength / totalLength * 100) + '%';
}
if (paneNext) {
paneNextLength = isHOrientation
? paneNext.getBoundingClientRect().width
: paneNext.getBoundingClientRect().height;
paneNextPerc = (paneNextLength / totalLength * 100) + '%';
}
function ensurevalue(value) {
if (!value)
return null;
value=value.trim().toLowerCase();
if (value.endsWith("%"))
return totalLength*parseFloat(value)/100;
if (value.endsWith("px"))
return parseFloat(value);
throw 'Invalid value';
}
minValue=ensurevalue(minValue);
maxValue=ensurevalue(maxValue);
minNextValue=ensurevalue(minNextValue);
maxNextValue=ensurevalue(maxNextValue);
Radzen[el] = {
clientPos: clientPos,
panePerc: parseFloat(panePerc),
paneNextPerc: isFinite(parseFloat(paneNextPerc)) ? parseFloat(paneNextPerc) : 0,
paneLength: paneLength,
paneNextLength: isFinite(paneNextLength) ? paneNextLength : 0,
mouseUpHandler: function(e) {
if (Radzen[el]) {
splitter.invokeMethodAsync(
'RadzenSplitter.OnPaneResized',
parseInt(pane.getAttribute('data-index')),
parseFloat(pane.style.flexBasis),
paneNext ? parseInt(paneNext.getAttribute('data-index')) : null,
paneNext ? parseFloat(paneNext.style.flexBasis) : null
);
document.removeEventListener('mousemove', Radzen[el].mouseMoveHandler);
document.removeEventListener('mouseup', Radzen[el].mouseUpHandler);
document.removeEventListener('touchmove', Radzen[el].touchMoveHandler);
document.removeEventListener('touchend', Radzen[el].mouseUpHandler);
Radzen[el] = null;
}
},
mouseMoveHandler: function(e) {
if (Radzen[el]) {
var spacePerc = Radzen[el].panePerc + Radzen[el].paneNextPerc;
var spaceLength = Radzen[el].paneLength + Radzen[el].paneNextLength;
var length = (Radzen[el].paneLength -
(Radzen[el].clientPos - (isHOrientation ? e.clientX : e.clientY)));
if (length > spaceLength)
length = spaceLength;
if (minValue && length < minValue) length = minValue;
if (maxValue && length > maxValue) length = maxValue;
if (paneNext) {
var nextSpace=spaceLength-length;
if (minNextValue && nextSpace < minNextValue) length = spaceLength-minNextValue;
if (maxNextValue && nextSpace > maxNextValue) length = spaceLength+maxNextValue;
}
var perc = length / Radzen[el].paneLength;
if (!isFinite(perc)) {
perc = 1;
Radzen[el].panePerc = 0.1;
Radzen[el].paneLength =isHOrientation
? pane.getBoundingClientRect().width
: pane.getBoundingClientRect().height;
}
var newPerc = Radzen[el].panePerc * perc;
if (newPerc < 0) newPerc = 0;
if (newPerc > 100) newPerc = 100;
pane.style.flexBasis = newPerc + '%';
if (paneNext)
paneNext.style.flexBasis = (spacePerc - newPerc) + '%';
}
},
touchMoveHandler: function(e) {
if (e.targetTouches[0]) {
Radzen[el].mouseMoveHandler(e.targetTouches[0]);
}
}
};
document.addEventListener('mousemove', Radzen[el].mouseMoveHandler);
document.addEventListener('mouseup', Radzen[el].mouseUpHandler);
document.addEventListener('touchmove', Radzen[el].touchMoveHandler, { passive: true });
document.addEventListener('touchend', Radzen[el].mouseUpHandler, { passive: true });
}
};

View File

@@ -0,0 +1,42 @@
@page "/badge"
<RadzenExample Name="Badge" Documentation="false">
<h3>Badges</h3>
<RadzenBadge BadgeStyle="BadgeStyle.Primary" Text="Primary" />
<RadzenBadge BadgeStyle="BadgeStyle.Secondary" Text="Secondary" />
<RadzenBadge BadgeStyle="BadgeStyle.Light" Text="Light" />
<RadzenBadge BadgeStyle="BadgeStyle.Success" Text="Success" />
<RadzenBadge BadgeStyle="BadgeStyle.Danger" Text="Danger" />
<RadzenBadge BadgeStyle="BadgeStyle.Warning" Text="Warning" />
<RadzenBadge BadgeStyle="BadgeStyle.Info" Text="Info" />
<h3 style="margin-top:20px">Pills</h3>
<RadzenBadge BadgeStyle="BadgeStyle.Primary" IsPill="true" Text="Primary" />
<RadzenBadge BadgeStyle="BadgeStyle.Secondary" IsPill="true" Text="Secondary" />
<RadzenBadge BadgeStyle="BadgeStyle.Light" IsPill="true" Text="Light" />
<RadzenBadge BadgeStyle="BadgeStyle.Success" IsPill="true" Text="Success" />
<RadzenBadge BadgeStyle="BadgeStyle.Danger" IsPill="true" Text="Danger" />
<RadzenBadge BadgeStyle="BadgeStyle.Warning" IsPill="true" Text="Warning" />
<RadzenBadge BadgeStyle="BadgeStyle.Info" IsPill="true" Text="Info" />
<h3 style="margin-top:20px">In Button</h3>
<RadzenButton ButtonStyle="ButtonStyle.Info">
Button
<RadzenBadge BadgeStyle="BadgeStyle.Primary" Text="15" />
</RadzenButton>
<RadzenButton ButtonStyle="ButtonStyle.Light">
Button
<RadzenBadge BadgeStyle="BadgeStyle.Primary" IsPill="@true" Text="15" />
</RadzenButton>
<h3 style="margin-top:20px">Child Content</h3>
<RadzenBadge BadgeStyle="BadgeStyle.Primary">
Childcontent
</RadzenBadge>
</RadzenExample>
@code {
}

View File

@@ -8,7 +8,7 @@
<h1>DataGrid <strong>Advanced Filter Mode</strong></h1>
<RadzenExample Name="DataGridAdvancedFilter" Heading="false">
<RadzenExample Name="DataGridAdvancedFilter" Heading="false" Documentation="false">
<RadzenDataGrid AllowFiltering="true" AllowColumnResize="true"
FilterMode="FilterMode.Advanced" PageSize="5" AllowPaging="true" AllowSorting="true" Data="@employees" TItem="Employee" ColumnWidth="300px"
FilterCaseSensitivity="FilterCaseSensitivity.CaseInsensitive"
@@ -17,7 +17,7 @@
<RadzenDataGridColumn TItem="Employee" Property="EmployeeID" Filterable="false" Title="ID" Frozen="true" Width="50px" TextAlign="TextAlign.Center" />
<RadzenDataGridColumn TItem="Employee" Title="Photo" Sortable="false" Filterable="false" Width="200px" >
<Template Context="data">
<RadzenImage Path="@data.Photo" style="width: 32px; height: 32px; border-radius: 50%;" />
<RadzenImage Path="@data.Photo" style="width: 40px; height: 40px; border-radius: 8px;" />
</Template>
</RadzenDataGridColumn>
<RadzenDataGridColumn TItem="Employee" Property="FirstName" Title="First Name" />

View File

@@ -0,0 +1,58 @@
@page "/datagrid-column-reorder"
@using RadzenBlazorDemos.Data
@using RadzenBlazorDemos.Models.Northwind
@using Microsoft.EntityFrameworkCore
@inject NorthwindContext dbContext
<h1>DataGrid</h1>
<p>Enable column reorder by setting the AllowColumnReorder property to true.</p
<RadzenExample Name="DataGrid" Heading="false" Documentation="false">
<RadzenButton Text="Change page state" Click="@((args) => { StateHasChanged(); })" Style="margin-bottom:20px" />
<RadzenDataGrid AllowColumnReorder="true" ColumnReordered="@OnColumnReordered"
AllowFiltering="true" AllowColumnResize="true" FilterMode="FilterMode.Advanced" PageSize="5" AllowPaging="true" AllowSorting="true" Data="@employees" TItem="Employee" ColumnWidth="300px" LogicalFilterOperator="LogicalFilterOperator.Or">
<Columns>
<RadzenDataGridColumn TItem="Employee" Property="EmployeeID" Filterable="false" Title="ID" Frozen="true" Width="50px" TextAlign="TextAlign.Center" Reorderable="false" Resizable="false" />
<RadzenDataGridColumn TItem="Employee" Title="Photo" Sortable="false" Filterable="false" Width="200px" >
<Template Context="data">
<RadzenImage Path="@data.Photo" style="width: 40px; height: 40px; border-radius: 8px;" />
</Template>
</RadzenDataGridColumn>
<RadzenDataGridColumn TItem="Employee" Property="FirstName" Title="First Name" />
<RadzenDataGridColumn TItem="Employee" Property="LastName" Title="Last Name" Width="150px"/>
<RadzenDataGridColumn TItem="Employee" Property="Title" Title="Title" />
<RadzenDataGridColumn TItem="Employee" Property="TitleOfCourtesy" Title="Title Of Courtesy" />
<RadzenDataGridColumn TItem="Employee" Property="BirthDate" Title="Birth Date" FormatString="{0:d}" />
<RadzenDataGridColumn TItem="Employee" Property="HireDate" Title="Hire Date" FormatString="{0:d}" />
<RadzenDataGridColumn TItem="Employee" Property="Address" Title="Address" />
<RadzenDataGridColumn TItem="Employee" Property="City" Title="City" />
<RadzenDataGridColumn TItem="Employee" Property="Region" Title="Region" />
<RadzenDataGridColumn TItem="Employee" Property="PostalCode" Title="Postal Code" />
<RadzenDataGridColumn TItem="Employee" Property="Country" Title="Country" />
<RadzenDataGridColumn TItem="Employee" Property="HomePhone" Title="Home Phone" />
<RadzenDataGridColumn TItem="Employee" Property="Extension" Title="Extension" />
<RadzenDataGridColumn TItem="Employee" Property="Notes" Title="Notes" />
</Columns>
</RadzenDataGrid>
</RadzenExample>
<EventConsole @ref=@console />
@code {
EventConsole console;
IEnumerable<Employee> employees;
protected override void OnInitialized()
{
employees = dbContext.Employees;
}
void OnColumnReordered(DataGridColumnReorderedEventArgs<Employee> args)
{
console.Log($"Reordered {args.Column.Title}. Old index: {args.OldIndex}, New index: {args.NewIndex}");
}
}

View File

@@ -10,13 +10,13 @@
<p>Enable column resizing by setting the AllowColumnResizing property to true.</p
<RadzenExample Name="DataGridColumnResizing" Heading="false">
<RadzenExample Name="DataGridColumnResizing" Heading="false" Documentation="false">
<RadzenDataGrid Data="@employees" TItem="Employee" ColumnWidth="300px" AllowColumnResize="true" ColumnResized=@OnColumnResized>
<Columns>
<RadzenDataGridColumn TItem="Employee" Property="EmployeeID" Title="ID" Width="50px" TextAlign="TextAlign.Center" />
<RadzenDataGridColumn TItem="Employee" Title="Photo" Sortable="false" Width="200px" >
<Template Context="data">
<RadzenImage Path="@data.Photo" style="width: 32px; height: 32px; border-radius: 50%;" />
<RadzenImage Path="@data.Photo" style="width: 40px; height: 40px; border-radius: 8px;" />
</Template>
</RadzenDataGridColumn>
<RadzenDataGridColumn TItem="Employee" Property="FirstName" Title="First Name" />

View File

@@ -32,7 +32,7 @@
<RadzenDataGridColumn Width="200px" TItem="Order" Property="Customer.CompanyName" Title="Customer" />
<RadzenDataGridColumn TItem="Order" Property="Employee.LastName" Title="Employee">
<Template Context="order">
<RadzenImage Path="@order.Employee?.Photo" style="width: 32px; height: 32px; border-radius: 50%" />
<RadzenImage Path="@order.Employee?.Photo" style="width: 40px; height: 40px; border-radius: 8px;" />
@order.Employee?.FirstName @order.Employee?.LastName
</Template>
</RadzenDataGridColumn>

View File

@@ -0,0 +1,94 @@
@page "/datagrid-empty"
@using RadzenBlazorDemos.Models.Northwind
<h1>Empty DataGrid</h1>
<RadzenExample Name="DataGridEmpty" Heading="false" Documentation="false">
<h2>Using Default Empty Text</h2>
<RadzenDataGrid TItem="Employee" Data="@data">
<Columns>
<RadzenDataGridColumn TItem="Employee" Property="EmployeeID" Title="ID" Width="50px" TextAlign="TextAlign.Center" />
<RadzenDataGridColumn TItem="Employee" Title="Photo" Sortable="false" Width="200px" >
<Template Context="data">
<RadzenImage Path="@data.Photo" style="width: 40px; height: 40px; border-radius: 8px;" />
</Template>
</RadzenDataGridColumn>
<RadzenDataGridColumn TItem="Employee" Property="FirstName" Title="First Name" />
<RadzenDataGridColumn TItem="Employee" Property="LastName" Title="Last Name" Width="150px"/>
<RadzenDataGridColumn TItem="Employee" Property="Title" Title="Title" />
<RadzenDataGridColumn TItem="Employee" Property="TitleOfCourtesy" Title="Title Of Courtesy" />
<RadzenDataGridColumn TItem="Employee" Property="BirthDate" Title="Birth Date" FormatString="{0:d}" />
<RadzenDataGridColumn TItem="Employee" Property="HireDate" Title="Hire Date" FormatString="{0:d}" />
<RadzenDataGridColumn TItem="Employee" Property="Address" Title="Address" />
<RadzenDataGridColumn TItem="Employee" Property="City" Title="City" />
<RadzenDataGridColumn TItem="Employee" Property="Region" Title="Region" />
<RadzenDataGridColumn TItem="Employee" Property="PostalCode" Title="Postal Code" />
<RadzenDataGridColumn TItem="Employee" Property="Country" Title="Country" />
<RadzenDataGridColumn TItem="Employee" Property="HomePhone" Title="Home Phone" />
<RadzenDataGridColumn TItem="Employee" Property="Extension" Title="Extension" />
<RadzenDataGridColumn TItem="Employee" Property="Notes" Title="Notes" />
</Columns>
</RadzenDataGrid>
<h2>Using Custom Empty Text</h2>
<RadzenTextBox @bind-Value="emptyText" />
<RadzenDataGrid TItem="Employee" Data="@data" EmptyText="@emptyText">
<Columns>
<RadzenDataGridColumn TItem="Employee" Property="EmployeeID" Title="ID" Width="50px" TextAlign="TextAlign.Center" />
<RadzenDataGridColumn TItem="Employee" Title="Photo" Sortable="false" Width="200px" >
<Template Context="data">
<RadzenImage Path="@data.Photo" style="width: 40px; height: 40px; border-radius: 8px;" />
</Template>
</RadzenDataGridColumn>
<RadzenDataGridColumn TItem="Employee" Property="FirstName" Title="First Name" />
<RadzenDataGridColumn TItem="Employee" Property="LastName" Title="Last Name" Width="150px"/>
<RadzenDataGridColumn TItem="Employee" Property="Title" Title="Title" />
<RadzenDataGridColumn TItem="Employee" Property="TitleOfCourtesy" Title="Title Of Courtesy" />
<RadzenDataGridColumn TItem="Employee" Property="BirthDate" Title="Birth Date" FormatString="{0:d}" />
<RadzenDataGridColumn TItem="Employee" Property="HireDate" Title="Hire Date" FormatString="{0:d}" />
<RadzenDataGridColumn TItem="Employee" Property="Address" Title="Address" />
<RadzenDataGridColumn TItem="Employee" Property="City" Title="City" />
<RadzenDataGridColumn TItem="Employee" Property="Region" Title="Region" />
<RadzenDataGridColumn TItem="Employee" Property="PostalCode" Title="Postal Code" />
<RadzenDataGridColumn TItem="Employee" Property="Country" Title="Country" />
<RadzenDataGridColumn TItem="Employee" Property="HomePhone" Title="Home Phone" />
<RadzenDataGridColumn TItem="Employee" Property="Extension" Title="Extension" />
<RadzenDataGridColumn TItem="Employee" Property="Notes" Title="Notes" />
</Columns>
</RadzenDataGrid>
<h2>Using Render Fragment as Empty Text</h2>
<RadzenDataGrid TItem="Employee" Data="@data">
<EmptyTemplate>
<p style="color: red">Empty Data Grid!</p>
</EmptyTemplate>
<Columns>
<RadzenDataGridColumn TItem="Employee" Property="EmployeeID" Title="ID" Width="50px" TextAlign="TextAlign.Center" />
<RadzenDataGridColumn TItem="Employee" Title="Photo" Sortable="false" Width="200px" >
<Template Context="data">
<RadzenImage Path="@data.Photo" style="width: 40px; height: 40px; border-radius: 8px;" />
</Template>
</RadzenDataGridColumn>
<RadzenDataGridColumn TItem="Employee" Property="FirstName" Title="First Name" />
<RadzenDataGridColumn TItem="Employee" Property="LastName" Title="Last Name" Width="150px"/>
<RadzenDataGridColumn TItem="Employee" Property="Title" Title="Title" />
<RadzenDataGridColumn TItem="Employee" Property="TitleOfCourtesy" Title="Title Of Courtesy" />
<RadzenDataGridColumn TItem="Employee" Property="BirthDate" Title="Birth Date" FormatString="{0:d}" />
<RadzenDataGridColumn TItem="Employee" Property="HireDate" Title="Hire Date" FormatString="{0:d}" />
<RadzenDataGridColumn TItem="Employee" Property="Address" Title="Address" />
<RadzenDataGridColumn TItem="Employee" Property="City" Title="City" />
<RadzenDataGridColumn TItem="Employee" Property="Region" Title="Region" />
<RadzenDataGridColumn TItem="Employee" Property="PostalCode" Title="Postal Code" />
<RadzenDataGridColumn TItem="Employee" Property="Country" Title="Country" />
<RadzenDataGridColumn TItem="Employee" Property="HomePhone" Title="Home Phone" />
<RadzenDataGridColumn TItem="Employee" Property="Extension" Title="Extension" />
<RadzenDataGridColumn TItem="Employee" Property="Notes" Title="Notes" />
</Columns>
</RadzenDataGrid>
</RadzenExample>
@code {
string emptyText = "No Items to display!";
List<Employee> data = new List<Employee>();
}

View File

@@ -10,7 +10,7 @@
<p>Set the initial filter of your RadzenDataGrid via the <code>FilterValue</code> and <code>FilterOperator</code> column properties.</p>
<RadzenExample Name="DataGridFilterApi" Heading="false">
<RadzenExample Name="DataGridFilterApi" Heading="false" Documentation="false">
<RadzenDataGrid AllowFiltering="true" AllowColumnResize="true"
FilterMode="FilterMode.Advanced" PageSize="5" AllowPaging="true" AllowSorting="true" Data="@employees" TItem="Employee" ColumnWidth="300px"
FilterCaseSensitivity="FilterCaseSensitivity.CaseInsensitive"
@@ -19,7 +19,7 @@
<RadzenDataGridColumn TItem="Employee" Property="EmployeeID" Filterable="false" Title="ID" Frozen="true" Width="50px" TextAlign="TextAlign.Center" />
<RadzenDataGridColumn TItem="Employee" Title="Photo" Sortable="false" Filterable="false" Width="200px" >
<Template Context="data">
<RadzenImage Path="@data.Photo" style="width: 32px; height: 32px; border-radius: 50%;" />
<RadzenImage Path="@data.Photo" style="width: 40px; height: 40px; border-radius: 8px;" />
</Template>
</RadzenDataGridColumn>
<RadzenDataGridColumn TItem="Employee" Property="FirstName" Title="First Name" FilterValue=@("Nan") FilterOperator="FilterOperator.StartsWith" />

View File

@@ -10,17 +10,29 @@
<p>Lock columns to prevent them from scrolling out of view via the <code>Frozen</code> property.</p>
<RadzenExample Name="DataGridFrozenColumns" Heading="false">
<RadzenDataGrid AllowFiltering="true" AllowColumnResize="true" FilterMode="FilterMode.Advanced" PageSize="5" AllowPaging="true" AllowSorting="true" Data="@employees" TItem="Employee" ColumnWidth="300px" LogicalFilterOperator="LogicalFilterOperator.Or">
<RadzenExample Name="DataGridFrozenColumns" Heading="false" Documentation="false">
<RadzenDataGrid AllowFiltering="true" AllowColumnResize="true" FilterMode="FilterMode.Advanced" AllowPaging="true" AllowSorting="true" Data="@employees" TItem="Employee"
ColumnWidth="300px" LogicalFilterOperator="LogicalFilterOperator.Or" Style="height:300px">
<Columns>
<RadzenDataGridColumn TItem="Employee" Property="EmployeeID" Filterable="false" Title="ID" Frozen="true" Width="50px" TextAlign="TextAlign.Center" />
<RadzenDataGridColumn TItem="Employee" Title="Photo" Sortable="false" Filterable="false" Width="200px" >
<RadzenDataGridColumn TItem="Employee" Title="Photo" Sortable="false" Filterable="false" Width="200px" Frozen="@frozen">
<HeaderTemplate>
<RadzenCheckBox @bind-Value="frozen" title="Pin/Unpin this column" />
</HeaderTemplate>
<Template Context="data">
<RadzenImage Path="@data.Photo" style="width: 32px; height: 32px; border-radius: 50%;" />
<RadzenImage Path="@data.Photo" style="width: 40px; height: 40px; border-radius: 8px;" />
</Template>
</RadzenDataGridColumn>
<RadzenDataGridColumn TItem="Employee" Property="FirstName" Title="First Name" Frozen="true" />
<RadzenDataGridColumn TItem="Employee" Property="LastName" Title="Last Name" Width="150px"/>
<RadzenDataGridColumn TItem="Employee" Property="FirstName" Title="First Name" Frozen="true">
<FooterTemplate>
Total employees: <b>@employees.Count()</b>
</FooterTemplate>
</RadzenDataGridColumn>
<RadzenDataGridColumn TItem="Employee" Property="LastName" Title="Last Name" Width="150px">
<FooterTemplate>
Footer
</FooterTemplate>
</RadzenDataGridColumn>
<RadzenDataGridColumn TItem="Employee" Property="Title" Title="Title" />
<RadzenDataGridColumn TItem="Employee" Property="TitleOfCourtesy" Title="Title Of Courtesy" />
<RadzenDataGridColumn TItem="Employee" Property="BirthDate" Title="Birth Date" FormatString="{0:d}" />
@@ -38,6 +50,7 @@
</RadzenExample>
@code {
IEnumerable<Employee> employees;
bool frozen;
protected override void OnInitialized()
{

View File

@@ -0,0 +1,61 @@
@page "/datagrid-group-header-template"
@using RadzenBlazorDemos.Data
@using RadzenBlazorDemos.Models.Northwind
@using Microsoft.EntityFrameworkCore
@inject NorthwindContext dbContext
<h1>DataGrid</h1>
<p>Use GroupHeaderTemplate to customize DataGrid group header rows.</p>
<RadzenExample Name="DataGrid" Heading="false" Documentation="false">
<RadzenDataGrid @ref="ordersGrid" AllowGrouping="true" AllowFiltering="true" AllowPaging="true" AllowSorting="true"
Data="@orders" TItem="Order">
<GroupHeaderTemplate>
@context.GroupDescriptor.GetTitle(): @context.Data.Key, Group items count: @context.Data.Count, Last order date: @(context.Data.Items.Cast<Order>().OrderByDescending(o => o.OrderDate).FirstOrDefault()?.OrderDate)
</GroupHeaderTemplate>
<Columns>
<RadzenDataGridColumn Width="50px" TItem="Order" Title="#" Filterable="false" Sortable="false" TextAlign="TextAlign.Center">
<Template>
@(orders.IndexOf(context) + 1)
</Template>
</RadzenDataGridColumn>
<RadzenDataGridColumn Width="200px" TItem="Order" Property="OrderID" Title="Order ID">
<FooterTemplate>
Displayed orders: <b>@ordersGrid.View.Count()</b> of <b>@orders.Count()</b>
</FooterTemplate>
</RadzenDataGridColumn>
<RadzenDataGridColumn Width="200px" TItem="Order" Property="Customer.CompanyName" Title="Customer" />
<RadzenDataGridColumn TItem="Order" Property="Employee.LastName" Title="Employee">
<Template Context="order">
@order.Employee?.FirstName @order.Employee?.LastName
</Template>
</RadzenDataGridColumn>
<RadzenDataGridColumn TItem="Order" Property="OrderDate" Title="Order Date" FormatString="{0:d}">
<FooterTemplate>
Last order date: <b>@String.Format("{0:d}", orders.OrderByDescending(o => o.OrderDate).Last().OrderDate)</b>
</FooterTemplate>
</RadzenDataGridColumn>
<RadzenDataGridColumn TItem="Order" Property="Freight" Title="Freight">
<Template Context="order">
@String.Format(new System.Globalization.CultureInfo("en-US"), "{0:C}", order.Freight)
</Template>
<FooterTemplate>
Total amount: <b>@String.Format(new System.Globalization.CultureInfo("en-US"), "{0:C}", orders.Sum(o => o.Freight))</b>
</FooterTemplate>
</RadzenDataGridColumn>
<RadzenDataGridColumn TItem="Order" Property="ShipName" Title="Ship Name" />
</Columns>
</RadzenDataGrid>
</RadzenExample>
@code {
IList<Order> orders;
RadzenDataGrid<Order> ordersGrid;
protected override void OnInitialized()
{
orders = dbContext.Orders.Include("Customer").Include("Employee").ToList();
}
}

View File

@@ -0,0 +1,56 @@
@page "/datagrid-grouping-api"
@using RadzenBlazorDemos.Data
@using RadzenBlazorDemos.Models.Northwind
@using Microsoft.EntityFrameworkCore
@inject NorthwindContext dbContext
<h1>DataGrid</h1>
<p>Set AllowGrouping="true" to enable group by column and GroupPanelText to localize the group panel text. Set Groupable="false" for column to disable grouping by that column.</p>
<RadzenExample Name="DataGrid" Heading="false" Documentation="false">
<RadzenDataGrid AllowGrouping="true" AllowFiltering="true" AllowColumnResize="true" FilterMode="FilterMode.Advanced" PageSize="5" AllowPaging="true" AllowSorting="true"
Data="@employees" TItem="Employee" ColumnWidth="300px" LogicalFilterOperator="LogicalFilterOperator.Or" Render="@OnRender">
<Columns>
<RadzenDataGridColumn TItem="Employee" Property="EmployeeID" Filterable="false" Title="ID" Frozen="true" Width="70px" TextAlign="TextAlign.Center" />
<RadzenDataGridColumn TItem="Employee" Title="Photo" Sortable="false" Filterable="false" Groupable="false" Width="200px" >
<Template Context="data">
<RadzenImage Path="@data.Photo" style="width: 40px; height: 40px; border-radius: 8px;" />
</Template>
</RadzenDataGridColumn>
<RadzenDataGridColumn TItem="Employee" Property="FirstName" Title="First Name" />
<RadzenDataGridColumn TItem="Employee" Property="LastName" Title="Last Name" Width="150px"/>
<RadzenDataGridColumn TItem="Employee" Property="Title" Title="Title" />
<RadzenDataGridColumn TItem="Employee" Property="TitleOfCourtesy" Title="Title Of Courtesy" />
<RadzenDataGridColumn TItem="Employee" Property="BirthDate" Title="Birth Date" FormatString="{0:d}" />
<RadzenDataGridColumn TItem="Employee" Property="HireDate" Title="Hire Date" FormatString="{0:d}" />
<RadzenDataGridColumn TItem="Employee" Property="Address" Title="Address" />
<RadzenDataGridColumn TItem="Employee" Property="City" Title="City" />
<RadzenDataGridColumn TItem="Employee" Property="Region" Title="Region" />
<RadzenDataGridColumn TItem="Employee" Property="PostalCode" Title="Postal Code" />
<RadzenDataGridColumn TItem="Employee" Property="Country" Title="Country" />
<RadzenDataGridColumn TItem="Employee" Property="HomePhone" Title="Home Phone" />
<RadzenDataGridColumn TItem="Employee" Property="Extension" Title="Extension" />
<RadzenDataGridColumn TItem="Employee" Property="Notes" Title="Notes" />
</Columns>
</RadzenDataGrid>
</RadzenExample>
@code {
IEnumerable<Employee> employees;
protected override void OnInitialized()
{
employees = dbContext.Employees;
}
void OnRender(DataGridRenderEventArgs<Employee> args)
{
if(args.FirstRender)
{
args.Grid.Groups.Add(new GroupDescriptor(){ Property = "Title" });
StateHasChanged();
}
}
}

View File

@@ -23,13 +23,13 @@
</RadzenDataGridColumn>
<RadzenDataGridColumn TItem="Order" Property="Employee.LastName" Title="Employee" Width="300px">
<Template Context="order">
<RadzenImage Path="@order.Employee?.Photo" style="width: 32px; height: 32px; border-radius: 50%;" />
<RadzenImage Path="@order.Employee?.Photo" style="width: 40px; height: 40px; border-radius: 8px;" />
@order.Employee?.FirstName @order.Employee?.LastName
</Template>
<EditTemplate Context="order">
<RadzenDropDown @bind-Value="order.EmployeeID" Data="@employees" ValueProperty="EmployeeID" Style="width:100%">
<Template>
<RadzenImage Path="@context.Photo" style="width: 32px; height: 32px; border-radius: 50%;" />
<RadzenImage Path="@context.Photo" style="width: 40px; height: 40px; border-radius: 8px;" />
@context.FirstName @context.LastName
</Template>
</RadzenDropDown>

View File

@@ -10,12 +10,13 @@
<p>The <code>LoadData</code> event allows you to perform custom paging, sorting and filtering.</p>
<RadzenExample Name="DataGridLoadData" Heading="false" Documentation="false">
<RadzenDataGrid Count="@count" Data="@employees" LoadData="@LoadData" AllowSorting="true" AllowFiltering="true" AllowPaging="true" PageSize="4" TItem="Employee" ColumnWidth="200px">
<RadzenButton Text="Reset" Click="@Reset" Style="margin-bottom: 20px;" />
<RadzenDataGrid @ref="grid" Count="@count" Data="@employees" LoadData="@LoadData" AllowSorting="true" AllowFiltering="true" AllowPaging="true" PageSize="4" TItem="Employee" ColumnWidth="200px">
<Columns>
<RadzenDataGridColumn TItem="Employee" Property="EmployeeID" Filterable="false" Title="ID" Frozen="true" Width="50px" TextAlign="TextAlign.Center" />
<RadzenDataGridColumn TItem="Employee" Title="Photo" Sortable="false" Filterable="false" Width="200px" >
<Template Context="data">
<RadzenImage Path="@data.Photo" style="width: 32px; height: 32px; border-radius: 50%;" />
<RadzenImage Path="@data.Photo" style="width: 40px; height: 40px; border-radius: 8px;" />
</Template>
</RadzenDataGridColumn>
<RadzenDataGridColumn TItem="Employee" Property="FirstName" Title="First Name" />
@@ -61,18 +62,27 @@ void LoadData(LoadDataArgs args)
query = query.OrderBy(args.OrderBy);
}
count = query.Count();
employees = query.Skip(args.Skip.Value).Take(args.Top.Value).ToList();
count = dbContext.Employees.Count();
}
</code>
</pre>
</li>
</ol>
@code {
RadzenDataGrid<Employee> grid;
int count;
IEnumerable<Employee> employees;
async Task Reset()
{
grid.Reset(true);
await grid.FirstPage(true);
}
void LoadData(LoadDataArgs args)
{
// This demo is using https://dynamic-linq.net
@@ -90,10 +100,10 @@ void LoadData(LoadDataArgs args)
query = query.OrderBy(args.OrderBy);
}
// Important!!! Make sure the Count property of RadzenDataGrid is set.
count = query.Count();
// Perform paginv via Skip and Take.
employees = query.Skip(args.Skip.Value).Take(args.Top.Value).ToList();
// Important!!! Make sure the Count property of RadzenDataGrid is set.
count = dbContext.Employees.Count();
}
}

View File

@@ -24,7 +24,7 @@
<RadzenDataGridColumn TItem="Employee" Property="EmployeeID" Title="Employee ID" />
<RadzenDataGridColumn TItem="Employee" Property="Photo" Title="Employee" Sortable="false" Filterable="false">
<Template Context="data">
<RadzenImage Path="@data.Photo" style="width: 32px; height: 32px; border-radius: 50%" />
<RadzenImage Path="@data.Photo" style="width: 40px; height: 40px; border-radius: 8px;" />
@data.FirstName @data.LastName
</Template>
</RadzenDataGridColumn>

View File

@@ -14,7 +14,7 @@
<RadzenDataGridColumn TItem="Employee" Property="EmployeeID" Filterable="false" Title="ID" Frozen="true" Width="50px" TextAlign="TextAlign.Center" />
<RadzenDataGridColumn TItem="Employee" Title="Photo" Sortable="false" Filterable="false" Width="200px" >
<Template Context="data">
<RadzenImage Path="@data.Photo" style="width: 32px; height: 32px; border-radius: 50%;" />
<RadzenImage Path="@data.Photo" style="width: 40px; height: 40px; border-radius: 8px;" />
</Template>
</RadzenDataGridColumn>
<RadzenDataGridColumn TItem="Employee" Property="FirstName" Title="First Name" />

View File

@@ -11,12 +11,13 @@
<p>Display tabular data with ease. Perform paging, sorting and filtering through Entity Framework without extra code.</p>
<RadzenExample Name="DataGrid" Heading="false">
<RadzenDataGrid AllowFiltering="true" AllowColumnResize="true" FilterMode="FilterMode.Advanced" PageSize="5" AllowPaging="true" AllowSorting="true" Data="@employees" TItem="Employee" ColumnWidth="300px" LogicalFilterOperator="LogicalFilterOperator.Or">
<RadzenDataGrid AllowFiltering="true" AllowColumnResize="true" FilterMode="FilterMode.Advanced" PageSize="5" AllowPaging="true" AllowSorting="true"
Data="@employees" TItem="Employee" ColumnWidth="300px" LogicalFilterOperator="LogicalFilterOperator.Or">
<Columns>
<RadzenDataGridColumn TItem="Employee" Property="EmployeeID" Filterable="false" Title="ID" Frozen="true" Width="50px" TextAlign="TextAlign.Center" />
<RadzenDataGridColumn TItem="Employee" Property="EmployeeID" Filterable="false" Title="ID" Frozen="true" Width="70px" TextAlign="TextAlign.Center" />
<RadzenDataGridColumn TItem="Employee" Title="Photo" Sortable="false" Filterable="false" Width="200px" >
<Template Context="data">
<RadzenImage Path="@data.Photo" style="width: 32px; height: 32px; border-radius: 50%;" />
<RadzenImage Path="@data.Photo" style="width: 40px; height: 40px; border-radius: 8px;" />
</Template>
</RadzenDataGridColumn>
<RadzenDataGridColumn TItem="Employee" Property="FirstName" Title="First Name" />

View File

@@ -8,13 +8,13 @@
<h1>DataGrid <strong>Pager API</strong></h1>
<RadzenExample Name="DataGridPagerApi" Heading="false">
<RadzenExample Name="DataGridPagerApi" Heading="false" Documentation="false">
<div style="margin-bottom: 16px">
<RadzenButton Click="@FirstPage" Text="First page" />
<RadzenButton Click="@TenthPage" Text="10th page" />
<RadzenButton Click="@LastPage" Text="Last page" />
</div>
<RadzenDataGrid @ref=@dataGrid Data="@orderDetails" TItem="OrderDetail" AllowPaging="true" AllowSorting="true">
<RadzenDataGrid @ref=@dataGrid Data="@orderDetails" TItem="OrderDetail" AllowPaging="true" AllowSorting="true" PageSizeOptions="@pageSizeOptions">
<Columns>
<RadzenDataGridColumn TItem="OrderDetail" Property="OrderID" Title="OrderID" />
<RadzenDataGridColumn TItem="OrderDetail" Property="ProductID" Title="ProductID" />
@@ -35,7 +35,7 @@
@code {
RadzenDataGrid<OrderDetail> dataGrid;
IEnumerable<int> pageSizeOptions = new int[] { 10, 20, 30 };
IEnumerable<OrderDetail> orderDetails;
async Task FirstPage()

View File

@@ -8,7 +8,7 @@
<h1>DataGrid <strong>Pager Position</strong></h1>
<RadzenExample Name="DataGridPagerPosition" Heading="false">
<RadzenExample Name="DataGridPagerPosition" Heading="false" Documentation="false">
<div style="display: flex; align-items: center; margin-bottom: 16px">
<div style="white-space:nowrap; margin-right: 16px">Pager Position:</div>
<RadzenDropDown @bind-Value="@pagerPosition" TextProperty="Text" ValueProperty="Value"

View File

@@ -8,7 +8,7 @@
<h1>DataGrid <strong>Simple Filter Mode</strong></h1>
<RadzenExample Name="DataGridSimpleFilter" Heading="false">
<RadzenExample Name="DataGridSimpleFilter" Heading="false" Documentation="false">
<RadzenDataGrid AllowFiltering="true" AllowColumnResize="true"
FilterMode="FilterMode.Simple" PageSize="5" AllowPaging="true" AllowSorting="true" Data="@employees" TItem="Employee" ColumnWidth="300px"
FilterCaseSensitivity="FilterCaseSensitivity.CaseInsensitive"
@@ -17,7 +17,7 @@
<RadzenDataGridColumn TItem="Employee" Property="EmployeeID" Filterable="false" Title="ID" Frozen="true" Width="50px" TextAlign="TextAlign.Center" />
<RadzenDataGridColumn TItem="Employee" Title="Photo" Sortable="false" Filterable="false" Width="200px" >
<Template Context="data">
<RadzenImage Path="@data.Photo" style="width: 32px; height: 32px; border-radius: 50%;" />
<RadzenImage Path="@data.Photo" style="width: 40px; height: 40px; border-radius: 8px;" />
</Template>
</RadzenDataGridColumn>
<RadzenDataGridColumn TItem="Employee" Property="FirstName" Title="First Name" />

View File

@@ -25,7 +25,7 @@
<RadzenDataGridColumn TItem="Employee" Property="EmployeeID" Title="Employee ID" />
<RadzenDataGridColumn TItem="Employee" Property="Photo" Title="Employee" Sortable="false" Filterable="false">
<Template Context="data">
<RadzenImage Path="@data.Photo" style="width: 32px; height: 32px; border-radius: 50%" />
<RadzenImage Path="@data.Photo" style="width: 40px; height: 40px; border-radius: 8px;" />
@data.FirstName @data.LastName
</Template>
</RadzenDataGridColumn>

View File

@@ -10,7 +10,7 @@
<p>Set the initial sort order of your RadzenDataGrid via the <code>SortOrder</code> column property.</p>
<RadzenExample Name="DataGridSortApi" Heading="false">
<RadzenExample Name="DataGridSortApi" Heading="false" Documentation="false">
<RadzenDataGrid AllowColumnResize="true" PageSize="5" AllowPaging="true" AllowSorting="true" Data="@employees" TItem="Employee" ColumnWidth="300px">
<Columns>
<RadzenDataGridColumn TItem="Employee" Property="FirstName" Title="First Name" SortOrder="SortOrder.Descending" />

View File

@@ -8,7 +8,7 @@
<h1>DataGrid <strong>Sorting</strong></h1>
<RadzenExample Name="DataGridSort" Heading="false">
<RadzenExample Name="DataGridSort" Heading="false" Documentation="false">
<RadzenDataGrid PageSize="5" AllowPaging="true" AllowSorting="true" Data="@employees" TItem="Employee" ColumnWidth="300px">
<Columns>
<RadzenDataGridColumn TItem="Employee" Property="FirstName" Title="First Name" />

View File

@@ -8,62 +8,100 @@
<RadzenExample Name="DropDownDataGrid" DocumentationUrl="https://www.radzen.com/documentation/blazor/dropdown-datagrid/">
<div class="row">
<div class="col-xl-6">
<h3>DropDownDataGrid</h3>
<RadzenDropDownDataGrid TValue="string" FilterCaseSensitivity="FilterCaseSensitivity.CaseInsensitive" AllowFiltering="true" AllowClear="true"
Data=@(customers.Select(c => new { CustomerID = c.CustomerID, CompanyName = c.CompanyName }).Distinct().AsQueryable())
TextProperty="CompanyName" ValueProperty="CustomerID"
Change=@(args => OnChange(args, "DropDownDataGrid")) />
<h3 style="margin-top: 2rem">DropDownDataGrid with filtering by all string columns</h3>
<RadzenDropDownDataGrid TValue="string" FilterCaseSensitivity="FilterCaseSensitivity.CaseInsensitive" AllowFiltering="true" AllowClear="true"
Data=@(customers)
TextProperty="CompanyName" ValueProperty="CustomerID" AllowFilteringByAllStringColumns="true"
Change=@(args => OnChange(args, "DropDownDataGrid with filtering by all string columns"))>
<Columns>
<RadzenDropDownDataGridColumn Property="CustomerID" Title="CustomerID" Width="100px" />
<RadzenDropDownDataGridColumn Property="CompanyName" Title="CompanyName" Width="200px" />
<RadzenDropDownDataGridColumn Property="City" Title="City" Width="100px" />
<RadzenDropDownDataGridColumn Property="Country" Title="Country" Width="100px" />
</Columns>
</RadzenDropDownDataGrid>
<h3 style="margin-top: 2rem">DropDownDataGrid with custom filter operator</h3>
<RadzenDropDownDataGrid TValue="string" FilterCaseSensitivity="FilterCaseSensitivity.CaseInsensitive" FilterOperator="StringFilterOperator.StartsWith"
AllowFiltering="true" AllowClear="true" Data=@customers TextProperty="CompanyName" ValueProperty="CustomerID"
Change=@(args => OnChange(args, "DropDownDataGrid with custom filter operator")) />
<h3 style="margin-top: 2rem">DropDownDataGrid with custom filtering</h3>
<RadzenDropDownDataGrid TValue="string" LoadData="@LoadData" AllowFiltering="true" AllowClear="true"
Data=@customCustomersData Count="@count" TextProperty="CompanyName" ValueProperty="CustomerID"
Change=@(args => OnChange(args, "DropDownDataGrid with custom filtering")) />
<h3 style="margin-top: 2rem">DropDownDataGrid with placeholder</h3>
<RadzenDropDownDataGrid TValue="string" FilterCaseSensitivity="FilterCaseSensitivity.CaseInsensitive" AllowFiltering="true" AllowClear="true" Placeholder="Select..." Data=@customers TextProperty="CompanyName"
ValueProperty="CustomerID" Change=@(args => OnChange(args, "DropDownDataGrid with placeholder")) />
<h3 style="margin-top: 2rem">DropDownDataGrid with template</h3>
<RadzenDropDownDataGrid AllowFiltering="true" FilterCaseSensitivity="FilterCaseSensitivity.CaseInsensitive" AllowClear="true"
@bind-Value="value" Placeholder="Select..." Data=@customers TextProperty="CompanyName" ValueProperty="CustomerID"
Change=@(args => OnChange(args, "DropDownDataGrid with placeholder")) Style="width:400px">
<Template>
Company: @((context as Customer).CompanyName)
</Template>
</RadzenDropDownDataGrid>
<h3 style="margin-top: 2rem">DropDownDataGrid with multiple selection and multiple columns</h3>
<RadzenDropDownDataGrid @ref="grid" AllowFiltering="true" FilterCaseSensitivity="FilterCaseSensitivity.CaseInsensitive" AllowClear="true" @bind-Value=@multipleValues
Multiple="true" Placeholder="Select..." Data=@customers TextProperty="CompanyName" ValueProperty="CustomerID"
Change=@(args => OnChange(args, "DropDownDataGrid with multiple selection")) Style="width:400px">
<Columns>
<RadzenDropDownDataGridColumn Width="40px" Sortable="false">
<HeaderTemplate>
<RadzenCheckBox TriState="false" TValue="bool" Value="@(customers.Any(c => multipleValues != null && multipleValues.Contains(c.CustomerID)))"
Change="@(args => multipleValues = args ? grid.View.Cast<Customer>().Select(c => c.CustomerID) : multipleValues = Enumerable.Empty<string>())" />
</HeaderTemplate>
<Template Context="data">
<RadzenCheckBox TriState="false" Value="@(multipleValues != null && multipleValues.Contains(((Customer)data).CustomerID))" />
<div class="row">
<div class="col-xl-6 mb-5">
<h3>Binding to simple collection</h3>
<RadzenDropDownDataGrid TValue="string" FilterCaseSensitivity="FilterCaseSensitivity.CaseInsensitive" AllowFiltering="true" AllowClear="true"
Data=@(customers.Select(c => c.CompanyName).Distinct().AsQueryable())
Change=@(args => OnChange(args, "DropDownDataGrid")) Style="width:100%" />
</div>
<div class="col-xl-6 mb-5">
<h3>Filtering by all string columns</h3>
<RadzenDropDownDataGrid TValue="string" FilterCaseSensitivity="FilterCaseSensitivity.CaseInsensitive" AllowFiltering="true" AllowClear="true"
Data=@(customers) Style="width:100%"
TextProperty="CompanyName" ValueProperty="CustomerID" AllowFilteringByAllStringColumns="true"
Change=@(args => OnChange(args, "DropDownDataGrid with filtering by all string columns"))>
<Columns>
<RadzenDropDownDataGridColumn Property="CustomerID" Title="CustomerID" Width="100px" />
<RadzenDropDownDataGridColumn Property="CompanyName" Title="CompanyName" Width="200px" />
<RadzenDropDownDataGridColumn Property="City" Title="City" Width="100px" />
<RadzenDropDownDataGridColumn Property="Country" Title="Country" Width="100px" />
</Columns>
</RadzenDropDownDataGrid>
</div>
</div>
<div class="row">
<div class="col-xl-6 mb-5">
<h3>Filter operator</h3>
<RadzenDropDownDataGrid TValue="string" FilterCaseSensitivity="FilterCaseSensitivity.CaseInsensitive" FilterOperator="StringFilterOperator.StartsWith"
AllowFiltering="true" AllowClear="true" Data=@customers TextProperty="CompanyName" ValueProperty="CustomerID"
Change=@(args => OnChange(args, "DropDownDataGrid with custom filter operator")) Style="width:100%" />
</div>
<div class="col-xl-6 mb-5">
<h3>Custom filtering</h3>
<RadzenDropDownDataGrid TValue="string" LoadData="@LoadData" AllowFiltering="true" AllowClear="true"
Data=@customCustomersData Count="@count" TextProperty="CompanyName" ValueProperty="CustomerID"
Change=@(args => OnChange(args, "DropDownDataGrid with custom filtering")) Style="width:100%" />
</div>
</div>
<div class="row">
<div class="col-xl-6 mb-5">
<h3>Multiple selection</h3>
<RadzenDropDownDataGrid @ref="grid" AllowFiltering="true" FilterCaseSensitivity="FilterCaseSensitivity.CaseInsensitive" AllowClear="true" @bind-Value=@multipleValues
Multiple="true" Placeholder="Select..." Data=@customers TextProperty="CompanyName" ValueProperty="CustomerID"
Change=@(args => OnChange(args, "DropDownDataGrid with multiple selection")) Style="width:100%">
<Columns>
<RadzenDropDownDataGridColumn Width="40px" Sortable="false">
<HeaderTemplate>
<RadzenCheckBox TriState="false" TValue="bool" Value="@(customers.Any(c => multipleValues != null && multipleValues.Contains(c.CustomerID)))"
Change="@(args => multipleValues = args ? grid.View.Cast<Customer>().Select(c => c.CustomerID) : multipleValues = Enumerable.Empty<string>())" />
</HeaderTemplate>
<Template Context="data">
<RadzenCheckBox TriState="false" Value="@(multipleValues != null && multipleValues.Contains(((Customer)data).CustomerID))" />
</Template>
</RadzenDropDownDataGridColumn>
<RadzenDropDownDataGridColumn Property="CustomerID" Title="CustomerID" Width="100px" />
<RadzenDropDownDataGridColumn Property="CompanyName" Title="CompanyName" Width="200px" />
<RadzenDropDownDataGridColumn Property="City" Title="City" Width="100px" />
<RadzenDropDownDataGridColumn Property="Country" Title="Country" Width="100px" />
</Columns>
</RadzenDropDownDataGrid>
</div>
<div class="col-xl-6 mb-5">
<h3>Custom template</h3>
<RadzenDropDownDataGrid AllowFiltering="true" FilterCaseSensitivity="FilterCaseSensitivity.CaseInsensitive" AllowClear="true"
@bind-Value="value" Placeholder="Select..." Data=@customers TextProperty="CompanyName" ValueProperty="CustomerID"
Change=@(args => OnChange(args, "DropDownDataGrid with placeholder")) Style="width:100%">
<Template>
Company: @((context as Customer).CompanyName)
</Template>
</RadzenDropDownDataGridColumn>
<RadzenDropDownDataGridColumn Property="CustomerID" Title="CustomerID" Width="100px" />
<RadzenDropDownDataGridColumn Property="CompanyName" Title="CompanyName" Width="200px" />
<RadzenDropDownDataGridColumn Property="City" Title="City" Width="100px" />
<RadzenDropDownDataGridColumn Property="Country" Title="Country" Width="100px" />
</Columns>
</RadzenDropDownDataGrid>
</RadzenDropDownDataGrid>
</div>
</div>
<div class="row">
<div class="col-xl-6 mb-5">
<h3>Virtualization using IQueryable</h3>
<RadzenDropDownDataGrid TValue="string" FilterCaseSensitivity="FilterCaseSensitivity.CaseInsensitive" FilterOperator="StringFilterOperator.StartsWith" AllowVirtualization="true"
AllowFiltering="true" AllowClear="true" Data=@customers TextProperty="CompanyName" ValueProperty="CustomerID"
Change=@(args => OnChange(args, "DropDownDataGrid with virtualization using IQueryable")) Style="width:100%">
<Columns>
<RadzenDropDownDataGridColumn Property="CustomerID" Title="Customer ID" />
<RadzenDropDownDataGridColumn Property="CompanyName" Title="Company Name" />
</Columns>
</RadzenDropDownDataGrid>
</div>
<div class="col-xl-6 mb-5">
<h3>Virtualization using LoadData event</h3>
<RadzenDropDownDataGrid TValue="string" LoadData="@LoadDataVirtualization" AllowFiltering="true" AllowClear="true" AllowVirtualization="true"
Data=@customCustomersDataVirtualization Count="@customCustomersDataVirtualizationCount" TextProperty="CompanyName" ValueProperty="CustomerID"
Change=@(args => OnChange(args, "DropDownDataGrid with virtualization using LoadData event")) Style="width:100%" />
</div>
</div>
</div>
<div class="col-xl-6">
<EventConsole @ref=@console />
@@ -125,4 +163,30 @@
InvokeAsync(StateHasChanged);
}
int customCustomersDataVirtualizationCount;
IEnumerable<Customer> customCustomersDataVirtualization;
void LoadDataVirtualization(LoadDataArgs args)
{
var query = dbContext.Customers.AsQueryable();
if (!string.IsNullOrEmpty(args.Filter))
{
query = query.Where(c => c.CustomerID.ToLower().Contains(args.Filter.ToLower()) || c.ContactName.ToLower().Contains(args.Filter.ToLower()));
}
if (!string.IsNullOrEmpty(args.OrderBy))
{
query = query.OrderBy(args.OrderBy);
}
console.Log($"LoadData with virtualization: Skip:{args.Skip}, Top:{args.Top}, OrderBy:{args.OrderBy}, Filter:{args.Filter}");
customCustomersDataVirtualizationCount = query.Count();
customCustomersDataVirtualization = query.Skip(args.Skip.Value).Take(args.Top.Value).ToList();
InvokeAsync(StateHasChanged);
}
}

View File

@@ -10,43 +10,85 @@
<RadzenExample Name="DropDown">
<div class="row">
<div class="col-xl-6">
<h3>DropDown</h3>
<RadzenDropDown AllowClear="true" TValue="string"
Data=@(customers.Select(c => new { CustomerID = c.CustomerID, CompanyName = c.CompanyName }).Distinct())
TextProperty="CompanyName" ValueProperty="CustomerID" Change=@(args => OnChange(args, "DropDown")) />
<h3 style="margin-top: 2rem">Disabled DropDown</h3>
<div style="display: flex; align-items: center">
<RadzenDropDown Disabled=@disabled AllowClear="true" TValue="string"
Data=@(customers.Select(c => new { CustomerID = c.CustomerID, CompanyName = c.CompanyName }).Distinct())
TextProperty="CompanyName" ValueProperty="CustomerID" Change=@(args => OnChange(args, "DropDown")) />
<RadzenSwitch style="margin-left: 1rem" @bind-Value=@disabled />
<div class="row">
<div class="col-xl-6 mb-5">
<h3>Binding to simple collection</h3>
<RadzenDropDown AllowClear="true" TValue="string" Style="width:300px"
Data=@(customers.Select(c => c.CompanyName).Distinct())
Change=@(args => OnChange(args, "DropDown")) />
</div>
<div class="col-xl-6 mb-5">
<h3>Disabled DropDown</h3>
<div style="display: flex; align-items: center">
<RadzenDropDown Disabled=@disabled AllowClear="true" TValue="string" Style="width:300px"
Data=@(customers.Select(c => new { CustomerID = c.CustomerID, CompanyName = c.CompanyName }).Distinct())
TextProperty="CompanyName" ValueProperty="CustomerID" Change=@(args => OnChange(args, "DropDown")) />
<RadzenSwitch style="margin-left: 1rem" @bind-Value=@disabled />
</div>
</div>
</div>
<div class="row">
<div class="col-xl-6 mb-5">
<h3>DropDown with virtualization using IQueryable</h3>
<RadzenDropDown AllowClear="true" TValue="string" AllowVirtualization="true" Style="width:300px"
AllowFiltering="true" Data=@customers TextProperty="CompanyName" ValueProperty="CustomerID"
Change=@(args => OnChange(args, "DropDown with virtualization")) />
</div>
<div class="col-xl-6 mb-5">
<h3>DropDown with virtualization using LoadData event</h3>
<RadzenDropDown AllowClear="true" TValue="string" AllowVirtualization="true" Style="width:300px"
LoadData=@LoadDataVirtualization AllowFiltering="true" Count="@count"
Data=@customCustomersDataVirtualization TextProperty="CompanyName" ValueProperty="CustomerID"
Change=@(args => OnChange(args, "DropDown with virtualization")) />
</div>
</div>
<div class="row">
<div class="col-xl-6 mb-5">
<h3>DropDown with custom filter operator</h3>
<RadzenDropDown AllowClear="true" TValue="string" Style="width:300px"
FilterCaseSensitivity="FilterCaseSensitivity.CaseInsensitive" FilterOperator="StringFilterOperator.StartsWith" AllowFiltering="true"
Data=@customers TextProperty="CompanyName" ValueProperty="CustomerID" Change=@(args => OnChange(args, "DropDown with custom filter operator")) />
</div>
<div class="col-xl-6 mb-5">
<h3>DropDown with custom filtering</h3>
<RadzenDropDown AllowClear="true" TValue="string" Style="width:300px"
LoadData=@LoadData AllowFiltering="true"
Data=@customCustomersData TextProperty="CompanyName" ValueProperty="CustomerID"
Change=@(args => OnChange(args, "DropDown with custom filtering")) />
</div>
</div>
<div class="row">
<div class="col-xl-6 mb-5">
<h3>DropDown with placeholder</h3>
<RadzenDropDown AllowClear="true" TValue="string" FilterCaseSensitivity="FilterCaseSensitivity.CaseInsensitive" AllowFiltering="true" Style="width:300px"
Placeholder="Select..." Data=@customers TextProperty="CompanyName" ValueProperty="CustomerID" Change=@(args => OnChange(args, "DropDown with placeholder")) />
</div>
<div class="col-xl-6 mb-5">
<h3>DropDown with template</h3>
<RadzenDropDown AllowClear="true" AllowFiltering="true" FilterCaseSensitivity="FilterCaseSensitivity.CaseInsensitive" @bind-Value=@value Placeholder="Select..."
Data=@customers TextProperty="CompanyName" ValueProperty="CustomerID" Change=@(args => OnChange(args, "DropDown with placeholder")) Style="width:300px" >
<Template>
Company: @((context as Customer).CompanyName)
</Template>
</RadzenDropDown>
</div>
</div>
<div class="row">
<div class="col-xl-6 mb-5">
<h3>DropDown with multiple selection</h3>
<RadzenDropDown AllowClear="true" AllowFiltering="true" FilterCaseSensitivity="FilterCaseSensitivity.CaseInsensitive"
@bind-Value=@multipleValues Multiple="true" Placeholder="Select..." Data=@customers TextProperty="CompanyName" ValueProperty="CustomerID"
Change=@(args => OnChange(args, "DropDown with multiple selection")) Style="width:300px" />
</div>
<div class="col-xl-6 mb-5">
<h3>Bind DropDown Value to model property</h3>
<RadzenDropDown AllowClear="true" AllowFiltering="true" FilterCaseSensitivity="FilterCaseSensitivity.CaseInsensitive" Data=@products @bind-Value=@myModel.MyValue
TextProperty="ProductName" ValueProperty="ProductID" Change=@(args => ChangeBound(args, "DropDown with bound Value")) Style="width:300px" />
</div>
</div>
<h3 style="margin-top: 2rem">DropDown with custom filter operator</h3>
<RadzenDropDown AllowClear="true" TValue="string"
FilterCaseSensitivity="FilterCaseSensitivity.CaseInsensitive" FilterOperator="StringFilterOperator.StartsWith" AllowFiltering="true"
Data=@customers TextProperty="CompanyName" ValueProperty="CustomerID" Change=@(args => OnChange(args, "DropDown with custom filter operator")) />
<h3 style="margin-top: 2rem">DropDown with custom filtering</h3>
<RadzenDropDown AllowClear="true" TValue="string"
LoadData=@LoadData AllowFiltering="true"
Data=@customCustomersData TextProperty="CompanyName" ValueProperty="CustomerID"
Change=@(args => OnChange(args, "DropDown with custom filtering")) />
<h3 style="margin-top: 2rem">DropDown with placeholder</h3>
<RadzenDropDown AllowClear="true" TValue="string" FilterCaseSensitivity="FilterCaseSensitivity.CaseInsensitive" AllowFiltering="true"
Placeholder="Select..." Data=@customers TextProperty="CompanyName" ValueProperty="CustomerID" Change=@(args => OnChange(args, "DropDown with placeholder")) />
<h3 style="margin-top: 2rem">DropDown with template</h3>
<RadzenDropDown AllowClear="true" AllowFiltering="true" FilterCaseSensitivity="FilterCaseSensitivity.CaseInsensitive" @bind-Value=@value Placeholder="Select..."
Data=@customers TextProperty="CompanyName" ValueProperty="CustomerID" Change=@(args => OnChange(args, "DropDown with placeholder")) Style="width:400px">
<Template>
Company: @((context as Customer).CompanyName)
</Template>
</RadzenDropDown>
<h3 style="margin-top: 2rem">DropDown with multiple selection</h3>
<RadzenDropDown AllowClear="true" AllowFiltering="true" FilterCaseSensitivity="FilterCaseSensitivity.CaseInsensitive"
@bind-Value=@multipleValues Multiple="true" Placeholder="Select..." Data=@customers TextProperty="CompanyName" ValueProperty="CustomerID"
Change=@(args => OnChange(args, "DropDown with multiple selection")) Style="width:400px" />
<h3 style="margin-top: 2rem">Bind DropDown Value to model property</h3>
<RadzenDropDown AllowClear="true" AllowFiltering="true" FilterCaseSensitivity="FilterCaseSensitivity.CaseInsensitive" Data=@products @bind-Value=@myModel.MyValue
TextProperty="ProductName" ValueProperty="ProductID" Style="width:400px" Change=@(args => ChangeBound(args, "DropDown with bound Value")) />
</div>
<div class="col-xl-6">
<EventConsole @ref=@console />
@@ -61,17 +103,20 @@
IEnumerable<Product> products;
MyObject myModel = new MyObject();
protected override void OnInitialized()
{
customers = dbContext.Customers.ToList();
products = dbContext.Products.ToList();
}
int count;
IEnumerable<Customer> customCustomersDataVirtualization;
IEnumerable<string> multipleValues = new string[] { "ALFKI", "ANATR" };
string value = "ALFKI";
EventConsole console;
protected override void OnInitialized()
{
customers = dbContext.Customers.ToList();
products = dbContext.Products.ToList();
}
void OnChange(object value, string name)
{
var str = value is IEnumerable<object> ? string.Join(", ", (IEnumerable<object>)value) : value;
@@ -104,4 +149,22 @@
InvokeAsync(StateHasChanged);
}
void LoadDataVirtualization(LoadDataArgs args)
{
var query = dbContext.Customers.AsQueryable();
if (!string.IsNullOrEmpty(args.Filter))
{
query = query.Where(c => c.CustomerID.ToLower().Contains(args.Filter.ToLower()) || c.ContactName.ToLower().Contains(args.Filter.ToLower()));
}
console.Log($"LoadData with virtualization: Skip:{args.Skip}, Top:{args.Top}, Filter:{args.Filter}");
count = query.Count();
customCustomersDataVirtualization = query.Skip(args.Skip.Value).Take(args.Top.Value).ToList();
InvokeAsync(StateHasChanged);
}
}

View File

@@ -47,6 +47,11 @@
</Template>
</RadzenDataList>
</ChildContent>
<SummaryTemplate>
<span>
@orders.Count() Orders
</span>
</SummaryTemplate>
</RadzenFieldset>
</div>
<div class="col-xl-6">

View File

@@ -17,7 +17,7 @@
<div class="col-xl-6 mb-5">
<h3>ListBox with template</h3>
<RadzenListBox @bind-Value=@value Data=@customers TextProperty="CompanyName" ValueProperty="CustomerID"
Change=@(args => OnChange(args, "ListBox with template")) Style="height:200px">
Change=@(args => OnChange(args, "ListBox with template")) Style="height:200px">
<Template>
Company: @((context as Customer).CompanyName)
</Template>
@@ -27,25 +27,37 @@
<div class="row">
<div class="col-xl-6 mb-5">
<h3>ListBox with multiple selection</h3>
<RadzenListBox AllowFiltering="true" FilterCaseSensitivity="FilterCaseSensitivity.CaseInsensitive" @bind-Value=@multipleValues Multiple="true" Data=@customers
TextProperty="CompanyName" ValueProperty="CustomerID" Change=@(args => OnChange(args, "ListBox with multiple selection")) Style="height:200px" />
<RadzenListBox AllowFiltering="true" FilterCaseSensitivity="FilterCaseSensitivity.CaseInsensitive" @bind-Value=@multipleValues Multiple="true" Data=@customers
TextProperty="CompanyName" ValueProperty="CustomerID" Change=@(args => OnChange(args, "ListBox with multiple selection")) Style="height:200px" />
</div>
<div class="col-xl-6 mb-5">
<h3>ListBox with filtering</h3>
<RadzenListBox AllowFiltering="true" FilterCaseSensitivity="FilterCaseSensitivity.CaseInsensitive" @bind-Value=@value Data=@customers TextProperty="CompanyName" ValueProperty="CustomerID"
Change=@(args => OnChange(args, "ListBox with filtering")) Style="height:200px" />
Change=@(args => OnChange(args, "ListBox with filtering")) Style="height:200px" />
</div>
</div>
<div class="row">
<div class="col-xl-6 mb-5">
<h3>ListBox with custom filter operator</h3>
<RadzenListBox AllowFiltering="true" FilterCaseSensitivity="FilterCaseSensitivity.CaseInsensitive" FilterOperator="StringFilterOperator.StartsWith" @bind-Value=@value
Data=@customers TextProperty="CompanyName" ValueProperty="CustomerID" Change=@(args => OnChange(args, "ListBox with custom filter operator")) Style="height:200px" />
Data=@customers TextProperty="CompanyName" ValueProperty="CustomerID" Change=@(args => OnChange(args, "ListBox with custom filter operator")) Style="height:200px" />
</div>
<div class="col-xl-6 mb-5">
<h3>ListBox with custom filtering</h3>
<RadzenListBox AllowFiltering="true" LoadData=@OnLoadData @bind-Value=@value Data=@customCustomersData TextProperty="CompanyName" ValueProperty="CustomerID"
Change=@(args => OnChange(args, "ListBox with custom filtering")) Style="height:200px" />
<RadzenListBox AllowFiltering="true" LoadData=@OnLoadData @bind-Value=@value Data=@customCustomersData TextProperty="CompanyName" ValueProperty="CustomerID"
Change=@(args => OnChange(args, "ListBox with custom filtering")) Style="height:200px" />
</div>
</div>
<div class="row">
<div class="col-xl-6 mb-5">
<h3>ListBox with virtualization using IQueryable</h3>
<RadzenListBox AllowFiltering="true" FilterCaseSensitivity="FilterCaseSensitivity.CaseInsensitive" FilterOperator="StringFilterOperator.StartsWith" @bind-Value=@value
Data=@customers TextProperty="CompanyName" ValueProperty="CustomerID" Change=@(args => OnChange(args, "ListBox with custom filter operator")) Style="height:200px" />
</div>
<div class="col-xl-6 mb-5">
<h3>ListBox with virtualization using LoadData event</h3>
<RadzenListBox AllowVirtualization="true" AllowFiltering="true" Count="@count" LoadData=@LoadDataVirtualization @bind-Value=@value Data=@customCustomersDataVirtualization TextProperty="CompanyName" ValueProperty="CustomerID"
Change=@(args => OnChange(args, "ListBox with custom filtering")) Style="height:200px" />
</div>
</div>
</div>
@@ -91,4 +103,24 @@
InvokeAsync(StateHasChanged);
}
IEnumerable<Customer> customCustomersDataVirtualization;
int count;
void LoadDataVirtualization(LoadDataArgs args)
{
var query = dbContext.Customers.AsQueryable();
if (!string.IsNullOrEmpty(args.Filter))
{
query = query.Where(c => c.CustomerID.ToLower().Contains(args.Filter.ToLower()) || c.ContactName.ToLower().Contains(args.Filter.ToLower()));
}
console.Log($"LoadData with virtualization: Skip:{args.Skip}, Top:{args.Top}, Filter:{args.Filter}");
count = query.Count();
customCustomersDataVirtualization = query.Skip(args.Skip.Value).Take(args.Top.Value).ToList();
InvokeAsync(StateHasChanged);
}
}

View File

@@ -37,7 +37,7 @@
<RadzenDataGridColumn Width="200px" TItem="Order" Property="Customer.CompanyName" Title="Customer" />
<RadzenDataGridColumn Width="150px" TItem="Order" Property="Employee.LastName" Title="Employee">
<Template Context="order">
<RadzenImage Path="@order.Employee?.Photo" style="width: 32px; height: 32px; border-radius: 50%" />
<RadzenImage Path="@order.Employee?.Photo" style="width: 40px; height: 40px; border-radius: 8px;" />
@order.Employee?.FirstName @order.Employee?.LastName
</Template>
</RadzenDataGridColumn>

Some files were not shown because too many files have changed in this diff Show More