mirror of
https://github.com/radzenhq/radzen-blazor.git
synced 2026-02-04 05:35:44 +00:00
Compare commits
553 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
45d38494f2 | ||
|
|
5c03d0d14c | ||
|
|
8404294f56 | ||
|
|
7f519bb71f | ||
|
|
7a5995002d | ||
|
|
ba8fe8e830 | ||
|
|
949a5b19cc | ||
|
|
5a68a00f38 | ||
|
|
d52d91852a | ||
|
|
b8b39e1ebd | ||
|
|
e795e63d02 | ||
|
|
27dc58a90f | ||
|
|
d4679353af | ||
|
|
73a53c8829 | ||
|
|
eb51f78f8c | ||
|
|
8667443e64 | ||
|
|
0650472551 | ||
|
|
7653ea683a | ||
|
|
d633d2f424 | ||
|
|
98ec370545 | ||
|
|
51b9579d6e | ||
|
|
af42791fa2 | ||
|
|
f7e9a88575 | ||
|
|
331ac4787e | ||
|
|
4ac2e0aa49 | ||
|
|
0cb10c206a | ||
|
|
5fd031f518 | ||
|
|
48c204a7b0 | ||
|
|
e61fc1c84e | ||
|
|
fb64381af9 | ||
|
|
84954f1919 | ||
|
|
cdabe516eb | ||
|
|
e5ddb2cef9 | ||
|
|
963185b927 | ||
|
|
f7ef6a207e | ||
|
|
8088d14340 | ||
|
|
f710b782a3 | ||
|
|
b13921f9aa | ||
|
|
522191052a | ||
|
|
e9e8844342 | ||
|
|
ccbf7b24cf | ||
|
|
57f1417d4c | ||
|
|
d5318e6e88 | ||
|
|
978e3fc610 | ||
|
|
dcb5eef814 | ||
|
|
518ad838e7 | ||
|
|
ba6ced577e | ||
|
|
138253e728 | ||
|
|
ffd299962b | ||
|
|
354a147155 | ||
|
|
a623017325 | ||
|
|
654bd80abd | ||
|
|
3249591351 | ||
|
|
40f934d7a6 | ||
|
|
53717dcc46 | ||
|
|
f16a00fe2e | ||
|
|
ab1af0ce28 | ||
|
|
be444bbbc4 | ||
|
|
e161872604 | ||
|
|
e21fa015bf | ||
|
|
fb3275d89f | ||
|
|
f42e4ffc71 | ||
|
|
7b15c190d3 | ||
|
|
73c2d27620 | ||
|
|
288db125ce | ||
|
|
0effaae435 | ||
|
|
a71f1dd3c6 | ||
|
|
c08843d587 | ||
|
|
44094cd4f4 | ||
|
|
a4bd9d518c | ||
|
|
a739a6e24a | ||
|
|
955b52d54b | ||
|
|
004293008c | ||
|
|
9f26a0b512 | ||
|
|
b16f95a4ba | ||
|
|
c079531d2e | ||
|
|
773f2dc074 | ||
|
|
64d783179b | ||
|
|
3dafd6c277 | ||
|
|
fb2fdb10b2 | ||
|
|
50dedf84d5 | ||
|
|
d7b96a7dca | ||
|
|
1d1acdf7c8 | ||
|
|
440bc76f08 | ||
|
|
d2a598dbf5 | ||
|
|
931f9dab6f | ||
|
|
10ec2af398 | ||
|
|
46382ef89f | ||
|
|
c4116feda4 | ||
|
|
4c18342cf4 | ||
|
|
92f103c1dd | ||
|
|
8c9374e00a | ||
|
|
870f3d2ef9 | ||
|
|
d75b3596aa | ||
|
|
c388d84f57 | ||
|
|
782f6c9655 | ||
|
|
078d12f2a1 | ||
|
|
271e1aa26a | ||
|
|
c9c11c7ff7 | ||
|
|
75da4667b7 | ||
|
|
a2591f7f77 | ||
|
|
72b4e8bd39 | ||
|
|
740b0bc3b1 | ||
|
|
3e48b15db0 | ||
|
|
f1b8a22cc8 | ||
|
|
02b75fcb68 | ||
|
|
9b2541975f | ||
|
|
d3ff9a5b7c | ||
|
|
75acf7d132 | ||
|
|
d6a9430c20 | ||
|
|
5a89720f59 | ||
|
|
bee7133e81 | ||
|
|
8522f88d66 | ||
|
|
10ecc5c75d | ||
|
|
cdd722c975 | ||
|
|
7fd9b258aa | ||
|
|
5368d398fe | ||
|
|
30cc8c8711 | ||
|
|
f7d1fea2af | ||
|
|
ee5674bb6d | ||
|
|
5e1fa61c55 | ||
|
|
92f968f933 | ||
|
|
9eabd75864 | ||
|
|
df121e68b4 | ||
|
|
be0721fa5d | ||
|
|
d670872d73 | ||
|
|
68eb9162a9 | ||
|
|
a65ce23a10 | ||
|
|
bea9bca891 | ||
|
|
9f2c6fe8cc | ||
|
|
07e4276190 | ||
|
|
3db15c168d | ||
|
|
7e9f66ec61 | ||
|
|
c7ce4ec4e3 | ||
|
|
ad32aed204 | ||
|
|
2df9235516 | ||
|
|
a0efb0b9a4 | ||
|
|
a244741640 | ||
|
|
e3f5360a7f | ||
|
|
c280bae14f | ||
|
|
e99671ba81 | ||
|
|
73338462e5 | ||
|
|
1912e69375 | ||
|
|
60a3789e9c | ||
|
|
a89bc5a5ce | ||
|
|
08f3126f46 | ||
|
|
53e746146b | ||
|
|
1e7cc0d655 | ||
|
|
b37a81b297 | ||
|
|
6aec8118f2 | ||
|
|
756732803f | ||
|
|
a6b8abb9ce | ||
|
|
38feb54237 | ||
|
|
ee828de086 | ||
|
|
bc82638fea | ||
|
|
edb6f58f66 | ||
|
|
23b9a6e7bf | ||
|
|
0b3c6058e2 | ||
|
|
cb6572980e | ||
|
|
78e5bbb9dc | ||
|
|
12b52b3e79 | ||
|
|
e226749388 | ||
|
|
001cd0cdcd | ||
|
|
c3806348a0 | ||
|
|
c6a8d80d45 | ||
|
|
2babacd15a | ||
|
|
456ab29a34 | ||
|
|
1de201841a | ||
|
|
a5586fd4ea | ||
|
|
a14ac78957 | ||
|
|
1193ede1ca | ||
|
|
8ad75a1773 | ||
|
|
9ea1b44e64 | ||
|
|
b92ef7922d | ||
|
|
3d6eff639f | ||
|
|
011e761d7f | ||
|
|
a2fdb687a1 | ||
|
|
ff846e0cc1 | ||
|
|
df0ad0d9f1 | ||
|
|
716d1a6cba | ||
|
|
3e7468177d | ||
|
|
d4113e6715 | ||
|
|
7f7ce06d0e | ||
|
|
7cfea596fd | ||
|
|
7eae5d0f6e | ||
|
|
a390658ad9 | ||
|
|
ecc403cbbc | ||
|
|
e870ca856c | ||
|
|
e7b8fec063 | ||
|
|
7767878c4c | ||
|
|
63de20fe36 | ||
|
|
6114a9a8ed | ||
|
|
d5514ca0cd | ||
|
|
8cf0565211 | ||
|
|
32246b1d69 | ||
|
|
418dbf09ec | ||
|
|
a198d09b71 | ||
|
|
f3bb0e7b90 | ||
|
|
b3917e19a2 | ||
|
|
e7d8b7454f | ||
|
|
4d4660eed9 | ||
|
|
b80e47672d | ||
|
|
3b370841cc | ||
|
|
7ec2a9a0a5 | ||
|
|
e340a376ef | ||
|
|
a2709afc5c | ||
|
|
9c7ed95f23 | ||
|
|
524f1f99cb | ||
|
|
2ac6d7f2bb | ||
|
|
6b3fd9efae | ||
|
|
d99daa6538 | ||
|
|
13e0bba379 | ||
|
|
ed7c5bc537 | ||
|
|
03b7968b99 | ||
|
|
274d64246b | ||
|
|
4450053fd3 | ||
|
|
8c321f18e1 | ||
|
|
e015807edc | ||
|
|
4ebcd2f214 | ||
|
|
67cd8b7a61 | ||
|
|
0a802ca73b | ||
|
|
097f37bfbc | ||
|
|
524e42980a | ||
|
|
34eebc9406 | ||
|
|
65f20c232c | ||
|
|
d742fdae86 | ||
|
|
397e2baf6c | ||
|
|
4b1d951083 | ||
|
|
ab65a5a975 | ||
|
|
9947cbf47b | ||
|
|
f781ba0c6a | ||
|
|
e3c605a7a9 | ||
|
|
849e6761b8 | ||
|
|
407ef36b70 | ||
|
|
fef5ceb36d | ||
|
|
2e22f556d8 | ||
|
|
95b833402f | ||
|
|
c0e7418e7c | ||
|
|
4d72ef1efe | ||
|
|
a00bce399f | ||
|
|
2b8658b233 | ||
|
|
fc2784450b | ||
|
|
896d9bd3ae | ||
|
|
9199096f69 | ||
|
|
bdb2694734 | ||
|
|
98ab3cd3d0 | ||
|
|
22f7d3f9f4 | ||
|
|
7f27dafe32 | ||
|
|
37a1e6d4b5 | ||
|
|
91d5473bf2 | ||
|
|
b883cccb30 | ||
|
|
2ca7b3ba5f | ||
|
|
faada7ae7b | ||
|
|
3910fb778f | ||
|
|
4577d063cc | ||
|
|
1f5c70166e | ||
|
|
f920f9f08d | ||
|
|
e6272e88e6 | ||
|
|
4be24abf7f | ||
|
|
85cc05a144 | ||
|
|
7f726c4e2a | ||
|
|
5c86ffd2ac | ||
|
|
257444b640 | ||
|
|
c61d453de4 | ||
|
|
4b88b18e78 | ||
|
|
1125894e7a | ||
|
|
e8894360fa | ||
|
|
168c071ac3 | ||
|
|
d6dd67951e | ||
|
|
c7e4470a60 | ||
|
|
cb6789504a | ||
|
|
314664c4e2 | ||
|
|
58794f806c | ||
|
|
6a470a6448 | ||
|
|
27bf1713a0 | ||
|
|
c1e428dd3e | ||
|
|
661e5b50f8 | ||
|
|
749c2cf600 | ||
|
|
153e9e01bc | ||
|
|
c1797cc215 | ||
|
|
00eb31cd88 | ||
|
|
bd4b1e485b | ||
|
|
387eacf5ff | ||
|
|
5d00e79e0b | ||
|
|
3aac6a785d | ||
|
|
3506256dff | ||
|
|
5c49ab32e5 | ||
|
|
f128209c3a | ||
|
|
4a4254847a | ||
|
|
d21697367c | ||
|
|
1ceaab2788 | ||
|
|
0c56f20f55 | ||
|
|
261339c7e9 | ||
|
|
1d1335fed5 | ||
|
|
c9b5a53be3 | ||
|
|
11a037aeec | ||
|
|
0743bb5f54 | ||
|
|
9fe5163d86 | ||
|
|
acd107b1a2 | ||
|
|
1ff96df224 | ||
|
|
fb537c46d4 | ||
|
|
a588b454ae | ||
|
|
0f145800fa | ||
|
|
44dfa72f16 | ||
|
|
19152f498c | ||
|
|
056a61c9fe | ||
|
|
a0cfc5d267 | ||
|
|
eb6dbf0c67 | ||
|
|
af2083120e | ||
|
|
95d4c0e992 | ||
|
|
b14f67685a | ||
|
|
b82fa04aec | ||
|
|
93d1e8604a | ||
|
|
53d32dbcc2 | ||
|
|
da43d91b5a | ||
|
|
0694ab0777 | ||
|
|
207940426d | ||
|
|
58a204ed56 | ||
|
|
f68a2719f4 | ||
|
|
4311b019f4 | ||
|
|
c1b7ce0bcc | ||
|
|
fe0ca5403c | ||
|
|
c5c33ebfeb | ||
|
|
2c24843e4d | ||
|
|
b0e17e572c | ||
|
|
7cd5727ccc | ||
|
|
d02bafc7a6 | ||
|
|
ca4bdad32a | ||
|
|
4fab7f9180 | ||
|
|
224f54c676 | ||
|
|
fbc1dbb443 | ||
|
|
4da4e532c5 | ||
|
|
a16447faa2 | ||
|
|
a883b26dda | ||
|
|
b9937ee6ca | ||
|
|
40ed1d5841 | ||
|
|
0d3b86d06b | ||
|
|
f8464d6f23 | ||
|
|
d2995e3b6c | ||
|
|
eda37027d5 | ||
|
|
11f9e5cfa4 | ||
|
|
a59a02a6a7 | ||
|
|
26db867bd5 | ||
|
|
18a92cbaca | ||
|
|
62ac151847 | ||
|
|
0b3628e085 | ||
|
|
ffb23e7f34 | ||
|
|
678d861e22 | ||
|
|
652e08ebbe | ||
|
|
95672569c5 | ||
|
|
c9bedc9315 | ||
|
|
dbaeb39564 | ||
|
|
1e9801b0d4 | ||
|
|
eed82f2b6e | ||
|
|
a0f1545421 | ||
|
|
a69909ff23 | ||
|
|
65c99d3fbd | ||
|
|
687094fec0 | ||
|
|
757debaecc | ||
|
|
6d5dda80ee | ||
|
|
b9d9e965d5 | ||
|
|
e845df2a10 | ||
|
|
93cfc0e15d | ||
|
|
7a35bc2340 | ||
|
|
dc7eebb8ae | ||
|
|
1dfc967900 | ||
|
|
bb5217948d | ||
|
|
c2269711c5 | ||
|
|
e707b99860 | ||
|
|
ec43241ccc | ||
|
|
c45436dcf4 | ||
|
|
d41c3ee72b | ||
|
|
0058d0aa56 | ||
|
|
868638f031 | ||
|
|
a8250f17c3 | ||
|
|
c3bbc7e31c | ||
|
|
5d5565b832 | ||
|
|
5da0ff61b2 | ||
|
|
79efa87d39 | ||
|
|
a56981bc70 | ||
|
|
24f30bf18f | ||
|
|
0fa843fd78 | ||
|
|
aecee331a4 | ||
|
|
c1b7cc6d65 | ||
|
|
b8ddfa6537 | ||
|
|
fd4bd631e5 | ||
|
|
96b8901cde | ||
|
|
124033d122 | ||
|
|
cbb292b828 | ||
|
|
22b5fc2452 | ||
|
|
d549a314bc | ||
|
|
f32fe71dbc | ||
|
|
169cf14fa6 | ||
|
|
3befe007fd | ||
|
|
6d84bafa2e | ||
|
|
f3badc0ad4 | ||
|
|
df9887b629 | ||
|
|
cbecf5b954 | ||
|
|
040cccebe2 | ||
|
|
efffdf54c3 | ||
|
|
c3cb0c8968 | ||
|
|
d676c67b50 | ||
|
|
9316170c89 | ||
|
|
9101614d35 | ||
|
|
7312b2859d | ||
|
|
bf7d99ccba | ||
|
|
fb0d588cbf | ||
|
|
8e7bd6323a | ||
|
|
8bebd1933d | ||
|
|
2429b2c027 | ||
|
|
769820792f | ||
|
|
36f39b5023 | ||
|
|
bb675ee040 | ||
|
|
9b4aff7a3f | ||
|
|
e312d71286 | ||
|
|
a397c686b8 | ||
|
|
9b92005810 | ||
|
|
d4e0c8c3bb | ||
|
|
ae1ec9aaa2 | ||
|
|
e811bb9213 | ||
|
|
7de5d90c82 | ||
|
|
bf5265c15b | ||
|
|
49b111a0e9 | ||
|
|
85964d9f17 | ||
|
|
4f9075fa77 | ||
|
|
0856c9005c | ||
|
|
31d8bccfcf | ||
|
|
9213e3d3ef | ||
|
|
3665079cc9 | ||
|
|
44881e521c | ||
|
|
c136d8050b | ||
|
|
a5cc04b46f | ||
|
|
a9a8b6314b | ||
|
|
5c7be3bcfc | ||
|
|
e3893198af | ||
|
|
6a4e6dc5a1 | ||
|
|
643916f733 | ||
|
|
e964851d53 | ||
|
|
79e495dc14 | ||
|
|
13326879f0 | ||
|
|
293a871db4 | ||
|
|
4c9dc6350d | ||
|
|
4c54afdc55 | ||
|
|
d60841b040 | ||
|
|
7e640f47a5 | ||
|
|
f3d1b273f1 | ||
|
|
e80f5b85e9 | ||
|
|
1b5725caee | ||
|
|
820e8f8323 | ||
|
|
30672e52bb | ||
|
|
ac9796f50d | ||
|
|
66b7b4cad0 | ||
|
|
f417b9cc73 | ||
|
|
a304d4643c | ||
|
|
8386e5a2b5 | ||
|
|
27f57b96c0 | ||
|
|
d9a049d523 | ||
|
|
f53f724b04 | ||
|
|
a41105656a | ||
|
|
54269abfd1 | ||
|
|
e812ff1337 | ||
|
|
ae28f8f239 | ||
|
|
470f261dc0 | ||
|
|
80cfda23b6 | ||
|
|
5321c4d52b | ||
|
|
0466912f3e | ||
|
|
3d3932e657 | ||
|
|
d63117a17a | ||
|
|
ba06a72326 | ||
|
|
2671f6ca61 | ||
|
|
8dddfcbc92 | ||
|
|
ebc5793f36 | ||
|
|
4946221651 | ||
|
|
de9817a97f | ||
|
|
1218c4f385 | ||
|
|
e9cee62d03 | ||
|
|
fa7cf37eab | ||
|
|
b9ecb7556f | ||
|
|
661b38e1e6 | ||
|
|
769f4ba589 | ||
|
|
6118253ebf | ||
|
|
0f7f717330 | ||
|
|
0b16f1eb97 | ||
|
|
e733894c02 | ||
|
|
c47dcfbe27 | ||
|
|
8ae008ec9d | ||
|
|
45ef0c78a3 | ||
|
|
3ac46f239e | ||
|
|
1e106f7ada | ||
|
|
09738b2dd7 | ||
|
|
dc67a0b0fc | ||
|
|
1258bbc770 | ||
|
|
5960318a60 | ||
|
|
d4faf758f4 | ||
|
|
f88216b9a0 | ||
|
|
e21d648588 | ||
|
|
dbcbdc9bbc | ||
|
|
c5d16e8381 | ||
|
|
ac1aa6f3b1 | ||
|
|
866c222c74 | ||
|
|
06843477cb | ||
|
|
9a7a6fc6ab | ||
|
|
4986da415f | ||
|
|
cdbd20b794 | ||
|
|
49567ade65 | ||
|
|
4d857449d2 | ||
|
|
dc03621a14 | ||
|
|
b83cca17e2 | ||
|
|
343afffd40 | ||
|
|
163eac9511 | ||
|
|
167bfcb0b3 | ||
|
|
f0f94eb84c | ||
|
|
7123c9ca12 | ||
|
|
41e12d8e54 | ||
|
|
473ab14ae6 | ||
|
|
127ffd451c | ||
|
|
32bb43b66f | ||
|
|
765f5acbcc | ||
|
|
8ac137f22d | ||
|
|
10bbf6b157 | ||
|
|
390dc0605b | ||
|
|
6fda9f0691 | ||
|
|
0a1c5830d2 | ||
|
|
33efa2316d | ||
|
|
b3de9374a7 | ||
|
|
1d869e8d2b | ||
|
|
56156dd5ff | ||
|
|
35c9f55c41 | ||
|
|
e70e3559eb | ||
|
|
5957439475 | ||
|
|
322ed552ed | ||
|
|
bf848d5ef8 | ||
|
|
285057a9df | ||
|
|
4de62ffa55 | ||
|
|
f97fde1387 | ||
|
|
8a5bba625c | ||
|
|
108a209ac8 | ||
|
|
8390a4aba9 | ||
|
|
9740416e56 | ||
|
|
8cc82642f9 | ||
|
|
5f4804f4cf | ||
|
|
24dbee5d3d | ||
|
|
298f84d25e | ||
|
|
182c66f0a9 | ||
|
|
fd11c34646 | ||
|
|
6bcc7388bb | ||
|
|
60da0c0082 | ||
|
|
2b2b48bec4 | ||
|
|
d579f79399 | ||
|
|
bf85df68b3 | ||
|
|
e6e7ec49df | ||
|
|
e7801e1222 | ||
|
|
3327254022 |
244
.editorconfig
Normal file
244
.editorconfig
Normal file
@@ -0,0 +1,244 @@
|
||||
# Remove the line below if you want to inherit .editorconfig settings from higher directories
|
||||
root = true
|
||||
|
||||
# C# files
|
||||
[*.cs]
|
||||
|
||||
#### Core EditorConfig Options ####
|
||||
|
||||
# Indentation and spacing
|
||||
indent_size = 4
|
||||
indent_style = space
|
||||
tab_width = 4
|
||||
|
||||
# New line preferences
|
||||
end_of_line = crlf
|
||||
insert_final_newline = false
|
||||
|
||||
#### .NET Code Actions ####
|
||||
|
||||
# Type members
|
||||
dotnet_hide_advanced_members = false
|
||||
dotnet_member_insertion_location = with_other_members_of_the_same_kind
|
||||
dotnet_property_generation_behavior = prefer_throwing_properties
|
||||
|
||||
# Symbol search
|
||||
dotnet_search_reference_assemblies = true
|
||||
|
||||
#### .NET Coding Conventions ####
|
||||
|
||||
# Organize usings
|
||||
dotnet_separate_import_directive_groups = false
|
||||
dotnet_sort_system_directives_first = false
|
||||
file_header_template = unset
|
||||
|
||||
# this. and Me. preferences
|
||||
dotnet_style_qualification_for_event = false
|
||||
dotnet_style_qualification_for_field = false
|
||||
dotnet_style_qualification_for_method = false
|
||||
dotnet_style_qualification_for_property = false
|
||||
|
||||
# Language keywords vs BCL types preferences
|
||||
dotnet_style_predefined_type_for_locals_parameters_members = true
|
||||
dotnet_style_predefined_type_for_member_access = true
|
||||
|
||||
# Parentheses preferences
|
||||
dotnet_style_parentheses_in_arithmetic_binary_operators = always_for_clarity
|
||||
dotnet_style_parentheses_in_other_binary_operators = always_for_clarity
|
||||
dotnet_style_parentheses_in_other_operators = never_if_unnecessary
|
||||
dotnet_style_parentheses_in_relational_binary_operators = always_for_clarity
|
||||
|
||||
# Modifier preferences
|
||||
dotnet_style_require_accessibility_modifiers = for_non_interface_members
|
||||
|
||||
# Expression-level preferences
|
||||
dotnet_prefer_system_hash_code = true
|
||||
dotnet_style_coalesce_expression = true
|
||||
dotnet_style_collection_initializer = true
|
||||
dotnet_style_explicit_tuple_names = true
|
||||
dotnet_style_namespace_match_folder = true
|
||||
dotnet_style_null_propagation = true
|
||||
dotnet_style_object_initializer = true
|
||||
dotnet_style_operator_placement_when_wrapping = beginning_of_line
|
||||
dotnet_style_prefer_auto_properties = true
|
||||
dotnet_style_prefer_collection_expression = when_types_loosely_match
|
||||
dotnet_style_prefer_compound_assignment = true
|
||||
dotnet_style_prefer_conditional_expression_over_assignment = true
|
||||
dotnet_style_prefer_conditional_expression_over_return = true
|
||||
dotnet_style_prefer_foreach_explicit_cast_in_source = when_strongly_typed
|
||||
dotnet_style_prefer_inferred_anonymous_type_member_names = true
|
||||
dotnet_style_prefer_inferred_tuple_names = true
|
||||
dotnet_style_prefer_is_null_check_over_reference_equality_method = true
|
||||
dotnet_style_prefer_simplified_boolean_expressions = true
|
||||
dotnet_style_prefer_simplified_interpolation = true
|
||||
|
||||
# Field preferences
|
||||
dotnet_style_readonly_field = true
|
||||
|
||||
# Parameter preferences
|
||||
dotnet_code_quality_unused_parameters = all
|
||||
|
||||
# Suppression preferences
|
||||
dotnet_remove_unnecessary_suppression_exclusions = none
|
||||
|
||||
# New line preferences
|
||||
dotnet_style_allow_multiple_blank_lines_experimental = true
|
||||
dotnet_style_allow_statement_immediately_after_block_experimental = true
|
||||
|
||||
#### C# Coding Conventions ####
|
||||
|
||||
# var preferences
|
||||
csharp_style_var_elsewhere = false
|
||||
csharp_style_var_for_built_in_types = false
|
||||
csharp_style_var_when_type_is_apparent = false
|
||||
|
||||
# Expression-bodied members
|
||||
csharp_style_expression_bodied_accessors = true
|
||||
csharp_style_expression_bodied_constructors = false
|
||||
csharp_style_expression_bodied_indexers = true
|
||||
csharp_style_expression_bodied_lambdas = true
|
||||
csharp_style_expression_bodied_local_functions = false
|
||||
csharp_style_expression_bodied_methods = false
|
||||
csharp_style_expression_bodied_operators = false
|
||||
csharp_style_expression_bodied_properties = true
|
||||
|
||||
# Pattern matching preferences
|
||||
csharp_style_pattern_matching_over_as_with_null_check = true
|
||||
csharp_style_pattern_matching_over_is_with_cast_check = true
|
||||
csharp_style_prefer_extended_property_pattern = true
|
||||
csharp_style_prefer_not_pattern = true
|
||||
csharp_style_prefer_pattern_matching = true
|
||||
csharp_style_prefer_switch_expression = true
|
||||
|
||||
# Null-checking preferences
|
||||
csharp_style_conditional_delegate_call = true
|
||||
|
||||
# Modifier preferences
|
||||
csharp_prefer_static_anonymous_function = true
|
||||
csharp_prefer_static_local_function = true
|
||||
csharp_preferred_modifier_order = public,private,protected,internal,static,extern,new,virtual,abstract,sealed,override,readonly,unsafe,volatile,async
|
||||
csharp_style_prefer_readonly_struct = true
|
||||
csharp_style_prefer_readonly_struct_member = true
|
||||
|
||||
# Code-block preferences
|
||||
csharp_prefer_braces = true
|
||||
csharp_prefer_simple_using_statement = true
|
||||
csharp_prefer_system_threading_lock = true
|
||||
csharp_style_namespace_declarations = block_scoped
|
||||
csharp_style_prefer_method_group_conversion = true
|
||||
csharp_style_prefer_primary_constructors = true
|
||||
csharp_style_prefer_top_level_statements = true
|
||||
|
||||
# Expression-level preferences
|
||||
csharp_prefer_simple_default_expression = true
|
||||
csharp_style_deconstructed_variable_declaration = true
|
||||
csharp_style_implicit_object_creation_when_type_is_apparent = true
|
||||
csharp_style_inlined_variable_declaration = true
|
||||
csharp_style_prefer_index_operator = true
|
||||
csharp_style_prefer_local_over_anonymous_function = true
|
||||
csharp_style_prefer_null_check_over_type_check = true
|
||||
csharp_style_prefer_range_operator = true
|
||||
csharp_style_prefer_tuple_swap = true
|
||||
csharp_style_prefer_utf8_string_literals = true
|
||||
csharp_style_throw_expression = true
|
||||
csharp_style_unused_value_assignment_preference = discard_variable
|
||||
csharp_style_unused_value_expression_statement_preference = discard_variable
|
||||
|
||||
# 'using' directive preferences
|
||||
csharp_using_directive_placement = outside_namespace
|
||||
|
||||
# New line preferences
|
||||
csharp_style_allow_blank_line_after_colon_in_constructor_initializer_experimental = true
|
||||
csharp_style_allow_blank_line_after_token_in_arrow_expression_clause_experimental = true
|
||||
csharp_style_allow_blank_line_after_token_in_conditional_expression_experimental = true
|
||||
csharp_style_allow_blank_lines_between_consecutive_braces_experimental = true
|
||||
csharp_style_allow_embedded_statements_on_same_line_experimental = true
|
||||
|
||||
#### C# Formatting Rules ####
|
||||
|
||||
# New line preferences
|
||||
csharp_new_line_before_catch = true
|
||||
csharp_new_line_before_else = true
|
||||
csharp_new_line_before_finally = true
|
||||
csharp_new_line_before_members_in_anonymous_types = true
|
||||
csharp_new_line_before_members_in_object_initializers = true
|
||||
csharp_new_line_before_open_brace = all
|
||||
csharp_new_line_between_query_expression_clauses = true
|
||||
|
||||
# Indentation preferences
|
||||
csharp_indent_block_contents = true
|
||||
csharp_indent_braces = false
|
||||
csharp_indent_case_contents = true
|
||||
csharp_indent_case_contents_when_block = true
|
||||
csharp_indent_labels = no_change
|
||||
csharp_indent_switch_labels = true
|
||||
|
||||
# Space preferences
|
||||
csharp_space_after_cast = false
|
||||
csharp_space_after_colon_in_inheritance_clause = true
|
||||
csharp_space_after_comma = true
|
||||
csharp_space_after_dot = false
|
||||
csharp_space_after_keywords_in_control_flow_statements = true
|
||||
csharp_space_after_semicolon_in_for_statement = true
|
||||
csharp_space_around_binary_operators = before_and_after
|
||||
csharp_space_around_declaration_statements = false
|
||||
csharp_space_before_colon_in_inheritance_clause = true
|
||||
csharp_space_before_comma = false
|
||||
csharp_space_before_dot = false
|
||||
csharp_space_before_open_square_brackets = false
|
||||
csharp_space_before_semicolon_in_for_statement = false
|
||||
csharp_space_between_empty_square_brackets = false
|
||||
csharp_space_between_method_call_empty_parameter_list_parentheses = false
|
||||
csharp_space_between_method_call_name_and_opening_parenthesis = false
|
||||
csharp_space_between_method_call_parameter_list_parentheses = false
|
||||
csharp_space_between_method_declaration_empty_parameter_list_parentheses = false
|
||||
csharp_space_between_method_declaration_name_and_open_parenthesis = false
|
||||
csharp_space_between_method_declaration_parameter_list_parentheses = false
|
||||
csharp_space_between_parentheses = false
|
||||
csharp_space_between_square_brackets = false
|
||||
|
||||
# Wrapping preferences
|
||||
csharp_preserve_single_line_blocks = true
|
||||
csharp_preserve_single_line_statements = true
|
||||
|
||||
#### Naming styles ####
|
||||
|
||||
# Naming rules
|
||||
|
||||
dotnet_naming_rule.interface_should_be_begins_with_i.severity = suggestion
|
||||
dotnet_naming_rule.interface_should_be_begins_with_i.symbols = interface
|
||||
dotnet_naming_rule.interface_should_be_begins_with_i.style = begins_with_i
|
||||
|
||||
dotnet_naming_rule.types_should_be_pascal_case.severity = suggestion
|
||||
dotnet_naming_rule.types_should_be_pascal_case.symbols = types
|
||||
dotnet_naming_rule.types_should_be_pascal_case.style = pascal_case
|
||||
|
||||
dotnet_naming_rule.non_field_members_should_be_pascal_case.severity = suggestion
|
||||
dotnet_naming_rule.non_field_members_should_be_pascal_case.symbols = non_field_members
|
||||
dotnet_naming_rule.non_field_members_should_be_pascal_case.style = pascal_case
|
||||
|
||||
# Symbol specifications
|
||||
|
||||
dotnet_naming_symbols.interface.applicable_kinds = interface
|
||||
dotnet_naming_symbols.interface.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected
|
||||
dotnet_naming_symbols.interface.required_modifiers =
|
||||
|
||||
dotnet_naming_symbols.types.applicable_kinds = class, struct, interface, enum
|
||||
dotnet_naming_symbols.types.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected
|
||||
dotnet_naming_symbols.types.required_modifiers =
|
||||
|
||||
dotnet_naming_symbols.non_field_members.applicable_kinds = property, event, method
|
||||
dotnet_naming_symbols.non_field_members.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected
|
||||
dotnet_naming_symbols.non_field_members.required_modifiers =
|
||||
|
||||
# Naming styles
|
||||
|
||||
dotnet_naming_style.pascal_case.required_prefix =
|
||||
dotnet_naming_style.pascal_case.required_suffix =
|
||||
dotnet_naming_style.pascal_case.word_separator =
|
||||
dotnet_naming_style.pascal_case.capitalization = pascal_case
|
||||
|
||||
dotnet_naming_style.begins_with_i.required_prefix = I
|
||||
dotnet_naming_style.begins_with_i.required_suffix =
|
||||
dotnet_naming_style.begins_with_i.word_separator =
|
||||
dotnet_naming_style.begins_with_i.capitalization = pascal_case
|
||||
8
.github/workflows/ci.yml
vendored
8
.github/workflows/ci.yml
vendored
@@ -15,11 +15,13 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Setup .NET
|
||||
uses: actions/setup-dotnet@v3
|
||||
uses: actions/setup-dotnet@v4
|
||||
with:
|
||||
dotnet-version: 8.0.x
|
||||
dotnet-version: 9.0.x
|
||||
|
||||
- name: Build
|
||||
run: dotnet build Radzen.Blazor/Radzen.Blazor.csproj
|
||||
- name: Test
|
||||
|
||||
@@ -17,7 +17,7 @@ COPY RadzenBlazorDemos.Host /app/RadzenBlazorDemos.Host
|
||||
WORKDIR /app
|
||||
RUN docfx DocFX/docfx.json
|
||||
|
||||
FROM mcr.microsoft.com/dotnet/sdk:8.0
|
||||
FROM mcr.microsoft.com/dotnet/sdk:9.0
|
||||
|
||||
COPY --from=0 /app/RadzenBlazorDemos.Host /app/RadzenBlazorDemos.Host
|
||||
COPY --from=0 /app/RadzenBlazorDemos /app/RadzenBlazorDemos
|
||||
|
||||
2
LICENSE
2
LICENSE
@@ -1,6 +1,6 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2018-2024 Radzen Ltd
|
||||
Copyright (c) 2018-2025 Radzen Ltd
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
|
||||
@@ -30,7 +30,7 @@ namespace Radzen.Blazor.Tests
|
||||
|
||||
component.SetParametersAndRender(parameters => parameters.Add(p => p.Icon, icon));
|
||||
|
||||
Assert.Contains(@$"<i class=""rz-button-icon-left rzi"">{icon}</i>", component.Markup);
|
||||
Assert.Contains(@$"<i class=""notranslate rz-button-icon-left rzi"">{icon}</i>", component.Markup);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
@@ -48,7 +48,7 @@ namespace Radzen.Blazor.Tests
|
||||
);
|
||||
|
||||
// does not render the actual icon when busy
|
||||
Assert.DoesNotContain(@$"<i class=""rz-button-icon-left rzi"">{icon}</i>", component.Markup);
|
||||
Assert.DoesNotContain(@$"<i class=""notranslate rz-button-icon-left rzi"">{icon}</i>", component.Markup);
|
||||
|
||||
// renders the icon with busy spin animation
|
||||
Assert.Contains(@"<i style=""animation: rotation", component.Markup);
|
||||
@@ -71,7 +71,7 @@ namespace Radzen.Blazor.Tests
|
||||
parameters.Add(p => p.Icon, icon);
|
||||
});
|
||||
|
||||
Assert.Contains(@$"<i class=""rz-button-icon-left rzi"">{icon}</i>", component.Markup);
|
||||
Assert.Contains(@$"<i class=""notranslate rz-button-icon-left rzi"">{icon}</i>", component.Markup);
|
||||
Assert.Contains(@$"<span class=""rz-button-text"">{text}</span>", component.Markup);
|
||||
}
|
||||
|
||||
@@ -86,7 +86,7 @@ namespace Radzen.Blazor.Tests
|
||||
|
||||
component.SetParametersAndRender(parameters => parameters.Add(p => p.Image, image));
|
||||
|
||||
Assert.Contains(@$"<img class=""rz-button-icon-left rzi"" src=""{image}"" alt=""button"" />", component.Markup);
|
||||
Assert.Contains(@$"<img class=""notranslate rz-button-icon-left rzi"" src=""{image}"" alt=""button"" />", component.Markup);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
@@ -106,7 +106,7 @@ namespace Radzen.Blazor.Tests
|
||||
parameters.Add(p => p.ImageAlternateText, text);
|
||||
});
|
||||
|
||||
Assert.Contains(@$"<img class=""rz-button-icon-left rzi"" src=""{image}"" alt=""{text}"" />", component.Markup);
|
||||
Assert.Contains(@$"<img class=""notranslate rz-button-icon-left rzi"" src=""{image}"" alt=""{text}"" />", component.Markup);
|
||||
Assert.Contains(@$"<span class=""rz-button-text"">{text}</span>", component.Markup);
|
||||
}
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@ using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Bunit;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Radzen.Blazor.Rendering;
|
||||
using Xunit;
|
||||
using Xunit.Abstractions;
|
||||
@@ -23,6 +24,9 @@ public class ChartTests
|
||||
using var ctx = new TestContext();
|
||||
ctx.JSInterop.Mode = JSRuntimeMode.Loose;
|
||||
ctx.JSInterop.Setup<Rect>("Radzen.createChart", _ => true).SetResult(new Rect {Left = 0, Top = 0, Width = 200, Height = 200});
|
||||
ctx.Services.AddScoped<TooltipService>();
|
||||
ctx.JSInterop.SetupVoid("Radzen.openChartTooltip", _ => true);
|
||||
ctx.RenderComponent<RadzenChartTooltip>();
|
||||
|
||||
var seriesData = Enumerable.Range(0, 5000).Select(i => new Point { X = i, Y = i });
|
||||
var chart = ctx.RenderComponent<RadzenChart>(chartParameters =>
|
||||
@@ -42,12 +46,12 @@ public class ChartTests
|
||||
})));
|
||||
|
||||
var stopwatch = Stopwatch.StartNew();
|
||||
foreach (var _ in Enumerable.Range(0, 10))
|
||||
foreach (var invocation in Enumerable.Range(0, 10))
|
||||
{
|
||||
await chart.InvokeAsync(() => chart.Instance.MouseMove(100, 80));
|
||||
Assert.Contains("<div class=\"rz-chart-tooltip", chart.Markup);
|
||||
Assert.Equal((invocation + 1) * 2, ctx.JSInterop.Invocations.Count(x => x.Identifier == "Radzen.openChartTooltip"));
|
||||
await chart.InvokeAsync(() => chart.Instance.MouseMove(0, 0));
|
||||
Assert.DoesNotContain("<div class=\"rz-chart-tooltip", chart.Markup);
|
||||
Assert.Equal(invocation + 1, ctx.JSInterop.Invocations.Count(x => x.Identifier == "Radzen.closeTooltip"));
|
||||
}
|
||||
output.WriteLine($"Time took: {stopwatch.Elapsed}");
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@ using Microsoft.AspNetCore.Components.Rendering;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading.Tasks;
|
||||
using Xunit;
|
||||
|
||||
namespace Radzen.Blazor.Tests
|
||||
@@ -362,6 +362,82 @@ namespace Radzen.Blazor.Tests
|
||||
component.Find(".rz-sortable-column").FirstElementChild.Click();
|
||||
|
||||
Assert.Contains(@$"rzi-sort-desc", component.Markup);
|
||||
|
||||
component.Find(".rz-sortable-column").FirstElementChild.Click();
|
||||
|
||||
Assert.DoesNotContain(@$"rzi-sort-desc", component.Markup);
|
||||
Assert.DoesNotContain(@$"rzi-sort-asc", component.Markup);
|
||||
}
|
||||
|
||||
|
||||
// clear Sorting tests
|
||||
[Fact]
|
||||
public void DataGrid_Renders_ClearSorting()
|
||||
{
|
||||
using var ctx = new TestContext();
|
||||
ctx.JSInterop.Mode = JSRuntimeMode.Loose;
|
||||
ctx.JSInterop.SetupModule("_content/Radzen.Blazor/Radzen.Blazor.js");
|
||||
|
||||
var component = ctx.RenderComponent<RadzenDataGrid<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 =>
|
||||
{
|
||||
builder.OpenComponent(0, typeof(RadzenDataGridColumn<dynamic>));
|
||||
builder.AddAttribute(1, "Property", "Id");
|
||||
builder.AddAttribute(2, "Title", "Id");
|
||||
builder.CloseComponent();
|
||||
});
|
||||
parameterBuilder.Add<bool>(p => p.AllowSorting, true);
|
||||
});
|
||||
|
||||
component.Find(".rz-sortable-column").FirstElementChild.Click();
|
||||
Assert.Contains(@$"rzi-sort-asc", component.Markup);
|
||||
|
||||
component.Instance.Sorts.Clear();
|
||||
|
||||
Assert.DoesNotContain(@$"rzi-sort-desc", component.Markup);
|
||||
Assert.DoesNotContain(@$"rzi-sort-asc", component.Markup);
|
||||
}
|
||||
|
||||
// sorting with load data event test.
|
||||
[Fact]
|
||||
public void DataGrid_Renders_LoadDataWithOrdering()
|
||||
{
|
||||
using var ctx = new TestContext();
|
||||
ctx.JSInterop.Mode = JSRuntimeMode.Loose;
|
||||
ctx.JSInterop.SetupModule("_content/Radzen.Blazor/Radzen.Blazor.js");
|
||||
|
||||
List<LoadDataArgs> loadDataArgs = [];
|
||||
|
||||
var component = ctx.RenderComponent<RadzenDataGrid<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 =>
|
||||
{
|
||||
builder.OpenComponent(0, typeof(RadzenDataGridColumn<dynamic>));
|
||||
builder.AddAttribute(1, "Property", "Id");
|
||||
builder.AddAttribute(2, "Title", "Id");
|
||||
builder.CloseComponent();
|
||||
});
|
||||
parameterBuilder.Add<bool>(p => p.AllowSorting, true);
|
||||
parameterBuilder.Add(p => p.LoadData, args => loadDataArgs.Add(args));
|
||||
});
|
||||
|
||||
component.Find(".rz-sortable-column").FirstElementChild.Click();
|
||||
Assert.Contains(@$"rzi-sort-asc", component.Markup);
|
||||
|
||||
component.Instance.Sorts.Clear();
|
||||
component.Render();
|
||||
|
||||
Assert.DoesNotContain(@$"rzi-sort-desc", component.Markup);
|
||||
Assert.DoesNotContain(@$"rzi-sort-asc", component.Markup);
|
||||
|
||||
Assert.Equal(4, loadDataArgs.Count);
|
||||
Assert.Equal("", loadDataArgs[0].OrderBy);
|
||||
Assert.Equal("Id asc", loadDataArgs[1].OrderBy);
|
||||
Assert.Equal("Id asc", loadDataArgs[2].OrderBy);
|
||||
Assert.Equal("", loadDataArgs[3].OrderBy);
|
||||
}
|
||||
|
||||
// Paging tests
|
||||
@@ -824,10 +900,14 @@ namespace Radzen.Blazor.Tests
|
||||
|
||||
component.SetParametersAndRender(parameters =>
|
||||
{
|
||||
parameters.Add<int>(p => p.PageSize, 20);
|
||||
parameters.Add<LoadDataArgs>(p => p.LoadData, args => { raised = true; newArgs = args; });
|
||||
});
|
||||
|
||||
component.SetParametersAndRender(parameters =>
|
||||
{
|
||||
parameters.Add<int>(p => p.PageSize, 20);
|
||||
});
|
||||
|
||||
component.Find(".rz-pager-next").Click();
|
||||
|
||||
Assert.True(raised);
|
||||
|
||||
@@ -155,7 +155,7 @@ namespace Radzen.Blazor.Tests
|
||||
parameters.Add<bool>(p => p.AllowClear, true);
|
||||
});
|
||||
|
||||
Assert.Contains(@$"<i class=""rz-dropdown-clear-icon rzi rzi-times""", component.Markup);
|
||||
Assert.Contains(@$"<i class=""notranslate rz-dropdown-clear-icon rzi rzi-times""", component.Markup);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
@@ -174,6 +174,34 @@ namespace Radzen.Blazor.Tests
|
||||
Assert.Contains(@$"tabindex=""{value}""", component.Markup);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void DatePicker_Renders_EmptyCssClass_WhenValueIsEmpty()
|
||||
{
|
||||
using var ctx = new TestContext();
|
||||
ctx.JSInterop.Mode = JSRuntimeMode.Loose;
|
||||
ctx.JSInterop.SetupModule("_content/Radzen.Blazor/Radzen.Blazor.js");
|
||||
|
||||
var component = ctx.RenderComponent<RadzenDatePicker<DateTime>>();
|
||||
|
||||
component.SetParametersAndRender(parameters => parameters.Add(p => p.Value, null));
|
||||
|
||||
Assert.Contains(@$"rz-state-empty", component.Markup);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void DatePicker_DoesNotRender_EmptyCssClass_WhenValueIsNotEmpty()
|
||||
{
|
||||
using var ctx = new TestContext();
|
||||
ctx.JSInterop.Mode = JSRuntimeMode.Loose;
|
||||
ctx.JSInterop.SetupModule("_content/Radzen.Blazor/Radzen.Blazor.js");
|
||||
|
||||
var component = ctx.RenderComponent<RadzenDatePicker<DateTime>>();
|
||||
|
||||
component.SetParametersAndRender(parameters => parameters.Add(p => p.Value, DateTime.Now));
|
||||
|
||||
Assert.DoesNotContain(@$"rz-state-empty", component.Markup);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void DatePicker_Renders_DisabledParameter()
|
||||
{
|
||||
|
||||
@@ -43,7 +43,7 @@ public class DollarsTypeConverter : TypeConverter
|
||||
return new Dollars(d);
|
||||
|
||||
if (value is string s)
|
||||
return decimal.TryParse(s, out var val) ? new Dollars(val) : null;
|
||||
return decimal.TryParse(s, culture, out var val) ? new Dollars(val) : null;
|
||||
|
||||
return base.ConvertFrom(context, culture, value);
|
||||
}
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using AngleSharp.Dom;
|
||||
using Bunit;
|
||||
@@ -13,18 +15,20 @@ namespace Radzen.Blazor.Tests
|
||||
{
|
||||
public string Text { get; set; }
|
||||
public int Id { get; set; }
|
||||
public bool Disabled { get; set; } = false;
|
||||
}
|
||||
|
||||
private static IRenderedComponent<RadzenDropDown<T>> DropDown<T>(TestContext ctx, Action<ComponentParameterCollectionBuilder<RadzenDropDown<T>>> configure = null)
|
||||
{
|
||||
var data = new [] {
|
||||
var data = new[] {
|
||||
new DataItem { Text = "Item 1", Id = 1 },
|
||||
new DataItem { Text = "Item 2", Id = 2 },
|
||||
};
|
||||
|
||||
var component = ctx.RenderComponent<RadzenDropDown<T>>();
|
||||
|
||||
component.SetParametersAndRender(parameters => {
|
||||
component.SetParametersAndRender(parameters =>
|
||||
{
|
||||
parameters.Add(p => p.Data, data);
|
||||
parameters.Add(p => p.TextProperty, nameof(DataItem.Text));
|
||||
|
||||
@@ -99,7 +103,8 @@ namespace Radzen.Blazor.Tests
|
||||
|
||||
ctx.JSInterop.Mode = JSRuntimeMode.Loose;
|
||||
|
||||
var component = DropDown<string>(ctx, parameters => {
|
||||
var component = DropDown<string>(ctx, parameters =>
|
||||
{
|
||||
parameters.Add(p => p.ValueProperty, nameof(DataItem.Text));
|
||||
});
|
||||
|
||||
@@ -114,6 +119,35 @@ namespace Radzen.Blazor.Tests
|
||||
Assert.Contains("rz-state-highlight", items[0].ClassList);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void DropDown_Respects_ItemEqualityComparer()
|
||||
{
|
||||
using var ctx = new TestContext();
|
||||
ctx.JSInterop.Mode = JSRuntimeMode.Loose;
|
||||
|
||||
List<DataItem> boundCollection = [new() { Text = "Item 2" }];
|
||||
|
||||
var component = DropDown<string>(ctx, parameters =>
|
||||
{
|
||||
parameters.Add(p => p.ItemComparer, new DataItemComparer());
|
||||
parameters.Add(p => p.Multiple, true);
|
||||
parameters.Add(p => p.Value, boundCollection);
|
||||
});
|
||||
|
||||
var selectedItems = component.FindAll(".rz-state-highlight");
|
||||
Assert.Equal(1, selectedItems.Count);
|
||||
Assert.Equal("Item 2", selectedItems[0].TextContent.Trim());
|
||||
|
||||
// select Item 1 in list
|
||||
var items = component.FindAll(".rz-multiselect-item");
|
||||
items[0].Click();
|
||||
component.Render();
|
||||
|
||||
selectedItems = component.FindAll(".rz-state-highlight");
|
||||
Assert.Equal(2, selectedItems.Count);
|
||||
Assert.Equal("Item 1", selectedItems[0].TextContent.Trim());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void DropDown_AppliesSelectionStyleWhenMultipleSelectionIsEnabled()
|
||||
{
|
||||
@@ -121,7 +155,8 @@ namespace Radzen.Blazor.Tests
|
||||
|
||||
ctx.JSInterop.Mode = JSRuntimeMode.Loose;
|
||||
|
||||
var component = DropDown<string>(ctx, parameters => {
|
||||
var component = DropDown<string>(ctx, parameters =>
|
||||
{
|
||||
parameters.Add(p => p.ValueProperty, nameof(DataItem.Text));
|
||||
parameters.Add(p => p.Multiple, true);
|
||||
});
|
||||
@@ -245,5 +280,78 @@ namespace Radzen.Blazor.Tests
|
||||
|
||||
Assert.Collection(selectedItems, item => Assert.Contains("value: Item 1", item.Text()), item => Assert.Contains("value: Item 2", item.Text()));
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(false, true, false, true, "false")]
|
||||
[InlineData(true, false, true, false, "true")]
|
||||
[InlineData(true, false, false, false, "false")]
|
||||
[InlineData(true, false, false, true, "true")]
|
||||
[InlineData(false, false, false, true, "false")]
|
||||
public void DropDown_AllSelectedFalseIfListIsAllDisabled(bool item1Selected, bool item1Disabled, bool item2Selected, bool item2Disabled, string expectedAriaCheckedValue)
|
||||
{
|
||||
using var ctx = new TestContext();
|
||||
ctx.JSInterop.Mode = JSRuntimeMode.Loose;
|
||||
|
||||
var data = new[] {
|
||||
new DataItem { Text = "Item 1", Id = 1, Disabled = item1Disabled },
|
||||
new DataItem { Text = "Item 2", Id = 2, Disabled = item2Disabled },
|
||||
};
|
||||
|
||||
List<int> selectedValues = [];
|
||||
if (item1Selected)
|
||||
{
|
||||
selectedValues.Add(data[0].Id);
|
||||
}
|
||||
if (item2Selected)
|
||||
{
|
||||
selectedValues.Add(data[1].Id);
|
||||
}
|
||||
|
||||
var component = ctx.RenderComponent<RadzenDropDown<DataItem>>(parameters => parameters
|
||||
.Add(p => p.Data, data)
|
||||
.Add(p => p.Value, selectedValues)
|
||||
.Add(p => p.Multiple, true)
|
||||
.Add(p => p.AllowSelectAll, true)
|
||||
.Add(p => p.TextProperty, nameof(DataItem.Text))
|
||||
.Add(p => p.DisabledProperty, nameof(DataItem.Disabled))
|
||||
.Add(p => p.ValueProperty, nameof(DataItem.Id)));
|
||||
|
||||
Assert.NotNull(component);
|
||||
var highlightedItems = component.FindAll(".rz-state-highlight");
|
||||
Assert.Equal(selectedValues.Count, highlightedItems.Count);
|
||||
|
||||
|
||||
var selectAllCheckBox = component.Find(".rz-multiselect-header input[type='checkbox']");
|
||||
|
||||
Assert.Equal(expectedAriaCheckedValue, selectAllCheckBox.GetAttribute("aria-checked"));
|
||||
}
|
||||
|
||||
class DataItemComparer : IEqualityComparer<DataItem>, IEqualityComparer<object>
|
||||
{
|
||||
public bool Equals(DataItem x, DataItem y)
|
||||
{
|
||||
if (ReferenceEquals(x, y)) return true;
|
||||
if (x is null) return false;
|
||||
if (y is null) return false;
|
||||
if (x.GetType() != y.GetType()) return false;
|
||||
return x.Text == y.Text;
|
||||
}
|
||||
|
||||
public int GetHashCode(DataItem obj)
|
||||
{
|
||||
return obj.Text.GetHashCode();
|
||||
}
|
||||
|
||||
public new bool Equals(object x, object y)
|
||||
{
|
||||
return Equals((DataItem)x, (DataItem)y);
|
||||
}
|
||||
|
||||
public int GetHashCode(object obj)
|
||||
{
|
||||
return GetHashCode((DataItem)obj);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
423
Radzen.Blazor.Tests/ExpressionParserTests.cs
Normal file
423
Radzen.Blazor.Tests/ExpressionParserTests.cs
Normal file
@@ -0,0 +1,423 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Linq.Dynamic.Core;
|
||||
using Xunit;
|
||||
|
||||
namespace Radzen.Blazor.Tests
|
||||
{
|
||||
public enum CarType
|
||||
{
|
||||
Sedan,
|
||||
Coupe
|
||||
}
|
||||
|
||||
public class ExpressionParserTests
|
||||
{
|
||||
class Person
|
||||
{
|
||||
public short? Age { get; set; }
|
||||
public string Name { get; set; }
|
||||
public bool? Famous { get; set; }
|
||||
public DateTime BirthDate { get; set; }
|
||||
}
|
||||
|
||||
public class Car
|
||||
{
|
||||
public CarType Type { get; set; }
|
||||
}
|
||||
|
||||
public enum Status
|
||||
{
|
||||
Office,
|
||||
Remote,
|
||||
}
|
||||
class OrderDetail
|
||||
{
|
||||
public Product Product { get; set; }
|
||||
public int Quantity { get; set; }
|
||||
public Order Order { get; set; }
|
||||
|
||||
public List<WorkStatus> WorkStatuses { get; set; }
|
||||
public List<Status> Statuses { get; set; }
|
||||
}
|
||||
|
||||
class Category
|
||||
{
|
||||
public string CategoryName { get; set; }
|
||||
|
||||
}
|
||||
|
||||
class Order
|
||||
{
|
||||
public DateTime OrderDate { get; set; }
|
||||
}
|
||||
|
||||
class Product
|
||||
{
|
||||
public string ProductName { get; set; }
|
||||
|
||||
public Category Category { get; set; }
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Should_ParseBindaryExpression()
|
||||
{
|
||||
var expression = ExpressionParser.ParsePredicate<Person>("p => p.Name == \"foo\"");
|
||||
|
||||
var func = expression.Compile();
|
||||
|
||||
Assert.True(func(new Person() { Name = "foo" }));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Should_ParseConditionalExpression()
|
||||
{
|
||||
var expression = ExpressionParser.ParsePredicate<OrderDetail>("it => (it.Product.ProductName == null ? \"\" : it.Product.ProductName).Contains(\"Queso\") && it.Quantity == 50");
|
||||
|
||||
var func = expression.Compile();
|
||||
|
||||
Assert.True(func(new OrderDetail() { Product = new Product { ProductName = "Queso" }, Quantity = 50 }));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Should_ParseNestedLogicalOperations()
|
||||
{
|
||||
var expression = ExpressionParser.ParsePredicate<OrderDetail>("it => (it.Product.ProductName == null ? \"\" : it.Product.ProductName).Contains(\"Queso\") && (it.Quantity == 50 || it.Quantity == 12)");
|
||||
|
||||
var func = expression.Compile();
|
||||
|
||||
Assert.True(func(new OrderDetail() { Product = new Product { ProductName = "Queso" }, Quantity = 12 }));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Should_SupportDateTimeParsing()
|
||||
{
|
||||
var expression = ExpressionParser.ParsePredicate<OrderDetail>("it => it.Order.OrderDate >= DateTime.Parse(\"2025-02-11\")");
|
||||
|
||||
var func = expression.Compile();
|
||||
Assert.True(func(new OrderDetail { Order = new Order { OrderDate = new DateTime(2025, 2, 11) } }));
|
||||
}
|
||||
|
||||
class ItemWithGenericProperty<T>
|
||||
{
|
||||
public T Value { get; set; }
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Should_SupportDateOnlyParsing()
|
||||
{
|
||||
var expression = ExpressionParser.ParsePredicate<ItemWithGenericProperty<DateOnly>>("it => it.Value >= DateOnly.Parse(\"2025-02-11\")");
|
||||
|
||||
var func = expression.Compile();
|
||||
|
||||
Assert.True(func(new ItemWithGenericProperty<DateOnly> { Value = new DateOnly(2025, 2, 11) }));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Should_SupportTimeOnlyParsing()
|
||||
{
|
||||
var expression = ExpressionParser.ParsePredicate<ItemWithGenericProperty<TimeOnly>>("it => it.Value >= TimeOnly.Parse(\"12:00:00\")");
|
||||
var func = expression.Compile();
|
||||
Assert.True(func(new ItemWithGenericProperty<TimeOnly> { Value = new TimeOnly(12, 0, 0) }));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Should_SupportGuidParsing()
|
||||
{
|
||||
var expression = ExpressionParser.ParsePredicate<ItemWithGenericProperty<Guid>>("it => it.Value == Guid.Parse(\"f0e7e7d8-4f4d-4b5f-8b3e-3f1d1b4f5f5f\")");
|
||||
var func = expression.Compile();
|
||||
Assert.True(func(new ItemWithGenericProperty<Guid> { Value = Guid.Parse("f0e7e7d8-4f4d-4b5f-8b3e-3f1d1b4f5f5f") }));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Should_SupportDateTimeOffsetParsing()
|
||||
{
|
||||
var expression = ExpressionParser.ParsePredicate<ItemWithGenericProperty<DateTimeOffset>>("it => it.Value == DateTimeOffset.Parse(\"2025-02-11\")");
|
||||
var func = expression.Compile();
|
||||
Assert.True(func(new ItemWithGenericProperty<DateTimeOffset> { Value = DateTimeOffset.Parse("2025-02-11") }));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Should_SupportEnumWithCasts()
|
||||
{
|
||||
var typeLocator = (string type) => AppDomain.CurrentDomain.GetAssemblies().SelectMany(a => a.GetTypes()).FirstOrDefault(t => t.FullName == type);
|
||||
|
||||
var expression = ExpressionParser.ParsePredicate<ItemWithGenericProperty<CarType[]>>("it => it.Value.Any(i => (new []{0}).Contains(i))", typeLocator);
|
||||
|
||||
var func = expression.Compile();
|
||||
|
||||
Assert.True(func(new ItemWithGenericProperty<CarType[]> { Value = [CarType.Sedan] }));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Should_SupportNullableCollection()
|
||||
{
|
||||
var expression = ExpressionParser.ParsePredicate<Person>("it => new bool?[]{ false }.Contains(it.Famous)");
|
||||
var func = expression.Compile();
|
||||
|
||||
Assert.True(func(new Person { Famous = false }));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Should_SupportEnumCollections()
|
||||
{
|
||||
var typeLocator = (string type) => AppDomain.CurrentDomain.GetAssemblies().SelectMany(a => a.GetTypes()).FirstOrDefault(t => t.FullName == type);
|
||||
|
||||
var expression = ExpressionParser.ParsePredicate<Car>($"it => it.Type == (Radzen.Blazor.Tests.CarType)1", typeLocator);
|
||||
|
||||
var func = expression.Compile();
|
||||
|
||||
Assert.True(func(new Car { Type = CarType.Coupe }));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Should_SupportCollectionLiterals()
|
||||
{
|
||||
var expression = ExpressionParser.ParsePredicate<OrderDetail>("it => (new []{\"Tofu\"}).Contains(it.Product.ProductName)");
|
||||
var func = expression.Compile();
|
||||
|
||||
Assert.True(func(new OrderDetail { Product = new Product { ProductName = "Tofu" } }));
|
||||
}
|
||||
|
||||
class WorkStatus
|
||||
{
|
||||
public string Name { get; set; }
|
||||
}
|
||||
|
||||
|
||||
[Fact]
|
||||
public void Should_SupportNestedLambdas()
|
||||
{
|
||||
var expression = ExpressionParser.ParsePredicate<OrderDetail>("it => it.WorkStatuses.Any(i => (new []{\"Office\"}).Contains(i.Name))");
|
||||
var func = expression.Compile();
|
||||
|
||||
Assert.True(func(new OrderDetail { WorkStatuses = [new() { Name = "Office" }] }));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Should_SupportNestedLambdasWithNot()
|
||||
{
|
||||
var expression = ExpressionParser.ParsePredicate<OrderDetail>("it => it.WorkStatuses.Any(i => !(new []{\"Office\"}).Contains(i.Name))");
|
||||
var func = expression.Compile();
|
||||
|
||||
Assert.False(func(new OrderDetail { WorkStatuses = [new() { Name = "Office" }] }));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Should_SupportNestedLambdasWithEnums()
|
||||
{
|
||||
var expression = ExpressionParser.ParsePredicate<OrderDetail>("it => it.Statuses.Any(i => (new []{1}).Contains(i))");
|
||||
var func = expression.Compile();
|
||||
|
||||
Assert.True(func(new OrderDetail { Statuses = new List<Status>() { (Status)1 } }));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Should_SupportNestedLambdasWithComplexMethod()
|
||||
{
|
||||
var expression = ExpressionParser.ParsePredicate<OrderDetail>("it => new [] { (Status)1 }.Intersect(it.Statuses).Any()", type => typeof(Status));
|
||||
var func = expression.Compile();
|
||||
|
||||
Assert.True(func(new OrderDetail { Statuses = new List<Status>() { (Status)1 } }));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Should_SupportToLower()
|
||||
{
|
||||
var expression = ExpressionParser.ParsePredicate<Person>("it => (it.Name == null ? \"\" : it.Name).ToLower().Contains(\"na\".ToLower())");
|
||||
|
||||
var func = expression.Compile();
|
||||
|
||||
Assert.True(func(new Person { Name = "Nana" }));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Should_SupportNullableProperties()
|
||||
{
|
||||
var expression = ExpressionParser.ParsePredicate<Person>("it => it.Age == 50");
|
||||
|
||||
var func = expression.Compile();
|
||||
|
||||
Assert.True(func(new Person { Age = 50 }));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Should_SupportNullablePropertiesWithArray()
|
||||
{
|
||||
var expression = ExpressionParser.ParsePredicate<Person>("it => (new []{}).Contains(it.Famous)");
|
||||
|
||||
var func = expression.Compile();
|
||||
|
||||
Assert.False(func(new Person { Famous = null }));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Should_SupportDateTimeWithArray()
|
||||
{
|
||||
var expression = ExpressionParser.ParsePredicate<Person>("it => (new []{DateTime.Parse(\"5/5/2000 12:00:00 AM\")}).Contains(it.BirthDate)");
|
||||
|
||||
var func = expression.Compile();
|
||||
|
||||
Assert.True(func(new Person { BirthDate = DateTime.Parse("5/5/2000 12:00:00 AM") }));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Should_SupportNumericConversion()
|
||||
{
|
||||
var expression = ExpressionParser.ParsePredicate<ItemWithGenericProperty<double>>("it => it.Value == 50");
|
||||
|
||||
var func = expression.Compile();
|
||||
|
||||
Assert.True(func(new ItemWithGenericProperty<double> { Value = 50.0 }));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Should_SupportNullCoalescence()
|
||||
{
|
||||
var expression = ExpressionParser.ParsePredicate<ItemWithGenericProperty<double?>>("it => (it.Value ?? 0) == 0");
|
||||
|
||||
var func = expression.Compile();
|
||||
|
||||
Assert.True(func(new ItemWithGenericProperty<double?> { Value = null }));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Should_SupportNullConditionAndCoalescence()
|
||||
{
|
||||
var expression = ExpressionParser.ParsePredicate<Person>("it => (((it == null) ? null : it.Name) ?? \"\").Contains(\"Da\")");
|
||||
|
||||
var func = expression.Compile();
|
||||
|
||||
Assert.True(func(new Person { Name = "Dali" }));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Should_CreateProjection()
|
||||
{
|
||||
var expression = ExpressionParser.ParseLambda<OrderDetail>("it => new { ProductName = it.Product.ProductName}");
|
||||
|
||||
var func = expression.Compile();
|
||||
|
||||
var result = func.DynamicInvoke(new OrderDetail { Product = new Product { ProductName = "Queso" } });
|
||||
|
||||
var property = result.GetType().GetProperty("ProductName");
|
||||
|
||||
Assert.Equal(typeof(string), property.PropertyType);
|
||||
|
||||
Assert.Equal("Queso", property.GetValue(result));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Should_CreateProjectionFromNestedAccess()
|
||||
{
|
||||
var expression = ExpressionParser.ParseLambda<OrderDetail>("it => new { it.Product.Category.CategoryName }");
|
||||
|
||||
var func = expression.Compile();
|
||||
|
||||
var orderDetail = new OrderDetail { Product = new Product { Category = new Category { CategoryName = "Beverages" } } };
|
||||
|
||||
var x = new { orderDetail?.Product?.Category?.CategoryName };
|
||||
|
||||
var result = func.DynamicInvoke(orderDetail);
|
||||
|
||||
var property = result.GetType().GetProperty("CategoryName");
|
||||
|
||||
Assert.Equal(typeof(string), property.PropertyType);
|
||||
|
||||
Assert.Equal("Beverages", property.GetValue(result));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Should_CreateProjectionFromNestedConditionalAccess()
|
||||
{
|
||||
var expression = ExpressionParser.ParseLambda<OrderDetail>("it => new { it.Product?.Category?.CategoryName }");
|
||||
|
||||
var func = expression.Compile();
|
||||
|
||||
var orderDetail = new OrderDetail { Product = new Product { Category = new Category { CategoryName = "Beverages" } } };
|
||||
|
||||
var x = new { orderDetail?.Product?.Category?.CategoryName };
|
||||
|
||||
var result = func.DynamicInvoke(orderDetail);
|
||||
|
||||
var property = result.GetType().GetProperty("CategoryName");
|
||||
|
||||
Assert.Equal(typeof(string), property.PropertyType);
|
||||
|
||||
Assert.Equal("Beverages", property.GetValue(result));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Should_CreateProjectionFromConditionalAccess()
|
||||
{
|
||||
var expression = ExpressionParser.ParseLambda<OrderDetail>("it => new { ProductName = it.Product?.ProductName}");
|
||||
var func = expression.Compile();
|
||||
var result = func.DynamicInvoke(new OrderDetail { Product = null });
|
||||
|
||||
var property = result.GetType().GetProperty("ProductName");
|
||||
|
||||
Assert.Equal(typeof(string), property.PropertyType);
|
||||
Assert.Null(property.GetValue(result));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Should_CreateProjectionFromNestedConditionalAccessAndAssignment()
|
||||
{
|
||||
var expression = ExpressionParser.ParseLambda<OrderDetail>("it => new { CategoryName = it.Product?.Category?.CategoryName}");
|
||||
var func = expression.Compile();
|
||||
var result = func.DynamicInvoke(new OrderDetail { Product = null });
|
||||
|
||||
var property = result.GetType().GetProperty("CategoryName");
|
||||
|
||||
Assert.Equal(typeof(string), property.PropertyType);
|
||||
Assert.Null(property.GetValue(result));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Should_SelectByString()
|
||||
{
|
||||
var list = new List<OrderDetail> { new OrderDetail { Product = new Product { ProductName = "Chai" } } }.AsQueryable();
|
||||
|
||||
var result = DynamicExtensions.Select(list, "Product.ProductName as ProductName");
|
||||
|
||||
Assert.Equal("Chai", result.ElementType.GetProperty("ProductName").GetValue(result.FirstOrDefault()));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Should_SelectByWithUntypedIQueryableString()
|
||||
{
|
||||
IQueryable list = new List<OrderDetail> { new OrderDetail { Product = new Product { ProductName = "Chai" } } }.AsQueryable();
|
||||
|
||||
var result = DynamicExtensions.Select(list, "Product.ProductName as ProductName");
|
||||
|
||||
Assert.Equal("Chai", result.ElementType.GetProperty("ProductName").GetValue(result.FirstOrDefault()));
|
||||
}
|
||||
|
||||
|
||||
[Fact]
|
||||
public void Should_SupportDictionaryIndexAccess()
|
||||
{
|
||||
var expression = ExpressionParser.ParsePredicate<Dictionary<string, object>>("it => (int)it[\"foo\"] == 1");
|
||||
var func = expression.Compile();
|
||||
Assert.True(func(new Dictionary<string, object> { ["foo"] = 1 }));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Should_SupportDictionaryIndexAccessWithNullableCast()
|
||||
{
|
||||
var expression = ExpressionParser.ParsePredicate<Dictionary<string, object>>("it => (Int32?)it[\"foo\"] == null");
|
||||
var func = expression.Compile();
|
||||
Assert.True(func(new Dictionary<string, object> { ["foo"] = null }));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Should_SupportArrayIndexAccess()
|
||||
{
|
||||
var expression = ExpressionParser.ParsePredicate<ItemWithGenericProperty<int[]>>("it => it.Value[0] == 1");
|
||||
var func = expression.Compile();
|
||||
|
||||
Assert.True(func(new ItemWithGenericProperty<int[]> { Value = [1] }));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -46,7 +46,7 @@ namespace Radzen.Blazor.Tests
|
||||
|
||||
component.SetParametersAndRender(parameters => parameters.Add(p => p.Icon, value));
|
||||
|
||||
Assert.Contains(@$"<i class=""rzi"">{value}</i>", component.Markup);
|
||||
Assert.Contains(@$"<i class=""notranslate rzi"">{value}</i>", component.Markup);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
@@ -104,11 +104,11 @@ namespace Radzen.Blazor.Tests
|
||||
|
||||
component.SetParametersAndRender(parameters => parameters.Add<bool>(p => p.AllowCollapse, true));
|
||||
|
||||
Assert.Contains(@"<span class=""rz-fieldset-toggler rzi rzi-w rzi-minus""></span>", component.Markup);
|
||||
Assert.Contains(@"<span class=""notranslate rz-fieldset-toggler rzi rzi-w rzi-minus""></span>", component.Markup);
|
||||
|
||||
component.SetParametersAndRender(parameters => parameters.Add<bool>(p => p.Collapsed, true));
|
||||
|
||||
Assert.Contains(@"<span class=""rz-fieldset-toggler rzi rzi-w rzi-plus""></span>", component.Markup);
|
||||
Assert.Contains(@"<span class=""notranslate rz-fieldset-toggler rzi rzi-w rzi-plus""></span>", component.Markup);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
||||
@@ -17,7 +17,7 @@ namespace Radzen.Blazor.Tests
|
||||
component.SetParametersAndRender(parameters => parameters.Add(p => p.Icon, icon));
|
||||
|
||||
Assert.Contains(@$">{icon}</i>", component.Markup);
|
||||
Assert.Contains(@$"class=""rzi""", component.Markup);
|
||||
Assert.Contains(@$"class=""notranslate rzi""", component.Markup);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
||||
@@ -47,7 +47,7 @@ namespace Radzen.Blazor.Tests
|
||||
|
||||
component.SetParametersAndRender(parameters => parameters.Add(p => p.Icon, icon));
|
||||
|
||||
Assert.Contains(@$"<i class=""rzi"">{icon}</i>", component.Markup);
|
||||
Assert.Contains(@$"<i class=""notranslate rzi"">{icon}</i>", component.Markup);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
@@ -78,6 +78,20 @@ namespace Radzen.Blazor.Tests
|
||||
Assert.Contains(@$"target=""{target}""", component.Markup);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Link_Renders_DisabledParameter()
|
||||
{
|
||||
using var ctx = new TestContext();
|
||||
|
||||
var component = ctx.RenderComponent<RadzenLink>();
|
||||
|
||||
component.SetParametersAndRender(parameters => parameters.Add(p => p.Disabled, true));
|
||||
|
||||
Assert.Contains("class=\"rz-link rz-link-disabled active\"", component.Markup);
|
||||
|
||||
Assert.DoesNotContain("href=", component.Markup);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Icon_Renders_UnmatchedParameter()
|
||||
{
|
||||
|
||||
@@ -28,6 +28,10 @@ namespace Radzen.Blazor.Tests
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public bool Disabled { get; set; }
|
||||
public bool Visible { get; set; }
|
||||
public IFormFieldContext FormFieldContext => null;
|
||||
|
||||
public object Value { get; set; }
|
||||
}
|
||||
|
||||
@@ -169,4 +173,4 @@ namespace Radzen.Blazor.Tests
|
||||
Assert.False(component.Instance.Validate(DateTime.Now));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -463,10 +463,11 @@ namespace Radzen.Blazor.Tests
|
||||
ctx.JSInterop.SetupModule("_content/Radzen.Blazor/Radzen.Blazor.js");
|
||||
|
||||
var value = new Dollars(11m);
|
||||
Dollars? ConvertFunc(string s) => decimal.TryParse(s, out var val) ? new Dollars(val) : null;
|
||||
Dollars? ConvertFunc(string s) => decimal.TryParse(s, System.Globalization.CultureInfo.InvariantCulture, out var val) ? new Dollars(val) : null;
|
||||
var component = ctx.RenderComponent<RadzenNumeric<Dollars?>>(
|
||||
ComponentParameter.CreateParameter(nameof(RadzenNumeric<Dollars?>.ConvertValue), (Func<string, Dollars?>)ConvertFunc),
|
||||
ComponentParameter.CreateParameter(nameof(RadzenNumeric<Dollars?>.Value), value)
|
||||
ComponentParameter.CreateParameter(nameof(RadzenNumeric<Dollars?>.Value), value),
|
||||
ComponentParameter.CreateParameter(nameof(RadzenNumeric<Dollars>.Culture), System.Globalization.CultureInfo.InvariantCulture)
|
||||
);
|
||||
|
||||
component.Render();
|
||||
@@ -494,7 +495,101 @@ namespace Radzen.Blazor.Tests
|
||||
|
||||
component.Render();
|
||||
|
||||
Assert.Contains($" value=\"{valueToTest.ToString(format)}\"", component.Markup);
|
||||
Assert.Contains($" value=\"{valueToTest.ToString(format, System.Globalization.CultureInfo.CurrentCulture)}\"", component.Markup);
|
||||
}
|
||||
[Fact]
|
||||
public void Numeric_Supports_TypeConverterWithCulture()
|
||||
{
|
||||
using var ctx = new TestContext();
|
||||
|
||||
var valueToTest = new Dollars(100.234m);
|
||||
string format = "0.00";
|
||||
|
||||
var component = ctx.RenderComponent<RadzenNumeric<Dollars>>(
|
||||
ComponentParameter.CreateParameter(nameof(RadzenNumeric<Dollars>.Format), format),
|
||||
ComponentParameter.CreateParameter(nameof(RadzenNumeric<Dollars>.Value), valueToTest),
|
||||
ComponentParameter.CreateParameter(nameof(RadzenNumeric<Dollars>.Culture), System.Globalization.CultureInfo.InvariantCulture)
|
||||
);
|
||||
|
||||
component.Render();
|
||||
|
||||
Assert.Contains($" value=\"{valueToTest.ToString(format, System.Globalization.CultureInfo.InvariantCulture)}\"", component.Markup);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Numeric_Supports_EmptyString()
|
||||
{
|
||||
using var ctx = new TestContext();
|
||||
|
||||
var valueToTest = "";
|
||||
string format = "0.00";
|
||||
|
||||
var component = ctx.RenderComponent<RadzenNumeric<string>>(
|
||||
ComponentParameter.CreateParameter(nameof(RadzenNumeric<string>.Format), format),
|
||||
ComponentParameter.CreateParameter(nameof(RadzenNumeric<string>.Value), valueToTest),
|
||||
ComponentParameter.CreateParameter(nameof(RadzenNumeric<Dollars>.Culture), System.Globalization.CultureInfo.InvariantCulture)
|
||||
);
|
||||
|
||||
component.Render();
|
||||
|
||||
Assert.Contains($" value=\"0.00\"", component.Markup);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Numeric_Supports_ValueString()
|
||||
{
|
||||
using var ctx = new TestContext();
|
||||
|
||||
var valueToTest = "12.50";
|
||||
string format = "0.00";
|
||||
|
||||
var component = ctx.RenderComponent<RadzenNumeric<string>>(
|
||||
ComponentParameter.CreateParameter(nameof(RadzenNumeric<string>.Format), format),
|
||||
ComponentParameter.CreateParameter(nameof(RadzenNumeric<string>.Value), valueToTest),
|
||||
ComponentParameter.CreateParameter(nameof(RadzenNumeric<Dollars>.Culture), System.Globalization.CultureInfo.InvariantCulture)
|
||||
);
|
||||
|
||||
component.Render();
|
||||
|
||||
Assert.Contains($" value=\"{valueToTest}\"", component.Markup);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Numeric_Supports_ValueStringEsCLCulture()
|
||||
{
|
||||
using var ctx = new TestContext();
|
||||
|
||||
var valueToTest = "12,50";
|
||||
string format = "0.00";
|
||||
|
||||
var component = ctx.RenderComponent<RadzenNumeric<string>>(
|
||||
ComponentParameter.CreateParameter(nameof(RadzenNumeric<string>.Format), format),
|
||||
ComponentParameter.CreateParameter(nameof(RadzenNumeric<string>.Value), valueToTest),
|
||||
ComponentParameter.CreateParameter(nameof(RadzenNumeric<Dollars>.Culture), System.Globalization.CultureInfo.GetCultureInfo("es-CL"))
|
||||
);
|
||||
|
||||
component.Render();
|
||||
|
||||
Assert.Contains($" value=\"{valueToTest}\"", component.Markup);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Numeric_Supports_ValueStringEnUSCulture()
|
||||
{
|
||||
using var ctx = new TestContext();
|
||||
|
||||
var valueToTest = "12.50";
|
||||
string format = "0.00";
|
||||
|
||||
var component = ctx.RenderComponent<RadzenNumeric<string>>(
|
||||
ComponentParameter.CreateParameter(nameof(RadzenNumeric<string>.Format), format),
|
||||
ComponentParameter.CreateParameter(nameof(RadzenNumeric<string>.Value), valueToTest),
|
||||
ComponentParameter.CreateParameter(nameof(RadzenNumeric<Dollars>.Culture), System.Globalization.CultureInfo.GetCultureInfo("en-US"))
|
||||
);
|
||||
|
||||
component.Render();
|
||||
|
||||
Assert.Contains($" value=\"{valueToTest}\"", component.Markup);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
@@ -517,10 +612,10 @@ namespace Radzen.Blazor.Tests
|
||||
});
|
||||
});
|
||||
|
||||
component.Find("input").Change("13.53");
|
||||
component.Find("input").Change(13.53);
|
||||
|
||||
var maxDollars = new Dollars(2);
|
||||
Assert.Contains($" value=\"{maxDollars.ToString()}\"", component.Markup);
|
||||
var maxDollars = new Dollars(maxValue);
|
||||
Assert.Contains($" value=\"{maxDollars}\"", component.Markup);
|
||||
Assert.Equal(component.Instance.Value, maxDollars);
|
||||
}
|
||||
|
||||
|
||||
@@ -47,7 +47,7 @@ namespace Radzen.Blazor.Tests
|
||||
|
||||
component.SetParametersAndRender(parameters => parameters.Add(p => p.Icon, value));
|
||||
|
||||
Assert.Contains(@$"<i class=""rzi"">{value}</i>", component.Markup);
|
||||
Assert.Contains(@$"<i class=""notranslate rzi"">{value}</i>", component.Markup);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
@@ -119,11 +119,11 @@ namespace Radzen.Blazor.Tests
|
||||
|
||||
component.SetParametersAndRender(parameters => parameters.Add<bool>(p => p.AllowCollapse, true));
|
||||
|
||||
Assert.Contains(@"<span class=""rzi rzi-minus""></span>", component.Markup);
|
||||
Assert.Contains(@"<span class=""notranslate rzi rzi-minus""></span>", component.Markup);
|
||||
|
||||
component.SetParametersAndRender(parameters => parameters.Add<bool>(p => p.Collapsed, true));
|
||||
|
||||
Assert.Contains(@"<span class=""rzi rzi-plus""></span>", component.Markup);
|
||||
Assert.Contains(@"<span class=""notranslate rzi rzi-plus""></span>", component.Markup);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
||||
@@ -1,8 +1,5 @@
|
||||
using AngleSharp.Css;
|
||||
using System;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Linq.Dynamic.Core;
|
||||
using Xunit;
|
||||
|
||||
namespace Radzen.Blazor.Tests
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net8</TargetFramework>
|
||||
<TargetFramework>net9</TargetFramework>
|
||||
|
||||
<IsPackable>false</IsPackable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.7.1" />
|
||||
<PackageReference Include="bunit.web" Version="1.2.49" />
|
||||
<PackageReference Include="bunit.web" Version="1.36.0" />
|
||||
<PackageReference Include="xunit" Version="2.4.1" />
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.3">
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
|
||||
@@ -45,7 +45,7 @@ namespace Radzen.Blazor.Tests
|
||||
|
||||
component.SetParametersAndRender(parameters => parameters.Add(p => p.Icon, icon));
|
||||
|
||||
Assert.Contains(@$"<i class=""rz-button-icon-left rzi"">{icon}</i>", component.Markup);
|
||||
Assert.Contains(@$"<i class=""notranslate rz-button-icon-left rzi"">{icon}</i>", component.Markup);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
@@ -63,7 +63,7 @@ namespace Radzen.Blazor.Tests
|
||||
parameters.Add(p => p.Icon, icon);
|
||||
});
|
||||
|
||||
Assert.Contains(@$"<i class=""rz-button-icon-left rzi"">{icon}</i>", component.Markup);
|
||||
Assert.Contains(@$"<i class=""notranslate rz-button-icon-left rzi"">{icon}</i>", component.Markup);
|
||||
Assert.Contains(@$"<span class=""rz-button-text"">{text}</span>", component.Markup);
|
||||
}
|
||||
|
||||
@@ -78,7 +78,7 @@ namespace Radzen.Blazor.Tests
|
||||
|
||||
component.SetParametersAndRender(parameters => parameters.Add(p => p.Image, image));
|
||||
|
||||
Assert.Contains(@$"<img class=""rz-button-icon-left rzi"" src=""{image}"" alt=""image"" />", component.Markup);
|
||||
Assert.Contains(@$"<img class=""notranslate rz-button-icon-left rzi"" src=""{image}"" alt=""image"" />", component.Markup);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
@@ -97,7 +97,7 @@ namespace Radzen.Blazor.Tests
|
||||
parameters.Add(p => p.ImageAlternateText, text);
|
||||
});
|
||||
|
||||
Assert.Contains(@$"<img class=""rz-button-icon-left rzi"" src=""{image}"" alt=""{text}"" />", component.Markup);
|
||||
Assert.Contains(@$"<img class=""notranslate rz-button-icon-left rzi"" src=""{image}"" alt=""{text}"" />", component.Markup);
|
||||
Assert.Contains(@$"<span class=""rz-button-text"">{text}</span>", component.Markup);
|
||||
}
|
||||
|
||||
|
||||
@@ -134,5 +134,18 @@ namespace Radzen.Blazor.Tests
|
||||
Assert.True(raised);
|
||||
Assert.True(object.Equals(value, !(bool)newValue));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Switch_Renders_ReadOnlyParameter()
|
||||
{
|
||||
using var ctx = new TestContext();
|
||||
|
||||
var component = ctx.RenderComponent<RadzenSwitch>();
|
||||
|
||||
component.SetParametersAndRender(parameters => parameters.Add<bool>(p => p.ReadOnly, true));
|
||||
|
||||
Assert.Contains(@$"rz-readonly", component.Markup);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -101,6 +101,17 @@ namespace Radzen.Blazor
|
||||
/// <value><c>true</c> if visible; otherwise, <c>false</c>.</value>
|
||||
[Parameter]
|
||||
public bool Visible { get; set; } = true;
|
||||
/// <summary>
|
||||
/// Specifies the label rotation angle in degrees. Set to <c>null</c> by default which means no rotation is applied. Has higher precedence than <see cref="LabelAutoRotation"/>.
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
public double? LabelRotation { get; set; } = null;
|
||||
|
||||
/// <summary>
|
||||
/// Specifies the automatic label rotation angle in degrees. If set RadzenChart will automatically rotate the labels to fit the available space by the specified value. Has lower precedence than <see cref="LabelRotation"/>.
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
public double? LabelAutoRotation { get; set; } = null;
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override bool ShouldRefreshChart(ParameterView parameters)
|
||||
@@ -108,6 +119,8 @@ namespace Radzen.Blazor
|
||||
return DidParameterChange(parameters, nameof(Min), Min) ||
|
||||
DidParameterChange(parameters, nameof(Max), Max) ||
|
||||
DidParameterChange(parameters, nameof(Visible), Visible) ||
|
||||
DidParameterChange(parameters, nameof(LabelRotation), LabelRotation) ||
|
||||
DidParameterChange(parameters, nameof(LabelAutoRotation), LabelAutoRotation) ||
|
||||
DidParameterChange(parameters, nameof(Step), Step);
|
||||
}
|
||||
|
||||
|
||||
@@ -2,7 +2,6 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using Microsoft.AspNetCore.Components;
|
||||
using System.Linq;
|
||||
using System.Linq.Dynamic.Core;
|
||||
using Radzen.Blazor.Rendering;
|
||||
using System.Threading.Tasks;
|
||||
using System.Net.Mime;
|
||||
@@ -410,7 +409,7 @@ namespace Radzen.Blazor
|
||||
|
||||
if (IsDate(CategoryProperty) || IsNumeric(CategoryProperty))
|
||||
{
|
||||
Items = Items.AsQueryable().OrderBy(DynamicLinqCustomTypeProvider.ParsingConfig, CategoryProperty).ToList();
|
||||
Items = Items.AsQueryable().OrderBy(CategoryProperty).ToList();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -478,38 +477,30 @@ namespace Radzen.Blazor
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public virtual RenderFragment RenderTooltip(object data, double marginLeft, double marginTop, double chartHeight)
|
||||
public virtual RenderFragment RenderTooltip(object data)
|
||||
{
|
||||
var item = (TItem)data;
|
||||
|
||||
var x = TooltipX(item);
|
||||
var y = TooltipY(item);
|
||||
|
||||
|
||||
return builder =>
|
||||
{
|
||||
|
||||
if (Chart.Tooltip.Shared)
|
||||
{
|
||||
var category = PropertyAccess.GetValue(item, CategoryProperty);
|
||||
builder.OpenComponent<ChartSharedTooltip>(0);
|
||||
builder.AddAttribute(1, nameof(ChartSharedTooltip.X), x + marginLeft);
|
||||
builder.AddAttribute(2, nameof(ChartSharedTooltip.Y), y + marginTop);
|
||||
builder.AddAttribute(3, nameof(ChartSharedTooltip.Class), TooltipClass(item));
|
||||
builder.AddAttribute(4, nameof(ChartSharedTooltip.Title), TooltipTitle(item));
|
||||
builder.AddAttribute(4, nameof(ChartSharedTooltip.ChildContent), RenderSharedTooltipItems(category));
|
||||
builder.AddAttribute(1, nameof(ChartSharedTooltip.Class), TooltipClass(item));
|
||||
builder.AddAttribute(2, nameof(ChartSharedTooltip.Title), TooltipTitle(item));
|
||||
builder.AddAttribute(3, nameof(ChartSharedTooltip.ChildContent), RenderSharedTooltipItems(category));
|
||||
builder.CloseComponent();
|
||||
}
|
||||
else
|
||||
{
|
||||
builder.OpenComponent<ChartTooltip>(0);
|
||||
builder.AddAttribute(1, nameof(ChartTooltip.X), x + marginLeft);
|
||||
builder.AddAttribute(2, nameof(ChartTooltip.Y), y + marginTop);
|
||||
builder.AddAttribute(3, nameof(ChartTooltip.ChildContent), TooltipTemplate?.Invoke(item));
|
||||
builder.AddAttribute(4, nameof(ChartTooltip.Title), TooltipTitle(item));
|
||||
builder.AddAttribute(5, nameof(ChartTooltip.Label), TooltipLabel(item));
|
||||
builder.AddAttribute(6, nameof(ChartTooltip.Value), TooltipValue(item));
|
||||
builder.AddAttribute(7, nameof(ChartTooltip.Class), TooltipClass(item));
|
||||
builder.AddAttribute(8, nameof(ChartTooltip.Style), TooltipStyle(item));
|
||||
builder.AddAttribute(1, nameof(ChartTooltip.ChildContent), TooltipTemplate?.Invoke(item));
|
||||
builder.AddAttribute(2, nameof(ChartTooltip.Title), TooltipTitle(item));
|
||||
builder.AddAttribute(3, nameof(ChartTooltip.Label), TooltipLabel(item));
|
||||
builder.AddAttribute(4, nameof(ChartTooltip.Value), TooltipValue(item));
|
||||
builder.AddAttribute(5, nameof(ChartTooltip.Class), TooltipClass(item));
|
||||
builder.AddAttribute(6, nameof(ChartTooltip.Style), TooltipStyle(item));
|
||||
builder.CloseComponent();
|
||||
}
|
||||
};
|
||||
@@ -546,6 +537,16 @@ namespace Radzen.Blazor
|
||||
};
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public Point GetTooltipPosition(object data)
|
||||
{
|
||||
var item = (TItem)data;
|
||||
var x = TooltipX(item);
|
||||
var y = TooltipY(item);
|
||||
|
||||
return new Point { X = x, Y = y };
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the tooltip inline style.
|
||||
/// </summary>
|
||||
|
||||
@@ -7,11 +7,11 @@ using Radzen.Blazor.Rendering;
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Linq.Dynamic.Core;
|
||||
using System.Linq.Dynamic.Core.Parser;
|
||||
using System.Linq.Expressions;
|
||||
using System.Reflection;
|
||||
using System.Reflection.Metadata;
|
||||
using System.Text;
|
||||
using System.Text.Encodings.Web;
|
||||
using System.Text.Json;
|
||||
@@ -530,6 +530,12 @@ namespace Radzen
|
||||
/// Gets the dropped item.
|
||||
/// </summary>
|
||||
public TItem ToItem { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// The data that underlies a drag-and-drop operation, known as the drag data store.
|
||||
/// See <see cref="DataTransfer"/>.
|
||||
/// </summary>
|
||||
public DataTransfer DataTransfer { get; set; } = default!;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -551,7 +557,6 @@ namespace Radzen
|
||||
/// Gets or sets a value indicating whether this item is visible.
|
||||
/// </summary>
|
||||
/// <value><c>true</c> if visible; otherwise, <c>false</c>.</value>
|
||||
[Parameter]
|
||||
public bool Visible { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
@@ -574,14 +579,12 @@ namespace Radzen
|
||||
/// Gets or sets a value indicating whether this item is visible.
|
||||
/// </summary>
|
||||
/// <value><c>true</c> if visible; otherwise, <c>false</c>.</value>
|
||||
[Parameter]
|
||||
public bool Visible { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether this item is visible.
|
||||
/// </summary>
|
||||
/// <value><c>true</c> if visible; otherwise, <c>false</c>.</value>
|
||||
[Parameter]
|
||||
public bool Disabled { get; set; }
|
||||
|
||||
/// <summary>
|
||||
@@ -612,6 +615,34 @@ namespace Radzen
|
||||
public RadzenListBox<TValue> ListBox { get; internal set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Supplies information about RadzenPickList ItemRender event.
|
||||
/// </summary>
|
||||
public class PickListItemRenderEventArgs<TItem>
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the data item.
|
||||
/// </summary>
|
||||
public TItem Item { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether this item is visible.
|
||||
/// </summary>
|
||||
/// <value><c>true</c> if visible; otherwise, <c>false</c>.</value>
|
||||
public bool Visible { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether this item is visible.
|
||||
/// </summary>
|
||||
/// <value><c>true</c> if visible; otherwise, <c>false</c>.</value>
|
||||
public bool Disabled { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the row HTML attributes.
|
||||
/// </summary>
|
||||
public IDictionary<string, object> Attributes { get; private set; } = new Dictionary<string, object>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Supplies information about a <see cref="RadzenDatePicker{TValue}.DateRender" /> event that is being raised.
|
||||
/// </summary>
|
||||
@@ -702,9 +733,14 @@ namespace Radzen
|
||||
public AppointmentData Appointment { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the time span.
|
||||
/// Gets or sets the time span which represents the difference between slot start and appointment start.
|
||||
/// </summary>
|
||||
public TimeSpan TimeSpan { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the date of the slot where the appointment is moved.
|
||||
/// </summary>
|
||||
public DateTime SlotDate { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -758,6 +794,11 @@ namespace Radzen
|
||||
/// </summary>
|
||||
/// <value><c>true</c> if expandable; otherwise, <c>false</c>.</value>
|
||||
public bool Expandable { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating row index.
|
||||
/// </summary>
|
||||
public int Index { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -2251,6 +2292,18 @@ namespace Radzen
|
||||
/// </summary>
|
||||
/// <value>The property.</value>
|
||||
public string Property { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the property type.
|
||||
/// </summary>
|
||||
/// <value>The property type.</value>
|
||||
public Type Type { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the name of the filtered property.
|
||||
/// </summary>
|
||||
/// <value>The property.</value>
|
||||
public string FilterProperty { get; set; }
|
||||
/// <summary>
|
||||
/// Gets or sets the value to filter by.
|
||||
/// </summary>
|
||||
@@ -2289,6 +2342,18 @@ namespace Radzen
|
||||
/// <value>The property.</value>
|
||||
public string Property { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the property type.
|
||||
/// </summary>
|
||||
/// <value>The property type.</value>
|
||||
public Type Type { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the name of the filtered property.
|
||||
/// </summary>
|
||||
/// <value>The property.</value>
|
||||
public string FilterProperty { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the value to filter by.
|
||||
/// </summary>
|
||||
@@ -2392,6 +2457,43 @@ namespace Radzen
|
||||
public int Level { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The result of a call to a <see cref="QueryableExtension"/>.GroupByMany() overload.
|
||||
/// </summary>
|
||||
public class GroupResult
|
||||
{
|
||||
/// <summary>
|
||||
/// The key value of the group.
|
||||
/// </summary>
|
||||
public dynamic Key { get; internal set; } = null!;
|
||||
|
||||
/// <summary>
|
||||
/// The number of resulting elements in the group.
|
||||
/// </summary>
|
||||
public int Count { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// The resulting elements in the group.
|
||||
/// </summary>
|
||||
public IEnumerable Items { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// The resulting subgroups in the group.
|
||||
/// </summary>
|
||||
public IEnumerable<GroupResult> Subgroups { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// Returns a <see cref="System.String" /> showing the key of the group and the number of items in the group.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// A <see cref="System.String" /> that represents this instance.
|
||||
/// </returns>
|
||||
public override string ToString()
|
||||
{
|
||||
return string.Format(CultureInfo.CurrentCulture, "{0} ({1})", ((object)Key).ToString(), Count);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Supplies information about a <see cref="PagedDataBoundComponent{TItem}.LoadData" /> event that is being raised.
|
||||
/// </summary>
|
||||
@@ -2866,9 +2968,14 @@ namespace Radzen
|
||||
/// </summary>
|
||||
/// <param name="value">The value.</param>
|
||||
/// <param name="type">The type.</param>
|
||||
/// <param name="culture">The culture.</param>
|
||||
/// <returns>System.Object</returns>
|
||||
public static object ChangeType(object value, Type type)
|
||||
public static object ChangeType(object value, Type type, CultureInfo culture = null)
|
||||
{
|
||||
if (culture == null)
|
||||
{
|
||||
culture = CultureInfo.CurrentCulture;
|
||||
}
|
||||
if (value == null && Nullable.GetUnderlyingType(type) != null)
|
||||
{
|
||||
return value;
|
||||
@@ -2896,7 +3003,7 @@ namespace Radzen
|
||||
|
||||
}
|
||||
|
||||
return value is IConvertible ? Convert.ChangeType(value, Nullable.GetUnderlyingType(type) ?? type) : value;
|
||||
return value is IConvertible ? Convert.ChangeType(value, Nullable.GetUnderlyingType(type) ?? type, culture) : value;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2917,7 +3024,9 @@ namespace Radzen
|
||||
{
|
||||
if (propertyName.Contains("["))
|
||||
{
|
||||
return DynamicExpressionParser.ParseLambda<TItem, TValue>(null, false, propertyName).Compile();
|
||||
var arg = Expression.Parameter(typeof(TItem));
|
||||
|
||||
return Expression.Lambda<Func<TItem, TValue>>(QueryableExtension.GetNestedPropertyExpression(arg, propertyName, type), arg).Compile();
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -3058,23 +3167,7 @@ namespace Radzen
|
||||
/// <param name="property">The property.</param>
|
||||
public static string GetProperty(string property)
|
||||
{
|
||||
Type type = null;
|
||||
try
|
||||
{
|
||||
type = Type.GetType($"System.{property}");
|
||||
}
|
||||
catch
|
||||
{
|
||||
// ignore the exception and assume the property start without a type and do not need the '@' prefix
|
||||
}
|
||||
var propertyName = $"{(type != null ? "@" : "")}{property}";
|
||||
|
||||
if (propertyName.IndexOf(".") != -1)
|
||||
{
|
||||
return $"np({propertyName})";
|
||||
}
|
||||
|
||||
return propertyName;
|
||||
return property;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -3303,7 +3396,7 @@ namespace Radzen
|
||||
var typeName = isEnum ? "Enum" : (Nullable.GetUnderlyingType(type) ?? type).Name;
|
||||
var typeFunc = $@"{typeName}{(!isEnum && Nullable.GetUnderlyingType(type) != null ? "?" : "")}";
|
||||
|
||||
return $@"{typeFunc}(it[""{name}""])";
|
||||
return $@"({typeFunc})it[""{name}""]";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3369,6 +3462,21 @@ namespace Radzen
|
||||
/// Sets the focus.
|
||||
/// </summary>
|
||||
ValueTask FocusAsync();
|
||||
|
||||
/// <summary>
|
||||
/// Sets the Disabled state of the component
|
||||
/// </summary>
|
||||
bool Disabled { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Sets the Visible state of the component
|
||||
/// </summary>
|
||||
bool Visible { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Sets the FormFieldContext of the component
|
||||
/// </summary>
|
||||
IFormFieldContext FormFieldContext { get; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -3753,4 +3861,4 @@ namespace Radzen
|
||||
/// </summary>
|
||||
Right
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -65,11 +65,8 @@ namespace Radzen
|
||||
/// <param name="sender">The source of the event.</param>
|
||||
/// <param name="e">The <see cref="Microsoft.AspNetCore.Components.Routing.LocationChangedEventArgs"/> instance containing the event data.</param>
|
||||
private void UriHelper_OnLocationChanged(object sender, Microsoft.AspNetCore.Components.Routing.LocationChangedEventArgs e)
|
||||
{
|
||||
if (this.OnNavigate != null)
|
||||
{
|
||||
this.OnNavigate();
|
||||
}
|
||||
{
|
||||
this.OnNavigate?.Invoke();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -3,12 +3,9 @@ using Microsoft.AspNetCore.Components.Forms;
|
||||
using Microsoft.AspNetCore.Components.Web;
|
||||
using Radzen.Blazor;
|
||||
using Radzen.Blazor.Rendering;
|
||||
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Linq.Dynamic.Core;
|
||||
using System.Linq.Expressions;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
@@ -262,23 +259,7 @@ namespace Radzen
|
||||
{
|
||||
if (!string.IsNullOrEmpty(searchText))
|
||||
{
|
||||
var ignoreCase = FilterCaseSensitivity == FilterCaseSensitivity.CaseInsensitive;
|
||||
|
||||
var query = new List<string>();
|
||||
|
||||
if (!string.IsNullOrEmpty(TextProperty))
|
||||
{
|
||||
query.Add(TextProperty);
|
||||
}
|
||||
|
||||
if (ignoreCase)
|
||||
{
|
||||
query.Add("ToLower()");
|
||||
}
|
||||
|
||||
query.Add($"{Enum.GetName(typeof(StringFilterOperator), FilterOperator)}(@0)");
|
||||
|
||||
_view = Query.Where(DynamicLinqCustomTypeProvider.ParsingConfig, string.Join(".", query), ignoreCase ? searchText.ToLower() : searchText);
|
||||
_view = Query.Where(TextProperty, searchText, FilterOperator, FilterCaseSensitivity);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -4,6 +4,7 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Radzen
|
||||
@@ -118,13 +119,32 @@ namespace Radzen
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type of the Blazor component which will be displayed in a dialog.</typeparam>
|
||||
/// <param name="title">The text displayed in the title bar of the dialog.</param>
|
||||
/// <param name="parameters">The dialog parameters. Passed as property values of <typeparamref name="T" />.</param>
|
||||
/// <param name="parameters">The dialog parameters.</param>
|
||||
/// <param name="options">The dialog options.</param>
|
||||
public virtual void Open<T>(string title, Dictionary<string, object> parameters = null, DialogOptions options = null) where T : ComponentBase
|
||||
{
|
||||
OpenDialog<T>(title, parameters, options);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Opens a dialog with the specified arguments.
|
||||
/// </summary>
|
||||
/// <param name="title">The text displayed in the title bar of the dialog.</param>
|
||||
/// <param name="componentType">The type of the component to be displayed in the dialog. Must inherit from <see cref="ComponentBase"/>.</param>
|
||||
/// <param name="parameters">The dialog parameters.</param>
|
||||
/// <param name="options">The dialog options.</param>
|
||||
public virtual void Open(string title, Type componentType, Dictionary<string, object> parameters = null, DialogOptions options = null)
|
||||
{
|
||||
if (!typeof(ComponentBase).IsAssignableFrom(componentType))
|
||||
{
|
||||
throw new ArgumentException("The component type must be a subclass of ComponentBase.", nameof(componentType));
|
||||
}
|
||||
|
||||
var method = GetType().GetMethod(nameof(OpenDialog), BindingFlags.Instance | BindingFlags.Public);
|
||||
|
||||
method.MakeGenericMethod(componentType).Invoke(this, new object[] { title, parameters, options });
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Invokes <see cref="OnRefresh" />.
|
||||
/// </summary>
|
||||
@@ -157,6 +177,33 @@ namespace Radzen
|
||||
return task.Task;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Opens a dialog with the specified arguments dynamically.
|
||||
/// </summary>
|
||||
/// <param name="title">The text displayed in the title bar of the dialog.</param>
|
||||
/// <param name="componentType">The type of the Blazor component to be displayed in a dialog. Must inherit from <see cref="ComponentBase"/>.</param>
|
||||
/// <param name="parameters">The dialog parameters, passed as property values of the specified component.</param>
|
||||
/// <param name="options">The dialog options.</param>
|
||||
/// <returns>A task that represents the result passed as an argument to <see cref="Close"/>.</returns>
|
||||
/// <exception cref="ArgumentException">Thrown if <paramref name="componentType"/> does not inherit from <see cref="ComponentBase"/>.</exception>
|
||||
public virtual Task<dynamic> OpenAsync(string title, Type componentType, Dictionary<string, object> parameters = null, DialogOptions options = null)
|
||||
{
|
||||
if (!typeof(ComponentBase).IsAssignableFrom(componentType))
|
||||
{
|
||||
throw new ArgumentException("The component type must be a subclass of ComponentBase.", nameof(componentType));
|
||||
}
|
||||
|
||||
var task = new TaskCompletionSource<dynamic>();
|
||||
tasks.Add(task);
|
||||
|
||||
var method = GetType().GetMethod(nameof(OpenDialog), BindingFlags.Instance | BindingFlags.Public);
|
||||
|
||||
method.MakeGenericMethod(componentType).Invoke(this, new object[] { title, parameters, options });
|
||||
|
||||
return task.Task;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Opens a side dialog with the specified arguments
|
||||
/// </summary>
|
||||
@@ -180,6 +227,85 @@ namespace Radzen
|
||||
return _sideDialogTask.Task;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Opens a side dialog with the specified arguments dynamically.
|
||||
/// </summary>
|
||||
/// <param name="title">The text displayed in the title bar of the side dialog.</param>
|
||||
/// <param name="componentType">The type of the Blazor component to be displayed in the side dialog. Must inherit from <see cref="ComponentBase"/>.</param>
|
||||
/// <param name="parameters">The dialog parameters, passed as property values of the specified component.</param>
|
||||
/// <param name="options">The side dialog options.</param>
|
||||
/// <returns>A task that represents the result passed as an argument to <see cref="CloseSide"/>.</returns>
|
||||
/// <exception cref="ArgumentException">Thrown if <paramref name="componentType"/> does not inherit from <see cref="ComponentBase"/>.</exception>
|
||||
public Task<dynamic> OpenSideAsync(string title, Type componentType, Dictionary<string, object> parameters = null, SideDialogOptions options = null)
|
||||
{
|
||||
if (!typeof(ComponentBase).IsAssignableFrom(componentType))
|
||||
{
|
||||
throw new ArgumentException("The component type must be a subclass of ComponentBase.", nameof(componentType));
|
||||
}
|
||||
|
||||
CloseSide();
|
||||
_sideDialogTask = new TaskCompletionSource<dynamic>();
|
||||
|
||||
if (options == null)
|
||||
{
|
||||
options = new SideDialogOptions();
|
||||
}
|
||||
|
||||
options.Title = title;
|
||||
OnSideOpen?.Invoke(componentType, parameters ?? new Dictionary<string, object>(), options);
|
||||
|
||||
return _sideDialogTask.Task;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Opens a side dialog with the specified arguments
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type of Blazor component which will be displayed in the side dialog.</typeparam>
|
||||
/// <param name="title">The text displayed in the title bar of the side dialog.</param>
|
||||
/// <param name="parameters">The dialog parameters. Passed as property values of <typeparamref name="T"/></param>
|
||||
/// <param name="options">The side dialog options.</param>
|
||||
public void OpenSide<T>(string title, Dictionary<string, object> parameters = null, SideDialogOptions options = null)
|
||||
where T : ComponentBase
|
||||
{
|
||||
CloseSide();
|
||||
|
||||
if (options == null)
|
||||
{
|
||||
options = new SideDialogOptions();
|
||||
}
|
||||
|
||||
options.Title = title;
|
||||
OnSideOpen?.Invoke(typeof(T), parameters ?? new Dictionary<string, object>(), options);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Opens a side dialog with the specified arguments dynamically.
|
||||
/// </summary>
|
||||
/// <param name="title">The text displayed in the title bar of the side dialog.</param>
|
||||
/// <param name="componentType">The type of the Blazor component to be displayed in the side dialog. Must inherit from <see cref="ComponentBase"/>.</param>
|
||||
/// <param name="parameters">The dialog parameters, passed as property values of the specified component.</param>
|
||||
/// <param name="options">The side dialog options.</param>
|
||||
/// <exception cref="ArgumentException">Thrown if <paramref name="componentType"/> does not inherit from <see cref="ComponentBase"/>.</exception>
|
||||
public void OpenSide(string title, Type componentType, Dictionary<string, object> parameters = null, SideDialogOptions options = null)
|
||||
{
|
||||
if (!typeof(ComponentBase).IsAssignableFrom(componentType))
|
||||
{
|
||||
throw new ArgumentException("The component type must be a subclass of ComponentBase.", nameof(componentType));
|
||||
}
|
||||
|
||||
CloseSide();
|
||||
|
||||
if (options == null)
|
||||
{
|
||||
options = new SideDialogOptions();
|
||||
}
|
||||
|
||||
options.Title = title;
|
||||
OnSideOpen?.Invoke(componentType, parameters ?? new Dictionary<string, object>(), options);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Closes the side dialog
|
||||
/// </summary>
|
||||
@@ -189,8 +315,9 @@ namespace Radzen
|
||||
if (_sideDialogTask?.Task.IsCompleted == false)
|
||||
{
|
||||
_sideDialogTask.TrySetResult(result);
|
||||
OnSideClose?.Invoke(result);
|
||||
}
|
||||
|
||||
OnSideClose?.Invoke(result);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -6,7 +6,6 @@ using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Linq.Dynamic.Core;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Radzen
|
||||
@@ -272,7 +271,7 @@ namespace Radzen
|
||||
/// <summary>
|
||||
/// The selected items
|
||||
/// </summary>
|
||||
protected IList<object> selectedItems = new List<object>();
|
||||
protected ISet<object> selectedItems = new HashSet<object>();
|
||||
/// <summary>
|
||||
/// The selected item
|
||||
/// </summary>
|
||||
@@ -288,10 +287,10 @@ namespace Radzen
|
||||
return;
|
||||
}
|
||||
|
||||
if (selectedItems.Count != View.Cast<object>().ToList().Where(i => disabledPropertyGetter != null ? disabledPropertyGetter(i) as bool? != true : true).Count())
|
||||
if (selectedItems.Count != View.Cast<object>().ToList().Where(i => disabledPropertyGetter == null || disabledPropertyGetter(i) as bool? != true).Count())
|
||||
{
|
||||
selectedItems.Clear();
|
||||
selectedItems = View.Cast<object>().ToList().Where(i => disabledPropertyGetter != null ? disabledPropertyGetter(i) as bool? != true : true).ToList();
|
||||
selectedItems = View.Cast<object>().ToList().Where(i => disabledPropertyGetter == null || disabledPropertyGetter(i) as bool? != true).ToHashSet(ItemComparer);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -341,15 +340,17 @@ namespace Radzen
|
||||
|
||||
internal bool IsAllSelected()
|
||||
{
|
||||
List<object> notDisabledItemsInList = View.Cast<object>().ToList()
|
||||
.Where(i => disabledPropertyGetter == null || disabledPropertyGetter(i) as bool? != true)
|
||||
.ToList();
|
||||
|
||||
if (LoadData.HasDelegate && !string.IsNullOrEmpty(ValueProperty))
|
||||
{
|
||||
return View != null && View.Cast<object>().ToList()
|
||||
.Where(i => disabledPropertyGetter != null ? disabledPropertyGetter(i) as bool? != true : true)
|
||||
return View != null && notDisabledItemsInList.Count > 0 && notDisabledItemsInList
|
||||
.All(i => IsItemSelectedByValue(GetItemOrValueFromProperty(i, ValueProperty)));
|
||||
}
|
||||
|
||||
return View != null && selectedItems.Count == View.Cast<object>().ToList()
|
||||
.Where(i => disabledPropertyGetter != null ? disabledPropertyGetter(i) as bool? != true : true).Count();
|
||||
return View != null && notDisabledItemsInList.Count > 0 && selectedItems.Count == notDisabledItemsInList.Count;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -434,9 +435,13 @@ namespace Radzen
|
||||
|
||||
var type = query.ElementType;
|
||||
|
||||
if (type == typeof(object) && typeof(EnumerableQuery).IsAssignableFrom(query.GetType()) && query.Any())
|
||||
if (type == typeof(object) && typeof(EnumerableQuery).IsAssignableFrom(query.GetType()) && query.Cast<object>().Any())
|
||||
{
|
||||
type = query.FirstOrDefault().GetType();
|
||||
var firstElement = query.Cast<object>().FirstOrDefault(i => i != null);
|
||||
if (firstElement != null)
|
||||
{
|
||||
type = firstElement.GetType();
|
||||
}
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(ValueProperty))
|
||||
@@ -453,6 +458,11 @@ namespace Radzen
|
||||
{
|
||||
disabledPropertyGetter = GetGetter(DisabledProperty, type);
|
||||
}
|
||||
|
||||
if (selectedItems.Count == 0)
|
||||
{
|
||||
selectedItems = new HashSet<object>(ItemComparer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -675,8 +685,10 @@ namespace Radzen
|
||||
|
||||
if (selectedIndex >= 0 && selectedIndex <= items.Count() - 1)
|
||||
{
|
||||
await JSRuntime.InvokeAsync<string>("Radzen.setInputValue", search, $"{searchText}".Trim());
|
||||
var itemToSelect = items.ElementAtOrDefault(selectedIndex);
|
||||
|
||||
await JSRuntime.InvokeAsync<string>("Radzen.setInputValue", search, $"{searchText}".Trim());
|
||||
|
||||
if (itemToSelect != null)
|
||||
{
|
||||
await OnSelectItem(itemToSelect, true);
|
||||
@@ -730,9 +742,10 @@ namespace Radzen
|
||||
}
|
||||
else
|
||||
{
|
||||
var filteredItems = Query.Where(TextProperty, args.Key, StringFilterOperator.StartsWith, FilterCaseSensitivity.CaseInsensitive)
|
||||
.Cast<object>()
|
||||
.ToList();
|
||||
var filteredItems = (!string.IsNullOrEmpty(TextProperty) ?
|
||||
Query.Where(TextProperty, args.Key, StringFilterOperator.StartsWith, FilterCaseSensitivity.CaseInsensitive) :
|
||||
Query)
|
||||
.Cast(Query.ElementType).Cast<dynamic>().ToList();
|
||||
|
||||
|
||||
if (previousKey != args.Key)
|
||||
@@ -986,7 +999,7 @@ namespace Radzen
|
||||
{
|
||||
if (Multiple)
|
||||
{
|
||||
return selectedItems.IndexOf(item) != -1;
|
||||
return selectedItems.Contains(item);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1130,9 +1143,13 @@ namespace Radzen
|
||||
var query = Data.AsQueryable();
|
||||
var elementType = query.ElementType;
|
||||
|
||||
if (elementType == typeof(object) && typeof(EnumerableQuery).IsAssignableFrom(query.GetType()) && query.Any())
|
||||
if (elementType == typeof(object) && typeof(EnumerableQuery).IsAssignableFrom(query.GetType()) && query.Cast<object>().Any())
|
||||
{
|
||||
elementType = query.FirstOrDefault().GetType();
|
||||
var firstElement = query.Cast<object>().FirstOrDefault(i => i != null);
|
||||
if (firstElement != null)
|
||||
{
|
||||
elementType = firstElement.GetType();
|
||||
}
|
||||
}
|
||||
|
||||
if (elementType != null)
|
||||
@@ -1212,18 +1229,14 @@ namespace Radzen
|
||||
}
|
||||
else
|
||||
{
|
||||
selectedItems = selectedItems.AsQueryable().Where(DynamicLinqCustomTypeProvider.ParsingConfig, $@"!object.Equals(it.{ValueProperty},@0)", value).ToList();
|
||||
selectedItems = selectedItems.AsQueryable().Where(i => !object.Equals(GetItemOrValueFromProperty(i, ValueProperty), value)).ToHashSet(ItemComparer);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!selectedItems.Any(i => object.Equals(i, item)))
|
||||
if (!selectedItems.Add(item))
|
||||
{
|
||||
selectedItems.Add(item);
|
||||
}
|
||||
else
|
||||
{
|
||||
selectedItems = selectedItems.Where(i => !object.Equals(i, item)).ToList();
|
||||
selectedItems.Remove(item);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1247,7 +1260,16 @@ namespace Radzen
|
||||
}
|
||||
else
|
||||
{
|
||||
SelectedItem = view.AsQueryable().Where(DynamicLinqCustomTypeProvider.ParsingConfig, $@"{ValueProperty} == @0", value).FirstOrDefault();
|
||||
SelectedItem = view.AsQueryable().Where(new FilterDescriptor[]
|
||||
{
|
||||
new FilterDescriptor()
|
||||
{
|
||||
Property = ValueProperty,
|
||||
FilterValue = value
|
||||
}
|
||||
},
|
||||
LogicalFilterOperator.And,
|
||||
FilterCaseSensitivity.Default).FirstOrDefault();
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -1264,7 +1286,7 @@ namespace Radzen
|
||||
{
|
||||
if (!string.IsNullOrEmpty(ValueProperty))
|
||||
{
|
||||
foreach (object v in values.ToDynamicList())
|
||||
foreach (object v in values.Cast<dynamic>().ToList())
|
||||
{
|
||||
dynamic item;
|
||||
|
||||
@@ -1274,10 +1296,19 @@ namespace Radzen
|
||||
}
|
||||
else
|
||||
{
|
||||
item = view.AsQueryable().Where(DynamicLinqCustomTypeProvider.ParsingConfig, $@"{ValueProperty} == @0", v).FirstOrDefault();
|
||||
item = view.AsQueryable().Where(new FilterDescriptor[]
|
||||
{
|
||||
new FilterDescriptor()
|
||||
{
|
||||
Property = ValueProperty,
|
||||
FilterValue = v
|
||||
}
|
||||
},
|
||||
LogicalFilterOperator.And,
|
||||
FilterCaseSensitivity.Default).FirstOrDefault();
|
||||
}
|
||||
|
||||
if (!object.Equals(item, null) && !selectedItems.AsQueryable().Where(DynamicLinqCustomTypeProvider.ParsingConfig, $@"object.Equals(it.{ValueProperty},@0)", v).Any())
|
||||
if (!object.Equals(item, null) && !selectedItems.AsQueryable().Where(i => object.Equals(GetItemOrValueFromProperty(i, ValueProperty), v)).Any())
|
||||
{
|
||||
selectedItems.Add(item);
|
||||
}
|
||||
@@ -1285,7 +1316,7 @@ namespace Radzen
|
||||
}
|
||||
else
|
||||
{
|
||||
selectedItems = ((IEnumerable)values).Cast<object>().ToList();
|
||||
selectedItems = values.Cast<object>().ToHashSet(ItemComparer);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1297,6 +1328,11 @@ namespace Radzen
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// For lists of objects, an IEqualityComparer to control how selected items are determined
|
||||
/// </summary>
|
||||
[Parameter] public IEqualityComparer<object> ItemComparer { get; set; }
|
||||
|
||||
internal bool IsItemSelectedByValue(object v)
|
||||
{
|
||||
switch (internalValue)
|
||||
|
||||
144
Radzen.Blazor/DynamicExtensions.cs
Normal file
144
Radzen.Blazor/DynamicExtensions.cs
Normal file
@@ -0,0 +1,144 @@
|
||||
using Radzen;
|
||||
using System.Linq.Expressions;
|
||||
|
||||
namespace System.Linq.Dynamic.Core
|
||||
{
|
||||
/// <summary>
|
||||
/// Class DynamicExtensions used to replace System.Linq.Dynamic.Core library.
|
||||
/// </summary>
|
||||
public static class DynamicExtensions
|
||||
{
|
||||
static readonly Func<string, Type> typeLocator = type => AppDomain.CurrentDomain.GetAssemblies()
|
||||
.SelectMany(a => a.GetTypes()).FirstOrDefault(t => t.FullName.Replace("+", ".") == type);
|
||||
|
||||
/// <summary>
|
||||
/// Filters using the specified filter descriptors.
|
||||
/// </summary>
|
||||
public static IQueryable<T> Where<T>(
|
||||
this IQueryable<T> source,
|
||||
string predicate,
|
||||
object[] parameters = null, object[] otherParameters = null)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (parameters != null && !string.IsNullOrEmpty(predicate))
|
||||
{
|
||||
for (var i = 0; i < parameters.Length; i++)
|
||||
{
|
||||
object param = parameters[i];
|
||||
string value = param switch
|
||||
{
|
||||
string s when s == string.Empty => @"""""",
|
||||
null => "null",
|
||||
string s => @$"""{s.Replace("\"", "\\\"")}""",
|
||||
bool b => b.ToString().ToLower(),
|
||||
Guid g => $"Guid.Parse(\"{g}\")",
|
||||
DateTime dt => $"DateTime.Parse(\"{dt:yyyy-MM-ddTHH:mm:ss.fffZ}\")",
|
||||
DateTimeOffset dto => $"DateTime.Parse(\"{dto.UtcDateTime:yyyy-MM-ddTHH:mm:ss.fffZ}\")",
|
||||
DateOnly d => $"DateOnly.Parse(\"{d:yyy-MM-dd}\")",
|
||||
TimeOnly t => $"TimeOnly.Parse(\"{t:HH:mm:ss}\")",
|
||||
_ => param.ToString()
|
||||
};
|
||||
|
||||
predicate = predicate.Replace($"@{i}", $"{value}");
|
||||
}
|
||||
}
|
||||
|
||||
predicate = (predicate == "true" ? "" : predicate)
|
||||
.Replace("DateTime(", "DateTime.Parse(")
|
||||
.Replace("DateTimeOffset(", "DateTimeOffset.Parse(")
|
||||
.Replace("DateOnly(", "DateOnly.Parse(")
|
||||
.Replace("Guid(", "Guid.Parse(")
|
||||
.Replace(" = ", " == ");
|
||||
|
||||
return !string.IsNullOrEmpty(predicate) ?
|
||||
source.Where(ExpressionParser.ParsePredicate<T>(predicate, typeLocator)) : source;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
throw new InvalidOperationException($"Invalid predicate: {predicate}", ex);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sorts the elements of a sequence in ascending or descending order according to a key.
|
||||
/// </summary>
|
||||
public static IOrderedQueryable<T> OrderBy<T>(
|
||||
this IQueryable<T> source,
|
||||
string selector,
|
||||
object[] parameters = null)
|
||||
{
|
||||
try
|
||||
{
|
||||
return QueryableExtension.OrderBy(source, selector);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
throw new InvalidOperationException($"Invalid selector: {selector}.", ex);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Projects each element of a sequence into a collection of property values.
|
||||
/// </summary>
|
||||
public static IQueryable Select<T>(this IQueryable<T> source, string selector, object[] parameters = null)
|
||||
{
|
||||
if (source.ElementType == typeof(object))
|
||||
{
|
||||
var elementType = source.ElementType;
|
||||
|
||||
if (source.Expression is MethodCallExpression methodCall && methodCall.Method.Name == "Cast")
|
||||
{
|
||||
elementType = methodCall.Arguments[0].Type.GetGenericArguments().FirstOrDefault() ?? typeof(object);
|
||||
}
|
||||
else if (typeof(EnumerableQuery).IsAssignableFrom(source.GetType()))
|
||||
{
|
||||
elementType = source.FirstOrDefault()?.GetType() ?? typeof(object);
|
||||
}
|
||||
|
||||
return source.Cast(elementType).Select(selector, expression => ExpressionParser.ParseLambda(expression, elementType));
|
||||
}
|
||||
|
||||
return source.Select(selector, expression => ExpressionParser.ParseLambda<T>(expression));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Projects each element of a sequence into a collection of property values.
|
||||
/// </summary>
|
||||
public static IQueryable Select(this IQueryable source, string selector, object[] parameters = null)
|
||||
{
|
||||
return source.Select(selector, expression => ExpressionParser.ParseLambda(expression, source.ElementType));
|
||||
}
|
||||
|
||||
private static IQueryable Select(this IQueryable source, string selector, Func<string, LambdaExpression> lambdaCreator)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (string.IsNullOrEmpty(selector))
|
||||
{
|
||||
return source;
|
||||
}
|
||||
|
||||
if (!selector.Contains("=>"))
|
||||
{
|
||||
var properties = selector
|
||||
.Replace("new (", "").Replace(")", "").Replace("new {", "").Replace("}", "").Trim()
|
||||
.Split(",", StringSplitOptions.RemoveEmptyEntries);
|
||||
|
||||
selector = string.Join(", ", properties
|
||||
.Select(s => (s.Contains(" as ") ? s.Split(" as ").LastOrDefault().Trim().Replace(".", "_") : s.Trim().Replace(".", "_")) +
|
||||
" = " + $"it.{s.Split(" as ").FirstOrDefault().Replace(".", "?.").Trim()}"));
|
||||
}
|
||||
|
||||
var lambda = lambdaCreator(selector.Contains("=>") ? selector : $"it => new {{ {selector} }}");
|
||||
|
||||
return source.Provider.CreateQuery(Expression.Call(typeof(Queryable), nameof(Queryable.Select),
|
||||
[source.ElementType, lambda.Body.Type], source.Expression, Expression.Quote(lambda)));
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
throw new InvalidOperationException($"Invalid selector: {selector}.", ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,18 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq.Dynamic.Core;
|
||||
using System.Linq.Dynamic.Core.CustomTypeProviders;
|
||||
using System.Reflection;
|
||||
|
||||
namespace Radzen.Blazor
|
||||
{
|
||||
class DynamicLinqCustomTypeProvider : IDynamicLinkCustomTypeProvider
|
||||
{
|
||||
static readonly HashSet<Type> empty = [];
|
||||
public HashSet<Type> GetCustomTypes() => empty;
|
||||
public Dictionary<Type, List<MethodInfo>> GetExtensionMethods() => throw new NotSupportedException();
|
||||
public Type ResolveType(string typeName) => throw new NotSupportedException();
|
||||
public Type ResolveTypeBySimpleName(string simpleTypeName) => throw new NotSupportedException();
|
||||
public static ParsingConfig ParsingConfig = new() { CustomTypeProvider = new DynamicLinqCustomTypeProvider() };
|
||||
}
|
||||
}
|
||||
548
Radzen.Blazor/ExpressionParser.cs
Normal file
548
Radzen.Blazor/ExpressionParser.cs
Normal file
@@ -0,0 +1,548 @@
|
||||
using Microsoft.CodeAnalysis;
|
||||
using Microsoft.CodeAnalysis.CSharp;
|
||||
using Microsoft.CodeAnalysis.CSharp.Syntax;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Linq.Expressions;
|
||||
using System.Reflection;
|
||||
using System.Reflection.Emit;
|
||||
|
||||
namespace Radzen;
|
||||
|
||||
static class DynamicTypeFactory
|
||||
{
|
||||
public static Type CreateType(string typeName, string[] propertyNames, Type[] propertyTypes)
|
||||
{
|
||||
if (propertyNames.Length != propertyTypes.Length)
|
||||
{
|
||||
throw new ArgumentException("Property names and types count mismatch.");
|
||||
}
|
||||
|
||||
var assemblyName = new AssemblyName("DynamicTypesAssembly");
|
||||
var assemblyBuilder = AssemblyBuilder.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.Run);
|
||||
var moduleBuilder = assemblyBuilder.DefineDynamicModule("DynamicTypesModule");
|
||||
|
||||
var typeBuilder = moduleBuilder.DefineType(typeName, TypeAttributes.Public | TypeAttributes.Class | TypeAttributes.Sealed);
|
||||
|
||||
for (int i = 0; i < propertyNames.Length; i++)
|
||||
{
|
||||
var fieldBuilder = typeBuilder.DefineField("_" + propertyNames[i], propertyTypes[i], FieldAttributes.Private);
|
||||
var propertyBuilder = typeBuilder.DefineProperty(propertyNames[i], PropertyAttributes.None, propertyTypes[i], null);
|
||||
|
||||
var getterMethod = typeBuilder.DefineMethod(
|
||||
"get_" + propertyNames[i],
|
||||
MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig,
|
||||
propertyTypes[i],
|
||||
Type.EmptyTypes);
|
||||
|
||||
var getterIl = getterMethod.GetILGenerator();
|
||||
getterIl.Emit(OpCodes.Ldarg_0);
|
||||
getterIl.Emit(OpCodes.Ldfld, fieldBuilder);
|
||||
getterIl.Emit(OpCodes.Ret);
|
||||
|
||||
propertyBuilder.SetGetMethod(getterMethod);
|
||||
|
||||
var setterMethod = typeBuilder.DefineMethod(
|
||||
"set_" + propertyNames[i],
|
||||
MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig,
|
||||
null,
|
||||
[propertyTypes[i]]);
|
||||
|
||||
var setterIl = setterMethod.GetILGenerator();
|
||||
setterIl.Emit(OpCodes.Ldarg_0);
|
||||
setterIl.Emit(OpCodes.Ldarg_1);
|
||||
setterIl.Emit(OpCodes.Stfld, fieldBuilder);
|
||||
setterIl.Emit(OpCodes.Ret);
|
||||
|
||||
propertyBuilder.SetSetMethod(setterMethod);
|
||||
}
|
||||
|
||||
var dynamicType = typeBuilder.CreateType();
|
||||
return dynamicType;
|
||||
}
|
||||
}
|
||||
|
||||
class ExpressionSyntaxVisitor : CSharpSyntaxVisitor<Expression>
|
||||
{
|
||||
private readonly ParameterExpression parameter;
|
||||
private readonly Func<string, Type> typeLocator;
|
||||
|
||||
public ExpressionSyntaxVisitor(ParameterExpression parameter, Func<string, Type> typeLocator)
|
||||
{
|
||||
this.parameter = parameter;
|
||||
this.typeLocator = typeLocator;
|
||||
}
|
||||
|
||||
public override Expression VisitBinaryExpression(BinaryExpressionSyntax node)
|
||||
{
|
||||
var left = Visit(node.Left);
|
||||
|
||||
var right = ConvertIfNeeded(Visit(node.Right), left.Type);
|
||||
|
||||
return Expression.MakeBinary(ParseBinaryOperator(node.OperatorToken), left, right);
|
||||
}
|
||||
|
||||
|
||||
public override Expression VisitMemberAccessExpression(MemberAccessExpressionSyntax node)
|
||||
{
|
||||
var expression = Visit(node.Expression) ?? parameter;
|
||||
return Expression.PropertyOrField(expression, node.Name.Identifier.Text);
|
||||
}
|
||||
|
||||
public override Expression VisitLiteralExpression(LiteralExpressionSyntax node)
|
||||
{
|
||||
return Expression.Constant(ParseLiteral(node));
|
||||
}
|
||||
|
||||
public override Expression VisitIdentifierName(IdentifierNameSyntax node)
|
||||
{
|
||||
if (node.Identifier.Text == parameter.Name)
|
||||
{
|
||||
return parameter;
|
||||
}
|
||||
|
||||
var type = GetType(node.Identifier.Text);
|
||||
|
||||
if (type != null)
|
||||
{
|
||||
return Expression.Constant(type);
|
||||
}
|
||||
|
||||
throw new NotSupportedException("Unsupported identifier: " + node.Identifier.Text);
|
||||
}
|
||||
|
||||
public override Expression VisitConditionalExpression(ConditionalExpressionSyntax node)
|
||||
{
|
||||
var condition = Visit(node.Condition);
|
||||
|
||||
var whenTrue = Visit(node.WhenTrue);
|
||||
|
||||
var whenFalse = Visit(node.WhenFalse);
|
||||
|
||||
if (whenTrue.Type != whenFalse.Type)
|
||||
{
|
||||
if (whenTrue.Type == typeof(object))
|
||||
{
|
||||
whenTrue = Expression.Convert(whenTrue, whenFalse.Type);
|
||||
}
|
||||
else if (whenFalse.Type == typeof(object))
|
||||
{
|
||||
whenFalse = Expression.Convert(whenFalse, whenTrue.Type);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new NotSupportedException("Conditional expression types mismatch: " + whenTrue.Type + " and " + whenFalse.Type);
|
||||
}
|
||||
}
|
||||
|
||||
return Expression.Condition(condition, whenTrue, whenFalse);
|
||||
}
|
||||
|
||||
public override Expression VisitParenthesizedExpression(ParenthesizedExpressionSyntax node)
|
||||
{
|
||||
return Visit(node.Expression);
|
||||
}
|
||||
|
||||
private Type GetType(string typeName)
|
||||
{
|
||||
var nullable = typeName.EndsWith('?');
|
||||
|
||||
if (nullable)
|
||||
{
|
||||
typeName = typeName[..^1];
|
||||
}
|
||||
|
||||
var type = typeName switch
|
||||
{
|
||||
nameof(Int32) => typeof(int),
|
||||
nameof(Int64) => typeof(long),
|
||||
nameof(Double) => typeof(double),
|
||||
nameof(Single) => typeof(float),
|
||||
nameof(Decimal) => typeof(decimal),
|
||||
nameof(String) => typeof(string),
|
||||
nameof(Boolean) => typeof(bool),
|
||||
nameof(DateTime) => typeof(DateTime),
|
||||
nameof(DateOnly) => typeof(DateOnly),
|
||||
nameof(DateTimeOffset) => typeof(DateTimeOffset),
|
||||
nameof(TimeOnly) => typeof(TimeOnly),
|
||||
nameof(Guid) => typeof(Guid),
|
||||
nameof(Char) => typeof(char),
|
||||
"int" => typeof(int),
|
||||
"long" => typeof(long),
|
||||
"double" => typeof(double),
|
||||
"float" => typeof(float),
|
||||
"decimal" => typeof(decimal),
|
||||
"string" => typeof(string),
|
||||
"char" => typeof(char),
|
||||
"bool" => typeof(bool),
|
||||
_ => typeLocator?.Invoke(typeName)
|
||||
};
|
||||
|
||||
if (nullable && type != null)
|
||||
{
|
||||
type = typeof(Nullable<>).MakeGenericType(type);
|
||||
}
|
||||
|
||||
return type;
|
||||
}
|
||||
|
||||
public override Expression VisitCastExpression(CastExpressionSyntax node)
|
||||
{
|
||||
var typeName = node.Type.ToString();
|
||||
|
||||
var targetType = GetType(typeName);
|
||||
|
||||
if (targetType == null)
|
||||
{
|
||||
throw new NotSupportedException("Unsupported cast type: " + node.Type);
|
||||
}
|
||||
|
||||
var operand = Visit(node.Expression);
|
||||
|
||||
return Expression.Convert(operand, targetType);
|
||||
}
|
||||
|
||||
public override Expression VisitImplicitArrayCreationExpression(ImplicitArrayCreationExpressionSyntax node)
|
||||
{
|
||||
var expressions = node.Initializer.Expressions.Select(Visit).ToArray();
|
||||
var elementType = expressions.Length > 0 ? expressions[0].Type : typeof(object);
|
||||
return Expression.NewArrayInit(elementType, expressions);
|
||||
}
|
||||
|
||||
public override Expression VisitArrayCreationExpression(ArrayCreationExpressionSyntax node)
|
||||
{
|
||||
var elementType = GetType(node.Type.ElementType.ToString());
|
||||
|
||||
if (elementType == null)
|
||||
{
|
||||
throw new NotSupportedException("Unsupported array element type: " + node.Type.ElementType);
|
||||
}
|
||||
|
||||
var expressions = node.Initializer.Expressions.Select(e => ConvertIfNeeded(Visit(e), elementType));
|
||||
|
||||
return Expression.NewArrayInit(elementType, expressions);
|
||||
}
|
||||
|
||||
private static MethodCallExpression CallStaticMethod(Type type, string methodName, Expression[] arguments, Type[] argumentTypes)
|
||||
{
|
||||
var methodInfo = type.GetMethod(methodName, BindingFlags.Public | BindingFlags.Static, argumentTypes);
|
||||
|
||||
if (methodInfo != null)
|
||||
{
|
||||
return Expression.Call(methodInfo, arguments);
|
||||
}
|
||||
|
||||
throw new NotSupportedException("Method not found: " + methodName);
|
||||
}
|
||||
|
||||
public override Expression DefaultVisit(SyntaxNode node)
|
||||
{
|
||||
throw new NotSupportedException("Unsupported syntax: " + node.GetType().Name);
|
||||
}
|
||||
|
||||
public override Expression VisitSimpleLambdaExpression(SimpleLambdaExpressionSyntax node)
|
||||
{
|
||||
var body = Visit(node.Body);
|
||||
|
||||
return Expression.Lambda(body, parameter);
|
||||
}
|
||||
|
||||
private Expression VisitArgument(Expression instance, ArgumentSyntax argument)
|
||||
{
|
||||
if (argument.Expression is SimpleLambdaExpressionSyntax lambda)
|
||||
{
|
||||
var itemType = GetItemType(instance.Type);
|
||||
|
||||
var visitor = new ExpressionSyntaxVisitor(Expression.Parameter(itemType, lambda.Parameter.Identifier.Text), typeLocator);
|
||||
|
||||
return visitor.Visit(lambda);
|
||||
}
|
||||
|
||||
return Visit(argument.Expression);
|
||||
}
|
||||
|
||||
private static Expression ConvertIfNeeded(Expression expression, Type targetType)
|
||||
{
|
||||
if (expression is not LambdaExpression)
|
||||
{
|
||||
return expression.Type == targetType ? expression : Expression.Convert(expression, targetType);
|
||||
}
|
||||
|
||||
return expression;
|
||||
}
|
||||
|
||||
public override Expression VisitInvocationExpression(InvocationExpressionSyntax node)
|
||||
{
|
||||
if (node.Expression is MemberAccessExpressionSyntax methodCall)
|
||||
{
|
||||
var instance = Visit(methodCall.Expression);
|
||||
var arguments = node.ArgumentList.Arguments.Select(a => VisitArgument(instance, a)).ToArray();
|
||||
var argumentTypes = arguments.Select(a => a.Type).ToArray();
|
||||
|
||||
if (instance is ConstantExpression constant && constant.Value is Type type)
|
||||
{
|
||||
return CallStaticMethod(type, methodCall.Name.Identifier.Text, arguments, argumentTypes);
|
||||
}
|
||||
|
||||
var instanceType = instance.Type;
|
||||
var methodInfo = instanceType.GetMethod(methodCall.Name.Identifier.Text, BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static, argumentTypes);
|
||||
|
||||
if (methodInfo == null)
|
||||
{
|
||||
methodInfo = typeof(Enumerable)
|
||||
.GetMethods(BindingFlags.Public | BindingFlags.Static)
|
||||
.FirstOrDefault(m => m.Name == methodCall.Name.Identifier.Text && m.GetParameters().Length == arguments.Length + 1);
|
||||
|
||||
if (methodInfo != null)
|
||||
{
|
||||
var argumentType = GetItemType(instanceType);
|
||||
var genericMethod = methodInfo.MakeGenericMethod(argumentType);
|
||||
var parameters = genericMethod.GetParameters();
|
||||
var argumentsWithInstance = new[] { instance }.Concat(arguments).ToArray();
|
||||
|
||||
if (parameters.Length != argumentsWithInstance.Length)
|
||||
{
|
||||
throw new NotSupportedException("Unsupported method call: " + methodCall.Name.Identifier.Text);
|
||||
}
|
||||
|
||||
return Expression.Call(genericMethod, argumentsWithInstance.Select((a, index) => ConvertIfNeeded(a, parameters[index].ParameterType)));
|
||||
}
|
||||
}
|
||||
|
||||
if (methodInfo == null)
|
||||
{
|
||||
throw new NotSupportedException("Unsupported method call: " + methodCall.Name.Identifier.Text);
|
||||
}
|
||||
|
||||
return Expression.Call(instance, methodInfo, arguments);
|
||||
}
|
||||
|
||||
throw new NotSupportedException("Unsupported invocation expression: " + node.ToString());
|
||||
}
|
||||
|
||||
private static Type GetItemType(Type enumerableOrArray)
|
||||
{
|
||||
return enumerableOrArray.IsArray ? enumerableOrArray.GetElementType() : enumerableOrArray.GetGenericArguments()[0];
|
||||
}
|
||||
|
||||
|
||||
private static object ParseLiteral(LiteralExpressionSyntax literal)
|
||||
{
|
||||
return literal.Kind() switch
|
||||
{
|
||||
SyntaxKind.StringLiteralExpression => literal.Token.ValueText,
|
||||
SyntaxKind.NumericLiteralExpression => literal.Token.Value,
|
||||
SyntaxKind.TrueLiteralExpression => true,
|
||||
SyntaxKind.FalseLiteralExpression => false,
|
||||
SyntaxKind.NullLiteralExpression => null,
|
||||
_ => throw new NotSupportedException("Unsupported literal: " + literal),
|
||||
};
|
||||
}
|
||||
|
||||
private static ExpressionType ParseBinaryOperator(SyntaxToken token)
|
||||
{
|
||||
return token.Kind() switch
|
||||
{
|
||||
SyntaxKind.EqualsEqualsToken => ExpressionType.Equal,
|
||||
SyntaxKind.LessThanToken => ExpressionType.LessThan,
|
||||
SyntaxKind.GreaterThanToken => ExpressionType.GreaterThan,
|
||||
SyntaxKind.LessThanEqualsToken => ExpressionType.LessThanOrEqual,
|
||||
SyntaxKind.GreaterThanEqualsToken => ExpressionType.GreaterThanOrEqual,
|
||||
SyntaxKind.ExclamationEqualsToken => ExpressionType.NotEqual,
|
||||
SyntaxKind.AmpersandAmpersandToken => ExpressionType.AndAlso,
|
||||
SyntaxKind.BarBarToken => ExpressionType.OrElse,
|
||||
SyntaxKind.QuestionQuestionToken => ExpressionType.Coalesce,
|
||||
_ => throw new NotSupportedException("Unsupported operator: " + token.Text),
|
||||
};
|
||||
}
|
||||
|
||||
private static string GetPropertyNameFromInitializer(AnonymousObjectMemberDeclaratorSyntax initializer)
|
||||
{
|
||||
if (initializer.NameEquals != null)
|
||||
{
|
||||
return initializer.NameEquals.Name.Identifier.Text;
|
||||
}
|
||||
|
||||
var expression = initializer.Expression;
|
||||
|
||||
if (expression is MemberAccessExpressionSyntax memberAccess)
|
||||
{
|
||||
expression = memberAccess.Name;
|
||||
}
|
||||
|
||||
while (expression is ConditionalAccessExpressionSyntax conditionalAccess)
|
||||
{
|
||||
expression = conditionalAccess.WhenNotNull;
|
||||
}
|
||||
|
||||
if (expression is MemberBindingExpressionSyntax memberBinding)
|
||||
{
|
||||
expression = memberBinding.Name;
|
||||
}
|
||||
|
||||
if (expression is IdentifierNameSyntax identifier)
|
||||
{
|
||||
return identifier.Identifier.Text;
|
||||
}
|
||||
|
||||
throw new NotSupportedException("Unsupported initializer: " + initializer.ToString());
|
||||
}
|
||||
|
||||
public override Expression VisitAnonymousObjectCreationExpression(AnonymousObjectCreationExpressionSyntax node)
|
||||
{
|
||||
var properties = node.Initializers.Select(init =>
|
||||
{
|
||||
var name = GetPropertyNameFromInitializer(init);
|
||||
var value = Visit(init.Expression);
|
||||
return new { Name = name, Value = value };
|
||||
}).ToList();
|
||||
|
||||
var propertyNames = properties.Select(p => p.Name).ToArray();
|
||||
var propertyTypes = properties.Select(p => p.Value.Type).ToArray();
|
||||
var dynamicType = DynamicTypeFactory.CreateType(parameter.Type.Name, propertyNames, propertyTypes);
|
||||
|
||||
var bindings = properties.Select(p => Expression.Bind(dynamicType.GetProperty(p.Name), p.Value));
|
||||
return Expression.MemberInit(Expression.New(dynamicType), bindings);
|
||||
}
|
||||
|
||||
private Expression instance;
|
||||
|
||||
public override Expression VisitConditionalAccessExpression(ConditionalAccessExpressionSyntax node)
|
||||
{
|
||||
var expression = Visit(node.Expression);
|
||||
|
||||
instance = expression;
|
||||
|
||||
var whenNotNull = Visit(node.WhenNotNull);
|
||||
|
||||
instance = null;
|
||||
|
||||
if (expression.Type.IsValueType && Nullable.GetUnderlyingType(expression.Type) == null)
|
||||
{
|
||||
throw new NotSupportedException("Conditional access is not supported on non-nullable value types: " + expression.Type);
|
||||
}
|
||||
|
||||
if (!expression.Type.IsValueType || Nullable.GetUnderlyingType(expression.Type) != null)
|
||||
{
|
||||
return Expression.Condition(Expression.NotEqual(expression, Expression.Constant(null, expression.Type)),
|
||||
whenNotNull, Expression.Default(whenNotNull.Type)
|
||||
);
|
||||
}
|
||||
|
||||
return whenNotNull;
|
||||
}
|
||||
|
||||
public override Expression VisitMemberBindingExpression(MemberBindingExpressionSyntax node)
|
||||
{
|
||||
if (instance is Expression expression)
|
||||
{
|
||||
return Expression.PropertyOrField(expression, node.Name.Identifier.Text);
|
||||
}
|
||||
|
||||
throw new NotSupportedException("Unsupported member binding: " + node.ToString());
|
||||
}
|
||||
|
||||
public override Expression VisitElementAccessExpression(ElementAccessExpressionSyntax node)
|
||||
{
|
||||
var expression = Visit(node.Expression);
|
||||
var arguments = node.ArgumentList.Arguments.Select(arg => Visit(arg.Expression)).ToArray();
|
||||
|
||||
if (expression.Type.IsArray)
|
||||
{
|
||||
return Expression.ArrayIndex(expression, arguments);
|
||||
}
|
||||
|
||||
var indexer = expression.Type.GetProperties()
|
||||
.FirstOrDefault(p => p.GetIndexParameters().Length == arguments.Length);
|
||||
|
||||
if (indexer != null)
|
||||
{
|
||||
return Expression.MakeIndex(expression, indexer, arguments);
|
||||
}
|
||||
|
||||
throw new NotSupportedException("Unsupported element access: " + node.ToString());
|
||||
}
|
||||
|
||||
public override Expression VisitPrefixUnaryExpression(PrefixUnaryExpressionSyntax node)
|
||||
{
|
||||
var operand = Visit(node.Operand);
|
||||
|
||||
return node.OperatorToken.Kind() switch
|
||||
{
|
||||
SyntaxKind.MinusToken => Expression.Negate(operand),
|
||||
SyntaxKind.ExclamationToken => Expression.Not(operand),
|
||||
_ => throw new NotSupportedException("Unsupported unary operator: " + node.OperatorToken.Text),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Parse lambda expressions from strings.
|
||||
/// </summary>
|
||||
public static class ExpressionParser
|
||||
{
|
||||
/// <summary>
|
||||
/// Parses a lambda expression that returns a boolean value.
|
||||
/// </summary>
|
||||
public static Expression<Func<T, bool>> ParsePredicate<T>(string expression, Func<string, Type> typeLocator = null)
|
||||
{
|
||||
return ParseLambda<T, bool>(expression, typeLocator);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Parses a lambda expression that returns a typed result.
|
||||
/// </summary>
|
||||
public static Expression<Func<T, TResult>> ParseLambda<T, TResult>(string expression, Func<string, Type> typeLocator = null)
|
||||
{
|
||||
var (parameter, body) = Parse<T>(expression, typeLocator);
|
||||
|
||||
return Expression.Lambda<Func<T, TResult>>(body, parameter);
|
||||
}
|
||||
|
||||
|
||||
private static (ParameterExpression, Expression) Parse<T>(string expression, Func<string, Type> typeLocator)
|
||||
{
|
||||
var syntaxTree = CSharpSyntaxTree.ParseText(expression);
|
||||
var root = syntaxTree.GetRoot();
|
||||
var lambdaExpression = root.DescendantNodes().OfType<SimpleLambdaExpressionSyntax>().FirstOrDefault();
|
||||
if (lambdaExpression == null)
|
||||
{
|
||||
throw new ArgumentException("Invalid lambda expression.");
|
||||
}
|
||||
var parameter = Expression.Parameter(typeof(T), lambdaExpression.Parameter.Identifier.Text);
|
||||
var visitor = new ExpressionSyntaxVisitor(parameter, typeLocator);
|
||||
var body = visitor.Visit(lambdaExpression.Body);
|
||||
return (parameter, body);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Parses a lambda expression that returns untyped result.
|
||||
/// </summary>
|
||||
public static LambdaExpression ParseLambda<T>(string expression, Func<string, Type> typeLocator = null)
|
||||
{
|
||||
var (parameter, body) = Parse<T>(expression, typeLocator);
|
||||
|
||||
return Expression.Lambda(body, parameter);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Parses a lambda expression that returns untyped result.
|
||||
/// </summary>
|
||||
public static LambdaExpression ParseLambda(string expression, Type type, Func<string, Type> typeLocator = null)
|
||||
{
|
||||
var syntaxTree = CSharpSyntaxTree.ParseText(expression);
|
||||
var root = syntaxTree.GetRoot();
|
||||
var lambdaExpression = root.DescendantNodes().OfType<SimpleLambdaExpressionSyntax>().FirstOrDefault();
|
||||
|
||||
if (lambdaExpression == null)
|
||||
{
|
||||
throw new ArgumentException("Invalid lambda expression.");
|
||||
}
|
||||
|
||||
var parameter = Expression.Parameter(type, lambdaExpression.Parameter.Identifier.Text);
|
||||
var visitor = new ExpressionSyntaxVisitor(parameter, typeLocator);
|
||||
var body = visitor.Visit(lambdaExpression.Body);
|
||||
|
||||
return Expression.Lambda(body, parameter);
|
||||
}
|
||||
}
|
||||
@@ -35,7 +35,8 @@ namespace Radzen.Blazor
|
||||
/// </summary>
|
||||
public static IEnumerable<object> EnumAsKeyValuePair(Type enumType, Func<string, string> translationFunction = null)
|
||||
{
|
||||
return Enum.GetValues(enumType).Cast<Enum>().Distinct().Select(val => new { Value = Convert.ToInt32(val), Text = val.GetDisplayDescription(translationFunction) });
|
||||
Type underlyingType = Enum.GetUnderlyingType(enumType);
|
||||
return Enum.GetValues(enumType).Cast<Enum>().Distinct().Select(val => new { Value = Convert.ChangeType(val, underlyingType), Text = val.GetDisplayDescription(translationFunction) });
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -50,20 +50,24 @@ namespace Radzen.Blazor
|
||||
/// <param name="valueScale">The value scale.</param>
|
||||
/// <returns>RenderFragment.</returns>
|
||||
RenderFragment RenderOverlays(ScaleBase categoryScale, ScaleBase valueScale);
|
||||
|
||||
/// <summary>
|
||||
/// Renders the series tooltip.
|
||||
/// </summary>
|
||||
/// <param name="data">The data.</param>
|
||||
/// <param name="marginLeft">The left margin.</param>
|
||||
/// <param name="marginTop">The right margin.</param>
|
||||
/// <param name="chartHeight">Height of the whole char area.</param>
|
||||
/// <returns>RenderFragment.</returns>
|
||||
RenderFragment RenderTooltip(object data, double marginLeft, double marginTop, double chartHeight);
|
||||
RenderFragment RenderTooltip(object data);
|
||||
/// <summary>
|
||||
/// Renders a tooltip item with the specified data to be displayed in a shared tooltip
|
||||
/// </summary>
|
||||
RenderFragment RenderSharedTooltipItem(object category);
|
||||
/// <summary>
|
||||
/// Get position of the series tooltip.
|
||||
/// </summary>
|
||||
/// <param name="data">The data.</param>
|
||||
/// <returns>Position.</returns>
|
||||
Point GetTooltipPosition(object data);
|
||||
/// <summary>
|
||||
/// Renders the legend item.
|
||||
/// </summary>
|
||||
/// <returns>RenderFragment.</returns>
|
||||
|
||||
@@ -28,6 +28,12 @@ namespace Radzen.Blazor
|
||||
/// <summary>
|
||||
/// Renders tooltip
|
||||
/// </summary>
|
||||
RenderFragment RenderTooltip(double mouseX, double mouseY, double marginLeft, double marginTop);
|
||||
RenderFragment RenderTooltip(double mouseX, double mouseY);
|
||||
|
||||
/// <summary>
|
||||
/// Get position of the overlay tooltip.
|
||||
/// </summary>
|
||||
/// <returns>Position.</returns>
|
||||
Point GetTooltipPosition(double mouseX, double mouseY);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -77,6 +77,12 @@ namespace Radzen.Blazor
|
||||
/// <param name="appointments">The appointments for this range.</param>
|
||||
Task SelectMonth(DateTime monthStart, IEnumerable<AppointmentData> appointments);
|
||||
/// <summary>
|
||||
/// Selects the specified day.
|
||||
/// </summary>
|
||||
/// <param name="day">The selected day.</param>
|
||||
/// <param name="appointments">The appointments for this range.</param>
|
||||
Task SelectDay(DateTime day, IEnumerable<AppointmentData> appointments);
|
||||
/// <summary>
|
||||
/// Selects the specified more link.
|
||||
/// </summary>
|
||||
/// <param name="start">The start.</param>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2018-2024 Radzen Ltd
|
||||
Copyright (c) 2018-2025 Radzen Ltd
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
|
||||
@@ -53,7 +53,7 @@ namespace Radzen.Blazor
|
||||
|
||||
protected virtual double CalculateTickCount(int distance)
|
||||
{
|
||||
return Math.Ceiling(Math.Abs(Output.End - Output.Start) / distance);
|
||||
return Math.Max(1, Math.Ceiling(Math.Abs(Output.End - Output.Start) / distance));
|
||||
}
|
||||
|
||||
public override (double Start, double End, double Step) Ticks(int distance)
|
||||
@@ -113,12 +113,12 @@ namespace Radzen.Blazor
|
||||
Round = false;
|
||||
}
|
||||
|
||||
if (step <= 0)
|
||||
if (step == 0)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException("Step must be greater than zero");
|
||||
throw new ArgumentOutOfRangeException("Step must be non-zero");
|
||||
}
|
||||
|
||||
return (start, end, step);
|
||||
return (start, end, Math.Abs(step));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,5 +3,4 @@
|
||||
<assembly fullname="System.Core">
|
||||
<type fullname="System.Linq.Queryable" preserve="all" />
|
||||
</assembly>
|
||||
<assembly fullname="System.Linq.Dynamic.Core" />
|
||||
</linker>
|
||||
@@ -8,7 +8,7 @@ using System.Text;
|
||||
namespace Radzen
|
||||
{
|
||||
/// <summary>
|
||||
/// Class NotificationService. Contains various methods with options to open notifications.
|
||||
/// Class NotificationService. Contains various methods with options to open notifications.
|
||||
/// Should be added as scoped service in the application services and RadzenNotification should be added in application main layout.
|
||||
/// </summary>
|
||||
/// <example>
|
||||
@@ -50,6 +50,20 @@ namespace Radzen
|
||||
/// <param name="detail">The detail.</param>
|
||||
/// <param name="duration">The duration.</param>
|
||||
/// <param name="click">The click event.</param>
|
||||
public void Notify(NotificationSeverity severity, string summary,
|
||||
string detail, TimeSpan duration, Action<NotificationMessage> click = null)
|
||||
{
|
||||
Notify(severity, summary, detail, duration.TotalMilliseconds, click);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Notifies the specified severity.
|
||||
/// </summary>
|
||||
/// <param name="severity">The severity.</param>
|
||||
/// <param name="summary">The summary.</param>
|
||||
/// <param name="detail">The detail.</param>
|
||||
/// <param name="duration">The duration, default of 3 seconds.</param>
|
||||
/// <param name="click">The click event.</param>
|
||||
/// <param name="closeOnClick">If true, then the notification will be closed when clicked on.</param>
|
||||
/// <param name="payload">Used to store a custom payload that can be retreived later in the click event handler.</param>
|
||||
/// <param name="close">Action to be executed on close.</param>
|
||||
@@ -108,7 +122,7 @@ namespace Radzen
|
||||
/// Gets or sets the click event.
|
||||
/// </summary>
|
||||
/// <value>This event handler is called when the notification is clicked on.</value>
|
||||
public Action<NotificationMessage> Click { get; set; }
|
||||
public Action<NotificationMessage> Click { get; set; }
|
||||
/// <summary>
|
||||
/// Get or set the event for when the notification is closed
|
||||
/// </summary>
|
||||
@@ -124,6 +138,12 @@ namespace Radzen
|
||||
/// <value>Used to store a custom payload that can be retreived later in the click event handler.</value>
|
||||
public object Payload { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets if progress should be shown during duration.
|
||||
/// </summary>
|
||||
/// <value>If true, then the progress will be shown during duration.</value>
|
||||
public bool ShowProgress { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the detail content.
|
||||
/// </summary>
|
||||
@@ -146,12 +166,12 @@ namespace Radzen
|
||||
public bool Equals(NotificationMessage other)
|
||||
{
|
||||
if(other == null) return false;
|
||||
|
||||
|
||||
if(object.ReferenceEquals(this, other)) return true;
|
||||
|
||||
return this.Severity == other.Severity
|
||||
&& this.Summary == other.Summary
|
||||
&& this.Detail == other.Detail
|
||||
return this.Severity == other.Severity
|
||||
&& this.Summary == other.Summary
|
||||
&& this.Detail == other.Detail
|
||||
&& this.Duration == other.Duration
|
||||
&& this.Style == other.Style
|
||||
&& this.Click == other.Click
|
||||
|
||||
@@ -2,7 +2,6 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Specialized;
|
||||
using System.Linq;
|
||||
using System.Linq.Dynamic.Core;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Components;
|
||||
using Radzen.Blazor;
|
||||
@@ -354,18 +353,18 @@ namespace Radzen
|
||||
/// Called when [parameters set asynchronous].
|
||||
/// </summary>
|
||||
/// <returns>Task.</returns>
|
||||
protected override Task OnParametersSetAsync()
|
||||
protected override async Task OnParametersSetAsync()
|
||||
{
|
||||
if (Visible && !LoadData.HasDelegate)
|
||||
{
|
||||
InvokeAsync(Reload);
|
||||
await InvokeAsync(Reload);
|
||||
}
|
||||
else
|
||||
{
|
||||
CalculatePager();
|
||||
}
|
||||
|
||||
return base.OnParametersSetAsync();
|
||||
await base.OnParametersSetAsync();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,14 +1,16 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk.Razor">
|
||||
<PropertyGroup>
|
||||
<IncludeSymbols>true</IncludeSymbols>
|
||||
<SymbolPackageFormat>snupkg</SymbolPackageFormat>
|
||||
<NoWarn>BL9993;BL0007;BL0005</NoWarn>
|
||||
<TargetFrameworks>net6.0;net7.0;net8.0</TargetFrameworks>
|
||||
<TargetFrameworks>net6.0;net7.0;net8.0;net9.0</TargetFrameworks>
|
||||
<RazorLangVersion>7.0</RazorLangVersion>
|
||||
<LangVersion>latest</LangVersion>
|
||||
<OutputType>Library</OutputType>
|
||||
<IsPackable>true</IsPackable>
|
||||
<PackageId>Radzen.Blazor</PackageId>
|
||||
<Product>Radzen.Blazor</Product>
|
||||
<Version>5.2.1</Version>
|
||||
<Version>6.2.1</Version>
|
||||
<Copyright>Radzen Ltd.</Copyright>
|
||||
<Authors>Radzen Ltd.</Authors>
|
||||
<Description>Radzen Blazor is a set of 90+ free native Blazor UI controls packed with DataGrid, Scheduler, Charts and robust theming including Material design and Fluent UI.</Description>
|
||||
@@ -22,14 +24,16 @@
|
||||
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="DartSassBuilder" Version="1.0.0" />
|
||||
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="4.8.0" />
|
||||
<PackageReference Include="DartSassBuilder" Version="1.1.0" PrivateAssets="All" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Components" Condition="'$(TargetFramework)' == 'net6.0'" Version="6.0.25" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Components.Web" Condition="'$(TargetFramework)' == 'net6.0'" Version="6.0.0" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Components" Condition="'$(TargetFramework)' == 'net7.0'" Version="7.0.14" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Components.Web" Condition="'$(TargetFramework)' == 'net7.0'" Version="7.0.0" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Components" Condition="'$(TargetFramework)' == 'net8.0'" Version="8.0.0" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Components.Web" Condition="'$(TargetFramework)' == 'net8.0'" Version="8.0.0" />
|
||||
<PackageReference Include="System.Linq.Dynamic.Core" Version="1.3.7" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Components" Condition="'$(TargetFramework)' == 'net9.0'" Version="9.*-*" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Components.Web" Condition="'$(TargetFramework)' == 'net9.0'" Version="9.*-*" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
@@ -50,10 +54,10 @@
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Sass Include="$(MSBuildProjectDirectory)/themes/*.scss" Exclude="$(MSBuildProjectDirectory)/themes/_*.scss" Condition="'$(TargetFramework)' == 'net6.0'" />
|
||||
<Sass Include="$(MSBuildProjectDirectory)/themes/*.scss" Exclude="$(MSBuildProjectDirectory)/themes/_*.scss" Condition="'$(TargetFramework)' == 'net8.0'" />
|
||||
</ItemGroup>
|
||||
|
||||
<Target Name="Sass" BeforeTargets="BeforeBuild" Condition="'$(TargetFramework)' == 'net6.0'">
|
||||
<Target Name="Sass" BeforeTargets="BeforeBuild" Condition="'$(TargetFramework)' == 'net8.0'">
|
||||
<PropertyGroup>
|
||||
<_SassFileList>@(Sass->'"%(FullPath)"', ' ')</_SassFileList>
|
||||
<DartSassBuilderArgs>files $(_SassFileList) --outputstyle $(DartSassOutputStyle) --level $(DartSassOutputLevel)</DartSassBuilderArgs>
|
||||
@@ -62,7 +66,7 @@
|
||||
<Message Text="Converted SassFile list to argument" Importance="$(DartSassMessageLevel)" />
|
||||
</Target>
|
||||
|
||||
<Target Name="MoveCss" AfterTargets="AfterCompile" Condition="'$(TargetFramework)' == 'net6.0'">
|
||||
<Target Name="MoveCss" AfterTargets="AfterCompile" Condition="'$(TargetFramework)' == 'net8.0'">
|
||||
<ItemGroup>
|
||||
<CssFile Include="$(MSBuildProjectDirectory)/themes/*.css" />
|
||||
</ItemGroup>
|
||||
|
||||
@@ -24,15 +24,15 @@
|
||||
id="@($"rz-accordiontab-{items.IndexOf(item)}")" aria-controls="@($"rz-accordiontab-{items.IndexOf(item)}-content")" aria-expanded="true">
|
||||
@if (IsSelected(i, item))
|
||||
{
|
||||
<span class="rz-accordion-toggle-icon rzi rzi-chevron-down"></span>
|
||||
<span class="notranslate rz-accordion-toggle-icon rzi rzi-chevron-down"></span>
|
||||
}
|
||||
else
|
||||
{
|
||||
<span class="rz-accordion-toggle-icon rzi rzi-chevron-right"></span>
|
||||
<span class="notranslate rz-accordion-toggle-icon rzi rzi-chevron-right"></span>
|
||||
}
|
||||
@if (!string.IsNullOrEmpty(item.Icon))
|
||||
{
|
||||
<i class="rzi" style="@(!string.IsNullOrEmpty(item.IconColor) ? $"color:{item.IconColor}" : null)">@((MarkupString)item.Icon)</i>
|
||||
<i class="notranslate rzi" style="@(!string.IsNullOrEmpty(item.IconColor) ? $"color:{item.IconColor}" : null)">@((MarkupString)item.Icon)</i>
|
||||
}
|
||||
@if (item.Template != null)
|
||||
{
|
||||
|
||||
@@ -113,7 +113,7 @@ namespace Radzen.Blazor
|
||||
/// <summary>
|
||||
/// Refreshes this instance.
|
||||
/// </summary>
|
||||
internal void Refresh()
|
||||
public void Refresh()
|
||||
{
|
||||
StateHasChanged();
|
||||
}
|
||||
@@ -163,6 +163,8 @@ namespace Radzen.Blazor
|
||||
|
||||
internal async System.Threading.Tasks.Task SelectItem(RadzenAccordionItem item, bool? value = null)
|
||||
{
|
||||
if(item.Disabled) return;
|
||||
|
||||
await CollapseAll(item);
|
||||
|
||||
var itemIndex = items.IndexOf(item);
|
||||
@@ -178,7 +180,7 @@ namespace Radzen.Blazor
|
||||
await Expand.InvokeAsync(itemIndex);
|
||||
}
|
||||
|
||||
item.SetSelected(value ?? !selected);
|
||||
await item.SetSelected(value ?? !selected);
|
||||
|
||||
if (!Multiple)
|
||||
{
|
||||
@@ -196,7 +198,7 @@ namespace Radzen.Blazor
|
||||
{
|
||||
if (i.GetSelected())
|
||||
{
|
||||
i.SetSelected(false);
|
||||
await i.SetSelected(false);
|
||||
await Collapse.InvokeAsync(items.IndexOf(i));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,7 +34,31 @@ namespace Radzen.Blazor
|
||||
/// </summary>
|
||||
/// <value><c>true</c> if selected; otherwise, <c>false</c>.</value>
|
||||
[Parameter]
|
||||
public bool Selected { get; set; }
|
||||
public bool Selected
|
||||
{
|
||||
get
|
||||
{
|
||||
return selected != null ? selected.Value : false;
|
||||
}
|
||||
set
|
||||
{
|
||||
selected = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the value changed.
|
||||
/// </summary>
|
||||
/// <value>The value changed.</value>
|
||||
[Parameter]
|
||||
public EventCallback<bool> SelectedChanged { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether this <see cref="RadzenAccordionItem"/> is disabled.
|
||||
/// </summary>
|
||||
/// <value><c>true</c> if disabled; otherwise, <c>false</c>.</value>
|
||||
[Parameter]
|
||||
public bool Disabled { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the title attribute of the expand button.
|
||||
@@ -132,9 +156,11 @@ namespace Radzen.Blazor
|
||||
return selected ?? Selected;
|
||||
}
|
||||
|
||||
internal void SetSelected(bool? value)
|
||||
internal async Task SetSelected(bool? value)
|
||||
{
|
||||
selected = value;
|
||||
|
||||
await SelectedChanged.InvokeAsync(Selected);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -144,12 +170,19 @@ namespace Radzen.Blazor
|
||||
/// <returns>A Task representing the asynchronous operation.</returns>
|
||||
public override async Task SetParametersAsync(ParameterView parameters)
|
||||
{
|
||||
bool shouldRefresh = false;
|
||||
if (parameters.DidParameterChange(nameof(Selected), Selected))
|
||||
{
|
||||
Accordion?.SelectItem(this, parameters.GetValueOrDefault<bool>(nameof(Selected)));
|
||||
selected = parameters.GetValueOrDefault<bool>(nameof(Selected));
|
||||
shouldRefresh = true;
|
||||
}
|
||||
|
||||
await base.SetParametersAsync(parameters);
|
||||
|
||||
if (shouldRefresh)
|
||||
{
|
||||
Accordion.Refresh();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
}
|
||||
<div id="@PopupID" class="rz-autocomplete-panel" style="@PopupStyle">
|
||||
<ul @ref="@list" class="rz-autocomplete-items rz-autocomplete-list" role="listbox">
|
||||
@if (!string.IsNullOrEmpty(searchText) || !string.IsNullOrEmpty(customSearchText))
|
||||
@if (OpenOnFocus || (!string.IsNullOrEmpty(searchText) || !string.IsNullOrEmpty(customSearchText)))
|
||||
{
|
||||
@foreach (var item in LoadData.HasDelegate ? Data != null ? Data : Enumerable.Empty<object>() : (View != null ? View : Enumerable.Empty<object>()))
|
||||
{
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
using Radzen;
|
||||
using Radzen.Blazor.Rendering;
|
||||
using System.Collections;
|
||||
using System.Linq.Dynamic.Core;
|
||||
using Microsoft.AspNetCore.Components.Forms;
|
||||
using Microsoft.JSInterop;
|
||||
using Microsoft.AspNetCore.Components;
|
||||
@@ -23,6 +22,35 @@ namespace Radzen.Blazor
|
||||
/// </example>
|
||||
public partial class RadzenAutoComplete : DataBoundFormComponent<string>
|
||||
{
|
||||
object selectedItem = null;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the selected item.
|
||||
/// </summary>
|
||||
/// <value>The selected item.</value>
|
||||
[Parameter]
|
||||
public object SelectedItem
|
||||
{
|
||||
get
|
||||
{
|
||||
return selectedItem;
|
||||
}
|
||||
set
|
||||
{
|
||||
if (selectedItem != value)
|
||||
{
|
||||
selectedItem = object.Equals(value, "null") ? null : value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the selected item changed.
|
||||
/// </summary>
|
||||
/// <value>The selected item changed.</value>
|
||||
[Parameter]
|
||||
public EventCallback<object> SelectedItemChanged { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Specifies additional custom attributes that will be rendered by the input.
|
||||
/// </summary>
|
||||
@@ -153,8 +181,8 @@ namespace Radzen.Blazor
|
||||
var value = await JSRuntime.InvokeAsync<string>("Radzen.getInputValue", search);
|
||||
|
||||
value = $"{value}";
|
||||
|
||||
if (value.Length < MinLength)
|
||||
|
||||
if (value.Length < MinLength && !OpenOnFocus)
|
||||
{
|
||||
await JSRuntime.InvokeVoidAsync("Radzen.closePopup", PopupID);
|
||||
return;
|
||||
@@ -195,7 +223,7 @@ namespace Radzen.Blazor
|
||||
{
|
||||
get
|
||||
{
|
||||
return Data != null && !string.IsNullOrEmpty(searchText) ? Data.AsQueryable() : null;
|
||||
return Data != null && (OpenOnFocus || !string.IsNullOrEmpty(searchText)) ? Data.AsQueryable() : null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -209,12 +237,7 @@ namespace Radzen.Blazor
|
||||
{
|
||||
if (Query != null)
|
||||
{
|
||||
string filterCaseSensitivityOperator = FilterCaseSensitivity == FilterCaseSensitivity.CaseInsensitive ? ".ToLower()" : "";
|
||||
|
||||
string textProperty = string.IsNullOrEmpty(TextProperty) ? string.Empty : $".{TextProperty}";
|
||||
|
||||
return Query.Where(DynamicLinqCustomTypeProvider.ParsingConfig, $"o=>o{textProperty}{filterCaseSensitivityOperator}.{Enum.GetName(typeof(StringFilterOperator), FilterOperator)}(@0)",
|
||||
FilterCaseSensitivity == FilterCaseSensitivity.CaseInsensitive ? searchText.ToLower() : searchText);
|
||||
return Query.Where(TextProperty, searchText, FilterOperator, FilterCaseSensitivity);
|
||||
}
|
||||
|
||||
return null;
|
||||
@@ -232,6 +255,8 @@ namespace Radzen.Blazor
|
||||
await ValueChanged.InvokeAsync($"{Value}");
|
||||
if (FieldIdentifier.FieldName != null) { EditContext?.NotifyFieldChanged(FieldIdentifier); }
|
||||
await Change.InvokeAsync(Value);
|
||||
|
||||
await SelectedItemChanged.InvokeAsync(null);
|
||||
}
|
||||
|
||||
async System.Threading.Tasks.Task SelectItem(object item)
|
||||
@@ -249,6 +274,8 @@ namespace Radzen.Blazor
|
||||
if (FieldIdentifier.FieldName != null) { EditContext?.NotifyFieldChanged(FieldIdentifier); }
|
||||
await Change.InvokeAsync(Value);
|
||||
|
||||
await SelectedItemChanged.InvokeAsync(item);
|
||||
|
||||
StateHasChanged();
|
||||
}
|
||||
|
||||
@@ -307,8 +334,22 @@ namespace Radzen.Blazor
|
||||
shouldClose = !visible;
|
||||
}
|
||||
|
||||
if (parameters.DidParameterChange(nameof(SelectedItem), SelectedItem))
|
||||
{
|
||||
var item = parameters.GetValueOrDefault<object>(nameof(SelectedItem));
|
||||
if (item != null)
|
||||
{
|
||||
await SelectItem(item);
|
||||
}
|
||||
}
|
||||
|
||||
await base.SetParametersAsync(parameters);
|
||||
|
||||
if (parameters.DidParameterChange(nameof(Value), Value))
|
||||
{
|
||||
Value = parameters.GetValueOrDefault<object>(nameof(Value));
|
||||
}
|
||||
|
||||
if (shouldClose && !firstRender)
|
||||
{
|
||||
await JSRuntime.InvokeVoidAsync("Radzen.destroyPopup", PopupID);
|
||||
|
||||
@@ -4,6 +4,8 @@ using Radzen.Blazor.Rendering;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Components.Routing;
|
||||
using Microsoft.JSInterop;
|
||||
using System.Threading;
|
||||
using System.Runtime.ExceptionServices;
|
||||
|
||||
namespace Radzen.Blazor
|
||||
{
|
||||
@@ -26,7 +28,7 @@ namespace Radzen.Blazor
|
||||
{
|
||||
var classList = ClassList.Create("rz-body")
|
||||
.Add("rz-body-expanded", Expanded);
|
||||
|
||||
|
||||
return classList.ToString();
|
||||
}
|
||||
|
||||
@@ -110,7 +112,7 @@ namespace Radzen.Blazor
|
||||
{
|
||||
if (IsJSRuntimeAvailable && Layout != null)
|
||||
{
|
||||
JSRuntime.InvokeVoidAsync("eval", $"document.getElementById('{GetId()}').scrollTop = 0");
|
||||
JSRuntime.InvokeVoidAsync("eval", $"try{{document.getElementById('{GetId()}').scrollTop = 0}}catch(e){{}}");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -25,11 +25,11 @@
|
||||
{
|
||||
@if (!string.IsNullOrEmpty(@Icon))
|
||||
{
|
||||
<i class="rz-button-icon-left rzi" style="@(!string.IsNullOrEmpty(IconColor) ? $"color:{IconColor}" : null)">@((MarkupString)Icon)</i>
|
||||
<i class="notranslate rz-button-icon-left rzi" style="@(!string.IsNullOrEmpty(IconColor) ? $"color:{IconColor}" : null)">@((MarkupString)Icon)</i>
|
||||
}
|
||||
@if (!string.IsNullOrEmpty(Image))
|
||||
{
|
||||
<img class="rz-button-icon-left rzi" src="@Image" alt="@ImageAlternateText" />
|
||||
<img class="notranslate rz-button-icon-left rzi" src="@Image" alt="@ImageAlternateText" />
|
||||
}
|
||||
@if (!string.IsNullOrEmpty(Text))
|
||||
{
|
||||
|
||||
6
Radzen.Blazor/RadzenCardGroup.razor
Normal file
6
Radzen.Blazor/RadzenCardGroup.razor
Normal file
@@ -0,0 +1,6 @@
|
||||
@inherits RadzenComponentWithChildren
|
||||
|
||||
@if (Visible)
|
||||
{
|
||||
<div @ref="@Element" @attributes="Attributes" class="@GetCssClass()" style="@Style" id="@GetId()">@ChildContent</div>
|
||||
}
|
||||
35
Radzen.Blazor/RadzenCardGroup.razor.cs
Normal file
35
Radzen.Blazor/RadzenCardGroup.razor.cs
Normal file
@@ -0,0 +1,35 @@
|
||||
using Microsoft.AspNetCore.Components;
|
||||
using Microsoft.AspNetCore.Components.Web;
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Radzen.Blazor
|
||||
{
|
||||
/// <summary>
|
||||
/// RadzenCardGroup component.
|
||||
/// </summary>
|
||||
public partial class RadzenCardGroup : RadzenComponentWithChildren
|
||||
{
|
||||
/// <summary>
|
||||
/// Toggles the responsive mode of the component. If set to <c>true</c> (the default) the component will be
|
||||
/// expanded on larger displays and collapsed on touch devices. Set to <c>false</c> if you want to disable this behavior.
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
public bool Responsive { get; set; } = true;
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override string GetComponentCssClass()
|
||||
{
|
||||
var classList = new List<string>();
|
||||
classList.Add("rz-card-group");
|
||||
|
||||
if (Responsive)
|
||||
{
|
||||
classList.Add("rz-card-group-responsive");
|
||||
}
|
||||
|
||||
return string.Join(" ", classList);
|
||||
}
|
||||
}
|
||||
}
|
||||
43
Radzen.Blazor/RadzenCarousel.razor
Normal file
43
Radzen.Blazor/RadzenCarousel.razor
Normal file
@@ -0,0 +1,43 @@
|
||||
@inherits RadzenComponent
|
||||
@using System.Linq
|
||||
@using Microsoft.JSInterop
|
||||
<CascadingValue Value=this>
|
||||
@if (Visible)
|
||||
{
|
||||
<section @ref=@Element style=@Style @attributes=@Attributes class=@GetCssClass() id=@GetId() tabindex="0">
|
||||
@if(AllowPaging && (PagerPosition == PagerPosition.Top || PagerPosition == PagerPosition.TopAndBottom))
|
||||
{
|
||||
<RadzenStack class="rz-carousel-pager rz-carousel-pager-top" Orientation="Orientation.Horizontal" AlignItems="AlignItems.Center" JustifyContent="JustifyContent.Center" Wrap="FlexWrap.Wrap">
|
||||
@foreach (var item in items)
|
||||
{
|
||||
var index = items.IndexOf(item);
|
||||
<a @onclick="@(args => Navigate(index))" class="rz-carousel-pager-button @(index == selectedIndex ? "rz-state-active" : "")"></a>
|
||||
}
|
||||
</RadzenStack>
|
||||
}
|
||||
@if(AllowNavigation)
|
||||
{
|
||||
<RadzenButton class="rz-carousel-prev" Icon="@PrevIcon" Text="@PrevText" ButtonStyle="@ButtonStyle" Size="@ButtonSize" Variant="@ButtonVariant" Shade="@ButtonShade"
|
||||
Click=@Prev />
|
||||
<RadzenButton class="rz-carousel-next" Icon="@NextIcon" Text="@NextText" ButtonStyle="@ButtonStyle" Size="@ButtonSize" Variant="@ButtonVariant" Shade="@ButtonShade"
|
||||
Click=@Next/>
|
||||
}
|
||||
<ul class="rz-carousel-items"
|
||||
@ontouchstart="OnTouchStart"
|
||||
@ontouchend="OnTouchEnd"
|
||||
@ontouchcancel="OnTouchCancel">
|
||||
@Items
|
||||
</ul>
|
||||
@if(AllowPaging && (PagerPosition == PagerPosition.Bottom || PagerPosition == PagerPosition.TopAndBottom))
|
||||
{
|
||||
<RadzenStack class="rz-carousel-pager rz-carousel-pager-bottom" Orientation="Orientation.Horizontal" AlignItems="AlignItems.Center" JustifyContent="JustifyContent.Center" Wrap="FlexWrap.Wrap">
|
||||
@foreach (var item in items)
|
||||
{
|
||||
var index = items.IndexOf(item);
|
||||
<a @onclick="@(args => Navigate(index))" class="rz-carousel-pager-button @(index == selectedIndex ? "rz-state-active" : "")"></a>
|
||||
}
|
||||
</RadzenStack>
|
||||
}
|
||||
</section>
|
||||
}
|
||||
</CascadingValue>
|
||||
367
Radzen.Blazor/RadzenCarousel.razor.cs
Normal file
367
Radzen.Blazor/RadzenCarousel.razor.cs
Normal file
@@ -0,0 +1,367 @@
|
||||
using Microsoft.AspNetCore.Components;
|
||||
using Microsoft.AspNetCore.Components.Web;
|
||||
using Microsoft.JSInterop;
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using System.Timers;
|
||||
|
||||
namespace Radzen.Blazor
|
||||
{
|
||||
/// <summary>
|
||||
/// RadzenCarousel component.
|
||||
/// </summary>
|
||||
/// <example>
|
||||
/// <code>
|
||||
/// <RadzenCarousel Change=@(args => Console.WriteLine($"Selected index is: {args}"))>
|
||||
/// <Items>
|
||||
/// <RadzenCarouselItem>
|
||||
/// Details for Orders
|
||||
/// </RadzenCarouselItem>
|
||||
/// <RadzenCarousel>
|
||||
/// Details for Employees
|
||||
/// </RadzenCarouselItem>
|
||||
/// </Items>
|
||||
/// </RadzenCarousel>
|
||||
/// </code>
|
||||
/// </example>
|
||||
public partial class RadzenCarousel : RadzenComponent
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the items.
|
||||
/// </summary>
|
||||
/// <value>The items.</value>
|
||||
[Parameter]
|
||||
public RenderFragment Items { get; set; }
|
||||
|
||||
internal List<RadzenCarouselItem> items = new List<RadzenCarouselItem>();
|
||||
|
||||
/// <summary>
|
||||
/// Adds the item.
|
||||
/// </summary>
|
||||
/// <param name="item">The item.</param>
|
||||
public void AddItem(RadzenCarouselItem item)
|
||||
{
|
||||
if (!items.Contains(item))
|
||||
{
|
||||
items.Add(item);
|
||||
|
||||
StateHasChanged();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes the item.
|
||||
/// </summary>
|
||||
/// <param name="item">The item.</param>
|
||||
public void RemoveItem(RadzenCarouselItem item)
|
||||
{
|
||||
if (items.Contains(item))
|
||||
{
|
||||
items.Remove(item);
|
||||
|
||||
if (!disposed)
|
||||
{
|
||||
try { InvokeAsync(StateHasChanged); } catch { }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override string GetComponentCssClass()
|
||||
{
|
||||
return $"rz-carousel {(AllowNavigation ? "" : "rz-carousel-no-navigation")} {(PagerOverlay ? "rz-carousel-pager-overlay" : "")}".Trim();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Navigates to specific index.
|
||||
/// </summary>
|
||||
public async Task Navigate(int index)
|
||||
{
|
||||
if (Auto)
|
||||
{
|
||||
await Reset();
|
||||
}
|
||||
|
||||
await GoTo(index);
|
||||
}
|
||||
|
||||
async Task Prev()
|
||||
{
|
||||
await Navigate(selectedIndex == 0 ? items.Count - 1 : selectedIndex - 1);
|
||||
}
|
||||
|
||||
async Task Next()
|
||||
{
|
||||
await Navigate(selectedIndex == items.Count - 1 ? 0 : selectedIndex + 1);
|
||||
}
|
||||
|
||||
async Task GoTo(int index)
|
||||
{
|
||||
if (index >= 0 && index <= items.Count - 1 && selectedIndex != index)
|
||||
{
|
||||
selectedIndex = index;
|
||||
await SelectedIndexChanged.InvokeAsync(selectedIndex);
|
||||
await Change.InvokeAsync(selectedIndex);
|
||||
await JSRuntime.InvokeVoidAsync("Radzen.scrollCarouselItem", items[selectedIndex].element);
|
||||
StateHasChanged();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Stops the auto-cycle timer.
|
||||
/// </summary>
|
||||
public void Stop()
|
||||
{
|
||||
timer?.Change(Timeout.Infinite, Timeout.Infinite);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Starts the auto-cycle timer.
|
||||
/// </summary>
|
||||
public void Start()
|
||||
{
|
||||
timer?.Change(TimeSpan.FromMilliseconds(Interval), TimeSpan.FromMilliseconds(Interval));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Resets the auto-cycle timer.
|
||||
/// </summary>
|
||||
public async Task Reset()
|
||||
{
|
||||
Stop();
|
||||
Start();
|
||||
|
||||
await Task.CompletedTask;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the selected index.
|
||||
/// </summary>
|
||||
/// <value>The selected index.</value>
|
||||
[Parameter]
|
||||
public int SelectedIndex { get; set; }
|
||||
|
||||
private int selectedIndex;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the selected index changed callback.
|
||||
/// </summary>
|
||||
/// <value>The selected index changed callback.</value>
|
||||
[Parameter]
|
||||
public EventCallback<int> SelectedIndexChanged { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the change callback.
|
||||
/// </summary>
|
||||
/// <value>The change callback.</value>
|
||||
[Parameter]
|
||||
public EventCallback<int> Change { get; set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public override async Task SetParametersAsync(ParameterView parameters)
|
||||
{
|
||||
var shouldUpdate = false;
|
||||
if (parameters.DidParameterChange(nameof(SelectedIndex), SelectedIndex))
|
||||
{
|
||||
selectedIndex = parameters.GetValueOrDefault<int>(nameof(SelectedIndex));
|
||||
shouldUpdate = true;
|
||||
}
|
||||
|
||||
if (parameters.DidParameterChange(nameof(Auto), Auto) ||
|
||||
parameters.DidParameterChange(nameof(Interval), Interval))
|
||||
{
|
||||
if (parameters.GetValueOrDefault<bool>(nameof(Auto)))
|
||||
{
|
||||
await Reset();
|
||||
}
|
||||
else
|
||||
{
|
||||
Stop();
|
||||
}
|
||||
}
|
||||
|
||||
await base.SetParametersAsync(parameters);
|
||||
|
||||
if (shouldUpdate)
|
||||
{
|
||||
await JSRuntime.InvokeVoidAsync("Radzen.scrollCarouselItem", items[selectedIndex].element);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether this <see cref="RadzenCarousel"/> cycle is automatic.
|
||||
/// </summary>
|
||||
/// <value><c>true</c> if cycle automatic; otherwise, <c>false</c>.</value>
|
||||
[Parameter]
|
||||
public bool Auto { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the auto-cycle interval in milliseconds.
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
public double Interval { get; set; } = 4000;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the pager position. Set to <c>PagerPosition.Bottom</c> by default.
|
||||
/// </summary>
|
||||
/// <value>The pager position.</value>
|
||||
[Parameter]
|
||||
public PagerPosition PagerPosition { get; set; } = PagerPosition.Bottom;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether pager overlays the carousel items. Set to <c>true</c> by default.
|
||||
/// </summary>
|
||||
/// <value><c>true</c> if pager overlay is allowed; otherwise, <c>false</c>.</value>
|
||||
[Parameter]
|
||||
public bool PagerOverlay { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether paging is allowed. Set to <c>true</c> by default.
|
||||
/// </summary>
|
||||
/// <value><c>true</c> if paging is allowed; otherwise, <c>false</c>.</value>
|
||||
[Parameter]
|
||||
public bool AllowPaging { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether previous/next navigation is allowed. Set to <c>true</c> by default.
|
||||
/// </summary>
|
||||
/// <value><c>true</c> if previous/next navigation is allowed; otherwise, <c>false</c>.</value>
|
||||
[Parameter]
|
||||
public bool AllowNavigation { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the buttons style
|
||||
/// </summary>
|
||||
/// <value>The buttons style.</value>
|
||||
[Parameter]
|
||||
public ButtonStyle ButtonStyle { get; set; } = ButtonStyle.Base;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the design variant of the buttons.
|
||||
/// </summary>
|
||||
/// <value>The variant of the buttons.</value>
|
||||
[Parameter]
|
||||
public Variant ButtonVariant { get; set; } = Variant.Text;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the color shade of the buttons.
|
||||
/// </summary>
|
||||
/// <value>The color shade of the buttons.</value>
|
||||
[Parameter]
|
||||
public Shade ButtonShade { get; set; } = Shade.Lighter;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the buttons size.
|
||||
/// </summary>
|
||||
/// <value>The buttons size.</value>
|
||||
[Parameter]
|
||||
public ButtonSize ButtonSize { get; set; } = ButtonSize.Large;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the next button text.
|
||||
/// </summary>
|
||||
/// <value>The next button text.</value>
|
||||
[Parameter]
|
||||
public string NextText { get; set; } = "";
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the previous button text.
|
||||
/// </summary>
|
||||
/// <value>The previous button text.</value>
|
||||
[Parameter]
|
||||
public string PrevText { get; set; } = "";
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the next button icon.
|
||||
/// </summary>
|
||||
/// <value>The next button icon.</value>
|
||||
[Parameter]
|
||||
public string NextIcon { get; set; } = "arrow_forward_ios";
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the previous button icon.
|
||||
/// </summary>
|
||||
/// <value>The previous button icon.</value>
|
||||
[Parameter]
|
||||
public string PrevIcon { get; set; } = "arrow_back_ios_new";
|
||||
|
||||
System.Threading.Timer timer;
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override async Task OnAfterRenderAsync(bool firstRender)
|
||||
{
|
||||
await base.OnAfterRenderAsync(firstRender);
|
||||
|
||||
if (firstRender)
|
||||
{
|
||||
var ts = TimeSpan.FromMilliseconds(Interval);
|
||||
timer = new System.Threading.Timer(state => InvokeAsync(Next),
|
||||
null, Auto ? ts : Timeout.InfiniteTimeSpan, ts);
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void Dispose()
|
||||
{
|
||||
base.Dispose();
|
||||
|
||||
if (timer != null)
|
||||
{
|
||||
timer.Dispose();
|
||||
timer = null;
|
||||
}
|
||||
}
|
||||
|
||||
double? x;
|
||||
double? y;
|
||||
|
||||
void OnTouchStart(TouchEventArgs args)
|
||||
{
|
||||
x = args.Touches[0].ClientX;
|
||||
y = args.Touches[0].ClientY;
|
||||
}
|
||||
|
||||
async Task OnTouchEnd(TouchEventArgs args)
|
||||
{
|
||||
if (x == null || y == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var xDiff = x.Value - args.ChangedTouches[0].ClientX;
|
||||
var yDiff = y.Value - args.ChangedTouches[0].ClientY;
|
||||
|
||||
if (Math.Abs(xDiff) < 100 && Math.Abs(yDiff) < 100)
|
||||
{
|
||||
x = null;
|
||||
y = null;
|
||||
return;
|
||||
}
|
||||
|
||||
if (Math.Abs(xDiff) > Math.Abs(yDiff))
|
||||
{
|
||||
if (xDiff > 0)
|
||||
{
|
||||
await Next();
|
||||
}
|
||||
else
|
||||
{
|
||||
await Prev();
|
||||
}
|
||||
}
|
||||
|
||||
x = null;
|
||||
y = null;
|
||||
}
|
||||
|
||||
void OnTouchCancel(TouchEventArgs args)
|
||||
{
|
||||
x = null;
|
||||
y = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
8
Radzen.Blazor/RadzenCarouselItem.razor
Normal file
8
Radzen.Blazor/RadzenCarouselItem.razor
Normal file
@@ -0,0 +1,8 @@
|
||||
@using Microsoft.JSInterop
|
||||
@implements IDisposable
|
||||
@inject IJSRuntime JSRuntime
|
||||
|
||||
<li @ref="element" @attributes=@Attributes class=@ClassList tabindex="0">
|
||||
@ChildContent
|
||||
<div class="rz-carousel-snapper"></div>
|
||||
</li>
|
||||
63
Radzen.Blazor/RadzenCarouselItem.razor.cs
Normal file
63
Radzen.Blazor/RadzenCarouselItem.razor.cs
Normal file
@@ -0,0 +1,63 @@
|
||||
using Microsoft.AspNetCore.Components;
|
||||
using Microsoft.JSInterop;
|
||||
using Radzen.Blazor.Rendering;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Radzen.Blazor
|
||||
{
|
||||
/// <summary>
|
||||
/// RadzenCarouselItem component.
|
||||
/// </summary>
|
||||
public partial class RadzenCarouselItem : IDisposable
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the class list.
|
||||
/// </summary>
|
||||
/// <value>The class list.</value>
|
||||
ClassList ClassList => ClassList.Create()
|
||||
.Add("rz-carousel-item")
|
||||
.Add(Attributes);
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the arbitrary attributes.
|
||||
/// </summary>
|
||||
/// <value>The arbitrary attributes.</value>
|
||||
[Parameter(CaptureUnmatchedValues = true)]
|
||||
public IDictionary<string, object> Attributes { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the child content.
|
||||
/// </summary>
|
||||
/// <value>The child content.</value>
|
||||
[Parameter]
|
||||
public RenderFragment ChildContent { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the tabs.
|
||||
/// </summary>
|
||||
/// <value>The tabs.</value>
|
||||
[CascadingParameter]
|
||||
public RadzenCarousel Carousel { get; set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
await base.OnInitializedAsync();
|
||||
|
||||
Carousel.AddItem(this);
|
||||
|
||||
itemIndex = Carousel.items.IndexOf(this);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void Dispose()
|
||||
{
|
||||
Carousel?.RemoveItem(this);
|
||||
}
|
||||
|
||||
int itemIndex;
|
||||
internal ElementReference element;
|
||||
}
|
||||
}
|
||||
@@ -13,7 +13,7 @@
|
||||
{
|
||||
<CascadingValue Value="@this">
|
||||
<Legend />
|
||||
<svg style="width: 100%; height: 100%">
|
||||
<svg style="width: 100%; height: 100%; overflow: visible;">
|
||||
<g transform="@($"translate({MarginLeft.ToInvariantString()}, {MarginTop.ToInvariantString()})")">
|
||||
<ClipPath />
|
||||
@if(ShouldRenderAxes())
|
||||
@@ -38,13 +38,7 @@
|
||||
@donut.RenderTitle(MarginLeft, MarginTop)
|
||||
}
|
||||
}
|
||||
<ChartTooltipContainer @ref="@chartTooltipContainer">
|
||||
@if (tooltip != null)
|
||||
{
|
||||
@tooltip
|
||||
}
|
||||
</ChartTooltipContainer>
|
||||
|
||||
|
||||
</CascadingValue>
|
||||
}
|
||||
</div>
|
||||
|
||||
@@ -52,6 +52,9 @@ namespace Radzen.Blazor
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
public EventCallback<LegendClickEventArgs> LegendClick { get; set; }
|
||||
|
||||
[Inject]
|
||||
TooltipService TooltipService { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the runtime width of the chart.
|
||||
@@ -276,7 +279,6 @@ namespace Radzen.Blazor
|
||||
}
|
||||
}
|
||||
|
||||
ChartTooltipContainer chartTooltipContainer;
|
||||
RenderFragment tooltip;
|
||||
object tooltipData;
|
||||
double mouseX;
|
||||
@@ -367,11 +369,15 @@ namespace Radzen.Blazor
|
||||
{
|
||||
foreach (var overlay in series.Overlays.Reverse())
|
||||
{
|
||||
if (overlay.Visible && overlay.Contains(mouseX - MarginLeft, mouseY - MarginTop, TooltipTolerance))
|
||||
if (overlay.Visible && overlay.Contains(queryX, queryY, TooltipTolerance))
|
||||
{
|
||||
tooltipData = null;
|
||||
tooltip = overlay.RenderTooltip(mouseX, mouseY, MarginLeft, MarginTop);
|
||||
chartTooltipContainer.Refresh();
|
||||
tooltip = overlay.RenderTooltip(queryX, queryY);
|
||||
var tooltipPosition = overlay.GetTooltipPosition(queryX, queryY);
|
||||
TooltipService.OpenChartTooltip(Element, tooltipPosition.X + MarginLeft, tooltipPosition.Y + MarginTop, _ => tooltip, new ChartTooltipOptions
|
||||
{
|
||||
ColorScheme = ColorScheme
|
||||
});
|
||||
await Task.Yield();
|
||||
|
||||
return;
|
||||
@@ -399,21 +405,25 @@ namespace Radzen.Blazor
|
||||
if (closestSeriesData != tooltipData)
|
||||
{
|
||||
tooltipData = closestSeriesData;
|
||||
tooltip = closestSeries.RenderTooltip(closestSeriesData, MarginLeft, MarginTop, Height ?? 0);
|
||||
chartTooltipContainer.Refresh();
|
||||
tooltip = closestSeries.RenderTooltip(closestSeriesData);
|
||||
var tooltipPosition = closestSeries.GetTooltipPosition(closestSeriesData);
|
||||
TooltipService.OpenChartTooltip(Element, tooltipPosition.X + MarginLeft, tooltipPosition.Y + MarginTop, _ => tooltip, new ChartTooltipOptions
|
||||
{
|
||||
ColorScheme = ColorScheme
|
||||
});
|
||||
await Task.Yield();
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (tooltip != null)
|
||||
{
|
||||
tooltipData = null;
|
||||
tooltip = null;
|
||||
if (tooltip != null)
|
||||
{
|
||||
tooltipData = null;
|
||||
tooltip = null;
|
||||
|
||||
chartTooltipContainer.Refresh();
|
||||
await Task.Yield();
|
||||
}
|
||||
TooltipService.Close();
|
||||
await Task.Yield();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
184
Radzen.Blazor/RadzenChartTooltip.razor
Normal file
184
Radzen.Blazor/RadzenChartTooltip.razor
Normal file
@@ -0,0 +1,184 @@
|
||||
@implements IAsyncDisposable
|
||||
@using Microsoft.JSInterop
|
||||
@inject IJSRuntime JSRuntime
|
||||
|
||||
@foreach (var tooltip in tooltips)
|
||||
{
|
||||
<div id="@UniqueID"
|
||||
style="display: none; top: 0; left: 0; z-index: 1001; position: absolute;"
|
||||
class="@($"rz-scheme-{tooltip.Options.ColorScheme.ToString().ToLowerInvariant()}")">
|
||||
@tooltip.Options.ChildContent(Service)
|
||||
</div>
|
||||
}
|
||||
|
||||
@code {
|
||||
public string UniqueID { get; set; }
|
||||
|
||||
[Inject] private TooltipService Service { get; set; }
|
||||
|
||||
List<ChartTooltip> tooltips = new List<ChartTooltip>();
|
||||
|
||||
async Task Open(ElementReference chart, double x, double y, ChartTooltipOptions options)
|
||||
{
|
||||
tooltips.Clear();
|
||||
tooltips.Add(new ChartTooltip { Options = options, Chart = chart, X = x, Y = y });
|
||||
|
||||
await InvokeAsync(StateHasChanged);
|
||||
|
||||
var tooltip = tooltips.LastOrDefault();
|
||||
|
||||
if (tooltip != null)
|
||||
{
|
||||
await JSRuntime.InvokeVoidAsync("Radzen.openChartTooltip",
|
||||
tooltip.Chart,
|
||||
x,
|
||||
y,
|
||||
UniqueID);
|
||||
}
|
||||
}
|
||||
|
||||
bool IsJSRuntimeAvailable { get; set; }
|
||||
|
||||
protected override async Task OnAfterRenderAsync(bool firstRender)
|
||||
{
|
||||
IsJSRuntimeAvailable = true;
|
||||
|
||||
var tooltip = tooltips.LastOrDefault();
|
||||
|
||||
if (tooltip != null)
|
||||
{
|
||||
await JSRuntime.InvokeVoidAsync("Radzen.openChartTooltip",
|
||||
tooltip.Chart,
|
||||
tooltip.X,
|
||||
tooltip.Y,
|
||||
UniqueID,
|
||||
Reference,
|
||||
"RadzenChartTooltip.CloseTooltip");
|
||||
}
|
||||
}
|
||||
|
||||
private DotNetObjectReference<RadzenChartTooltip> reference;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the reference for the current component.
|
||||
/// </summary>
|
||||
/// <value>The reference.</value>
|
||||
protected DotNetObjectReference<RadzenChartTooltip> Reference
|
||||
{
|
||||
get
|
||||
{
|
||||
if (reference == null)
|
||||
{
|
||||
reference = DotNetObjectReference.Create(this);
|
||||
}
|
||||
|
||||
return reference;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Closes this instance.
|
||||
/// </summary>
|
||||
[JSInvokable("RadzenChartTooltip.CloseTooltip")]
|
||||
public void CloseTooltip()
|
||||
{
|
||||
Service.Close();
|
||||
}
|
||||
|
||||
public async Task Close()
|
||||
{
|
||||
var lastTooltip = tooltips.LastOrDefault();
|
||||
if (lastTooltip != null)
|
||||
{
|
||||
if (IsJSRuntimeAvailable)
|
||||
{
|
||||
try
|
||||
{
|
||||
tooltips.Remove(lastTooltip);
|
||||
await JSRuntime.InvokeVoidAsync("Radzen.closeTooltip", UniqueID);
|
||||
}
|
||||
catch
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
await InvokeAsync(StateHasChanged);
|
||||
}
|
||||
|
||||
public async ValueTask DisposeAsync()
|
||||
{
|
||||
while (tooltips.Count != 0)
|
||||
{
|
||||
await Close();
|
||||
}
|
||||
reference?.Dispose();
|
||||
reference = null;
|
||||
|
||||
if (IsJSRuntimeAvailable)
|
||||
{
|
||||
try
|
||||
{
|
||||
await JSRuntime.InvokeVoidAsync("Radzen.destroyPopup", UniqueID);
|
||||
}
|
||||
catch
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
}
|
||||
|
||||
Service.OnOpenChartTooltip -= OnOpen;
|
||||
Service.OnClose -= OnClose;
|
||||
Service.OnNavigate -= OnNavigate;
|
||||
}
|
||||
|
||||
protected override void OnInitialized()
|
||||
{
|
||||
UniqueID = Convert.ToBase64String(Guid.NewGuid().ToByteArray()).Replace("/", "-").Replace("+", "-").Substring(0, 10);
|
||||
|
||||
Service.OnOpenChartTooltip += OnOpen;
|
||||
Service.OnClose += OnClose;
|
||||
Service.OnNavigate += OnNavigate;
|
||||
}
|
||||
|
||||
void OnOpen(ElementReference element, double x, double y, ChartTooltipOptions options)
|
||||
{
|
||||
Open(element, x, y, options).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
void OnClose()
|
||||
{
|
||||
Close().ConfigureAwait(false);
|
||||
}
|
||||
|
||||
void OnNavigate()
|
||||
{
|
||||
JSRuntime.InvokeVoidAsync("Radzen.closePopup", UniqueID);
|
||||
}
|
||||
|
||||
private sealed class ChartTooltip
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the owning chart.
|
||||
/// </summary>
|
||||
/// <value>The chart.</value>
|
||||
public ElementReference Chart { get; set; }
|
||||
/// <summary>
|
||||
/// Gets or sets the horizontal position of the tooltip.
|
||||
/// </summary>
|
||||
/// <value>The position.</value>
|
||||
public double X { get; set; }
|
||||
/// <summary>
|
||||
/// Gets or sets the vertical position of the tooltip.
|
||||
/// </summary>
|
||||
/// <value>The position.</value>
|
||||
public double Y { get; set; }
|
||||
/// <summary>
|
||||
/// Gets or sets the options.
|
||||
/// </summary>
|
||||
/// <value>The options.</value>
|
||||
public ChartTooltipOptions Options { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -35,7 +35,7 @@ namespace Radzen.Blazor
|
||||
.Add("rz-state-active", !object.Equals(Value, false))
|
||||
.AddDisabled(Disabled);
|
||||
|
||||
ClassList IconClassList => ClassList.Create("rz-chkbox-icon")
|
||||
ClassList IconClassList => ClassList.Create("notranslate rz-chkbox-icon")
|
||||
.Add("rzi rzi-check", object.Equals(Value, true))
|
||||
.Add("rzi rzi-times", object.Equals(Value, null));
|
||||
|
||||
|
||||
@@ -30,7 +30,7 @@ namespace Radzen.Blazor
|
||||
.AddDisabled(Disabled || item.Disabled);
|
||||
|
||||
ClassList IconClassList(RadzenCheckBoxListItem<TValue> item) => ClassList.Create("rz-chkbox-icon")
|
||||
.Add("rzi rzi-check", IsSelected(item));
|
||||
.Add("notranslate rzi rzi-check", IsSelected(item));
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the value property.
|
||||
|
||||
@@ -8,10 +8,10 @@
|
||||
<div @ref=@Element style=@Style @onclick=@Toggle @attributes=@Attributes class=@GetCssClass() id=@GetId() tabindex="@(Disabled ? -1 : TabIndex)" @onkeypress="@(args => OnKeyPress(args, Toggle()))" @onkeypress:preventDefault=preventKeyPress @onkeypress:stopPropagation>
|
||||
@if (Icon != null)
|
||||
{
|
||||
<i class="rzi" style="@(!string.IsNullOrEmpty(IconColor) ? $"color:{IconColor}" : null)">@Icon</i>
|
||||
<i class="notranslate rzi" style="@(!string.IsNullOrEmpty(IconColor) ? $"color:{IconColor}" : null)">@Icon</i>
|
||||
}
|
||||
<div class="rz-colorpicker-value" style="background-color: @Value" ></div>
|
||||
<button aria-label="@ToggleAriaLabel" type="button" tabindex="-1" class="rz-colorpicker-trigger" disabled=@Disabled @onclick:preventDefault><i class="rzi" /></button>
|
||||
<button aria-label="@ToggleAriaLabel" type="button" tabindex="-1" class="rz-colorpicker-trigger" disabled=@Disabled @onclick:preventDefault><i class="notranslate rzi" /></button>
|
||||
<Popup Lazy=@(PopupRenderMode == PopupRenderMode.OnDemand) @ref=@Popup class="rz-colorpicker-popup" Close=@OnClosePopup Open=@Open>
|
||||
@if (ShowHSV)
|
||||
{
|
||||
|
||||
@@ -2,7 +2,6 @@ using Microsoft.AspNetCore.Components;
|
||||
using Microsoft.AspNetCore.Components.Web;
|
||||
using Radzen.Blazor.Rendering;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.JSInterop;
|
||||
|
||||
@@ -167,7 +166,7 @@ namespace Radzen.Blazor
|
||||
}
|
||||
}
|
||||
|
||||
void UpdateColorUsingHsvHandles()
|
||||
async Task UpdateColorUsingHsvHandles()
|
||||
{
|
||||
var hsv = new HSV {
|
||||
Hue = HueHandleLeft,
|
||||
@@ -175,45 +174,59 @@ namespace Radzen.Blazor
|
||||
Value = 1 - SaturationHandleTop,
|
||||
Alpha = AlphaHandleLeft
|
||||
};
|
||||
|
||||
Color = hsv.ToRGB().ToCSS();
|
||||
TriggerChange();
|
||||
|
||||
await TriggerChange();
|
||||
}
|
||||
|
||||
Rect lastHslRect;
|
||||
void OnSaturationMove(DraggableEventArgs args)
|
||||
|
||||
async Task OnSaturationMove(DraggableEventArgs args)
|
||||
{
|
||||
lastHslRect = args.Rect; ;
|
||||
|
||||
SaturationHandleLeft = Math.Clamp((args.ClientX - args.Rect.Left) / args.Rect.Width, 0, 1);
|
||||
SaturationHandleTop = Math.Clamp((args.ClientY - args.Rect.Top) / args.Rect.Height, 0, 1);
|
||||
|
||||
UpdateColorUsingHsvHandles();
|
||||
await UpdateColorUsingHsvHandles();
|
||||
}
|
||||
|
||||
void TriggerChange()
|
||||
async Task TriggerChange()
|
||||
{
|
||||
if (!ShowButton)
|
||||
{
|
||||
ValueChanged.InvokeAsync(Color);
|
||||
Change.InvokeAsync(Color);
|
||||
await OnChanged();
|
||||
}
|
||||
|
||||
StateHasChanged();
|
||||
}
|
||||
|
||||
void ChangeRGB(object value)
|
||||
async Task OnChanged()
|
||||
{
|
||||
await ValueChanged.InvokeAsync(Color);
|
||||
|
||||
if (FieldIdentifier.FieldName != null)
|
||||
{
|
||||
EditContext?.NotifyFieldChanged(FieldIdentifier);
|
||||
}
|
||||
|
||||
await Change.InvokeAsync(Color);
|
||||
}
|
||||
|
||||
async Task ChangeRGB(object value)
|
||||
{
|
||||
var rgb = RGB.Parse(value as string);
|
||||
if (rgb != null)
|
||||
{
|
||||
rgb.Alpha = AlphaHandleLeft;
|
||||
UpdateColor(rgb);
|
||||
await UpdateColor(rgb);
|
||||
}
|
||||
}
|
||||
|
||||
internal async Task SelectColor(string value)
|
||||
{
|
||||
UpdateColor(RGB.Parse(value));
|
||||
await UpdateColor(RGB.Parse(value));
|
||||
|
||||
if (!ShowButton)
|
||||
{
|
||||
@@ -221,7 +234,7 @@ namespace Radzen.Blazor
|
||||
}
|
||||
}
|
||||
|
||||
void UpdateColor(RGB rgb)
|
||||
async Task UpdateColor(RGB rgb)
|
||||
{
|
||||
Color = rgb.ToCSS();
|
||||
|
||||
@@ -232,10 +245,10 @@ namespace Radzen.Blazor
|
||||
HueHandleLeft = hsv.Hue;
|
||||
AlphaHandleLeft = hsv.Alpha;
|
||||
|
||||
TriggerChange();
|
||||
await TriggerChange();
|
||||
}
|
||||
|
||||
void ChangeAlpha(double value)
|
||||
async Task ChangeAlpha(double value)
|
||||
{
|
||||
if (value >= 0 && value <= 100)
|
||||
{
|
||||
@@ -244,19 +257,19 @@ namespace Radzen.Blazor
|
||||
|
||||
Color = rgb.ToCSS();
|
||||
|
||||
TriggerChange();
|
||||
await TriggerChange();
|
||||
}
|
||||
}
|
||||
|
||||
void ChangeAlpha(object alpha)
|
||||
async Task ChangeAlpha(object alpha)
|
||||
{
|
||||
if (Double.TryParse((string)alpha, out var value))
|
||||
{
|
||||
ChangeAlpha(value);
|
||||
await ChangeAlpha(value);
|
||||
}
|
||||
}
|
||||
|
||||
void ChangeColor(double value, Action<RGB, double> update)
|
||||
async Task ChangeColor(double value, Action<RGB, double> update)
|
||||
{
|
||||
if (value >= 0 && value <= 255)
|
||||
{
|
||||
@@ -264,42 +277,42 @@ namespace Radzen.Blazor
|
||||
|
||||
update(rgb, value);
|
||||
|
||||
UpdateColor(rgb);
|
||||
await UpdateColor(rgb);
|
||||
}
|
||||
}
|
||||
|
||||
void ChangeColor(object color, Action<RGB, double> update)
|
||||
async Task ChangeColor(object color, Action<RGB, double> update)
|
||||
{
|
||||
if (Double.TryParse((string)color, out var value))
|
||||
{
|
||||
ChangeColor(value, update);
|
||||
await ChangeColor(value, update);
|
||||
}
|
||||
}
|
||||
|
||||
Rect lastAlphaRect;
|
||||
void OnAlphaMove(DraggableEventArgs args)
|
||||
|
||||
async Task OnAlphaMove(DraggableEventArgs args)
|
||||
{
|
||||
lastAlphaRect = args.Rect;
|
||||
|
||||
AlphaHandleLeft = Math.Round(Math.Clamp((args.ClientX - args.Rect.Left) / args.Rect.Width, 0, 1), 2);
|
||||
|
||||
UpdateColorUsingHsvHandles();
|
||||
await UpdateColorUsingHsvHandles();
|
||||
}
|
||||
|
||||
Rect lastHueRect;
|
||||
void OnHueMove(DraggableEventArgs args)
|
||||
async Task OnHueMove(DraggableEventArgs args)
|
||||
{
|
||||
lastHueRect = args.Rect;
|
||||
|
||||
HueHandleLeft = Math.Clamp((args.ClientX - args.Rect.Left) / args.Rect.Width, 0, 1);
|
||||
|
||||
UpdateColorUsingHsvHandles();
|
||||
await UpdateColorUsingHsvHandles();
|
||||
}
|
||||
|
||||
async Task OnClick()
|
||||
{
|
||||
await ValueChanged.InvokeAsync(Color);
|
||||
await Change.InvokeAsync(Color);
|
||||
await OnChanged();
|
||||
await Popup.CloseAsync();
|
||||
}
|
||||
|
||||
@@ -309,6 +322,7 @@ namespace Radzen.Blazor
|
||||
{
|
||||
SetInitialValue();
|
||||
}
|
||||
|
||||
await Close.InvokeAsync(null);
|
||||
}
|
||||
|
||||
@@ -370,14 +384,7 @@ namespace Radzen.Blazor
|
||||
/// <inheritdoc />
|
||||
protected override string GetComponentCssClass()
|
||||
{
|
||||
var classList = new List<string>() { "rz-colorpicker" };
|
||||
|
||||
if (Disabled)
|
||||
{
|
||||
classList.Add("rz-state-disabled");
|
||||
}
|
||||
|
||||
return string.Join(" ", classList);
|
||||
return GetClassList("rz-colorpicker").ToString();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
@@ -435,7 +442,7 @@ namespace Radzen.Blazor
|
||||
lastHueRect = await JSRuntime.InvokeAsync<Rect>("Radzen.clientRect", (GetId() + "hue"));
|
||||
}
|
||||
|
||||
OnHueMove(new DraggableEventArgs() { Rect = lastHueRect, ClientX = lastHueRect.Left + lastHueRect.Width * HueHandleLeft + (key == "ArrowLeft" ? -1 : 1) });
|
||||
await OnHueMove(new DraggableEventArgs() { Rect = lastHueRect, ClientX = lastHueRect.Left + lastHueRect.Width * HueHandleLeft + (key == "ArrowLeft" ? -1 : 1) });
|
||||
}
|
||||
else if (key == "Escape")
|
||||
{
|
||||
@@ -460,7 +467,7 @@ namespace Radzen.Blazor
|
||||
lastAlphaRect = await JSRuntime.InvokeAsync<Rect>("Radzen.clientRect", (GetId() + "alpha"));
|
||||
}
|
||||
|
||||
OnAlphaMove(new DraggableEventArgs() { Rect = lastAlphaRect, ClientX = lastAlphaRect.Left + lastAlphaRect.Width * AlphaHandleLeft + (key == "ArrowLeft" ? -3 : 3) });
|
||||
await OnAlphaMove(new DraggableEventArgs() { Rect = lastAlphaRect, ClientX = lastAlphaRect.Left + lastAlphaRect.Width * AlphaHandleLeft + (key == "ArrowLeft" ? -3 : 3) });
|
||||
}
|
||||
else if (key == "Escape")
|
||||
{
|
||||
@@ -485,9 +492,9 @@ namespace Radzen.Blazor
|
||||
{
|
||||
preventKeyPress = true;
|
||||
|
||||
OnSaturationMove(new DraggableEventArgs()
|
||||
{
|
||||
Rect = lastHslRect,
|
||||
await OnSaturationMove(new DraggableEventArgs()
|
||||
{
|
||||
Rect = lastHslRect,
|
||||
ClientX = lastHslRect.Left + lastHslRect.Width * SaturationHandleLeft + (key == "ArrowLeft" ? -1 : key == "ArrowRight" ? 1 : 0),
|
||||
ClientY = lastHslRect.Top + lastHslRect.Height * SaturationHandleTop + (key == "ArrowUp" ? -1 : key == "ArrowDown" ? 1 : 0)
|
||||
});
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
<RadzenNotification @attributes="Attributes" />
|
||||
<RadzenContextMenu @attributes="Attributes" />
|
||||
<RadzenTooltip @attributes="Attributes" />
|
||||
<RadzenChartTooltip @attributes="Attributes" />
|
||||
|
||||
@code {
|
||||
/// <summary>
|
||||
|
||||
@@ -48,11 +48,13 @@ namespace Radzen.Blazor
|
||||
{
|
||||
var validationResults = new List<ValidationResult>();
|
||||
|
||||
var getter = PropertyAccess.Getter<object>(EditContext.Model, component.FieldIdentifier.FieldName);
|
||||
var model = component.FieldIdentifier.Model;
|
||||
|
||||
var value = getter(EditContext.Model);
|
||||
var getter = PropertyAccess.Getter<object>(model, component.FieldIdentifier.FieldName);
|
||||
|
||||
var validationContext = new ValidationContext(EditContext.Model)
|
||||
var value = getter(model);
|
||||
|
||||
var validationContext = new ValidationContext(model)
|
||||
{
|
||||
MemberName = component.FieldIdentifier.FieldName
|
||||
};
|
||||
|
||||
@@ -227,6 +227,20 @@ namespace Radzen.Blazor
|
||||
[Parameter]
|
||||
public string DoesNotContainText { get; set; } = "Does not contain";
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the in operator text.
|
||||
/// </summary>
|
||||
/// <value>The in operator text.</value>
|
||||
[Parameter]
|
||||
public string InText { get; set; } = "In";
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the not in operator text.
|
||||
/// </summary>
|
||||
/// <value>The not in operator text.</value>
|
||||
[Parameter]
|
||||
public string NotInText { get; set; } = "Not in";
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the starts with text.
|
||||
/// </summary>
|
||||
@@ -262,6 +276,13 @@ namespace Radzen.Blazor
|
||||
[Parameter]
|
||||
public string IsNotEmptyText { get; set; } = "Is not empty";
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the custom filter operator text.
|
||||
/// </summary>
|
||||
/// <value>The custom filter operator text.</value>
|
||||
[Parameter]
|
||||
public string CustomText { get; set; } = "Custom";
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether the columns can be filtered.
|
||||
/// </summary>
|
||||
|
||||
@@ -119,6 +119,8 @@ else
|
||||
}
|
||||
|
||||
Filter.Property = property.Property;
|
||||
Filter.FilterProperty = property.FilterProperty;
|
||||
Filter.Type = property.FilterPropertyType;
|
||||
|
||||
if (Filter.FilterOperator == null)
|
||||
{
|
||||
@@ -289,7 +291,7 @@ else
|
||||
var eventCallbackGenericCreate = typeof(NumericFilterEventCallback).GetMethod("Create").MakeGenericMethod(type);
|
||||
var eventCallbackGenericAction = typeof(NumericFilterEventCallback).GetMethod("Action").MakeGenericMethod(type);
|
||||
|
||||
builder.AddAttribute(3, "Change", eventCallbackGenericCreate.Invoke(this,
|
||||
builder.AddAttribute(4, "ValueChanged", eventCallbackGenericCreate.Invoke(this,
|
||||
new object[] { this, eventCallbackGenericAction.Invoke(this, new object[] { action }) }));
|
||||
|
||||
builder.CloseComponent();
|
||||
|
||||
@@ -3,10 +3,7 @@ using Microsoft.JSInterop;
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Data.Common;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Linq.Dynamic.Core;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Radzen.Blazor
|
||||
@@ -118,6 +115,13 @@ namespace Radzen.Blazor
|
||||
[Parameter]
|
||||
public string Property { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the filter property name.
|
||||
/// </summary>
|
||||
/// <value>The filter property name.</value>
|
||||
[Parameter]
|
||||
public string FilterProperty { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether this property is selected in the filter.
|
||||
/// </summary>
|
||||
@@ -275,6 +279,24 @@ namespace Radzen.Blazor
|
||||
[Parameter]
|
||||
public FilterOperator FilterOperator { get; set; }
|
||||
|
||||
IEnumerable<FilterOperator> _filterOperators;
|
||||
/// <summary>
|
||||
/// Gets or sets the filter operators.
|
||||
/// </summary>
|
||||
/// <value>The filter operators.</value>
|
||||
[Parameter]
|
||||
public IEnumerable<FilterOperator> FilterOperators
|
||||
{
|
||||
get
|
||||
{
|
||||
return _filterOperators;
|
||||
}
|
||||
set
|
||||
{
|
||||
_filterOperators = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Set property filter operator.
|
||||
/// </summary>
|
||||
@@ -293,6 +315,8 @@ namespace Radzen.Blazor
|
||||
/// </summary>
|
||||
public virtual IEnumerable<FilterOperator> GetFilterOperators()
|
||||
{
|
||||
if (FilterOperators != null) return FilterOperators;
|
||||
|
||||
if (PropertyAccess.IsEnum(FilterPropertyType))
|
||||
return new FilterOperator[] { FilterOperator.Equals, FilterOperator.NotEquals };
|
||||
|
||||
@@ -340,10 +364,16 @@ namespace Radzen.Blazor
|
||||
{
|
||||
switch (filterOperator)
|
||||
{
|
||||
case FilterOperator.Custom:
|
||||
return DataFilter?.CustomText;
|
||||
case FilterOperator.Contains:
|
||||
return DataFilter?.ContainsText;
|
||||
case FilterOperator.DoesNotContain:
|
||||
return DataFilter?.DoesNotContainText;
|
||||
case FilterOperator.In:
|
||||
return DataFilter?.InText;
|
||||
case FilterOperator.NotIn:
|
||||
return DataFilter?.NotInText;
|
||||
case FilterOperator.EndsWith:
|
||||
return DataFilter?.EndsWithText;
|
||||
case FilterOperator.Equals:
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
@if (AllowGrouping || AllowColumnPicking)
|
||||
{
|
||||
<div class="rz-group-header" @onmouseup=@(args => EndColumnDropToGroup())>
|
||||
@if (@HeaderTemplate != null)
|
||||
@if (@HeaderTemplate != null && ShowHeader)
|
||||
{
|
||||
<div class="rz-custom-header" @onkeydown:stopPropagation>
|
||||
@HeaderTemplate
|
||||
@@ -36,8 +36,8 @@
|
||||
{
|
||||
<div class="rz-group-header-item">
|
||||
<span class="rz-group-header-item-title">@gd.GetTitle()</span>
|
||||
<a id="@(GetId() + "rg")" aria-label="@RemoveGroupArialLabel" @onclick:preventDefault="true" @onclick=@(args => RemoveGroupAsync(gd)) role="button" class="rz-dialog-titlebar-icon rz-dialog-titlebar-close">
|
||||
<span class="rzi rzi-times"></span>
|
||||
<a id="@(GetId() + "rg")" aria-label="@RemoveGroupAriaLabel" @onclick:preventDefault="true" @onclick=@(args => RemoveGroupAsync(gd)) role="button" class="rz-dialog-titlebar-icon rz-dialog-titlebar-close">
|
||||
<span class="notranslate rzi rzi-times"></span>
|
||||
</a>
|
||||
</div>
|
||||
}
|
||||
@@ -53,7 +53,7 @@
|
||||
{
|
||||
<div class="rz-column-picker">
|
||||
<RadzenDropDown SelectAllText="@AllColumnsText" AllowSelectAll="@AllowPickAllColumns"
|
||||
MaxSelectedLabels="@ColumnsPickerMaxSelectedLabels" InputAttributes="@(new Dictionary<string,object>(){ { "aria-label", SelectVisibleColumnsArialLabel }})"
|
||||
MaxSelectedLabels="@ColumnsPickerMaxSelectedLabels" InputAttributes="@(new Dictionary<string,object>(){ { "aria-label", SelectVisibleColumnsAriaLabel }})"
|
||||
SelectedItemsText="@ColumnsShowingText" Change=@ToggleColumns
|
||||
@bind-Value="@selectedColumns" FilterCaseSensitivity=FilterCaseSensitivity.CaseInsensitive
|
||||
Multiple="true" AllowFiltering="@ColumnsPickerAllowFiltering"
|
||||
@@ -67,7 +67,7 @@
|
||||
}
|
||||
else
|
||||
{
|
||||
@if (@HeaderTemplate != null)
|
||||
@if (@HeaderTemplate != null && ShowHeader)
|
||||
{
|
||||
<div class="rz-group-header">
|
||||
<div class="rz-custom-header" @onkeydown:stopPropagation>
|
||||
@@ -168,167 +168,9 @@
|
||||
{
|
||||
var filterMode = column.FilterMode ?? FilterMode;
|
||||
<th colspan="@column.GetColSpan()" class="@($"rz-unselectable-text {getFrozenColumnClass(column, visibleColumns)} {column.HeaderCssClass}")" scope="col" style="@column.GetStyle(true, true)">
|
||||
@if (AllowFiltering && column.Filterable && column.Columns == null && (!string.IsNullOrEmpty(column.GetFilterProperty()) || column.FilterTemplate != null))
|
||||
@if (allColumns.All(c => c.Parent == null) && AllowFiltering && column.Filterable && column.Columns == null && (!string.IsNullOrEmpty(column.GetFilterProperty()) || column.FilterTemplate != null))
|
||||
{
|
||||
<div class="rz-cell-filter">
|
||||
<div class="rz-cell-filter-content">
|
||||
@if (column.FilterTemplate != null)
|
||||
{
|
||||
@column.FilterTemplate(column)
|
||||
}
|
||||
else
|
||||
{
|
||||
<span class="rz-cell-filter-label" style="height:35px; width:100%;" onclick="event.preventDefault()">
|
||||
@if (PropertyAccess.IsDate(column.FilterPropertyType))
|
||||
{
|
||||
if (filterMode == FilterMode.Simple)
|
||||
{
|
||||
<button aria-label="@FilterToggleAriaLabel" class="rz-button rz-button-md rz-button-icon-only rz-variant-flat rz-base rz-shade-default" onclick="@($"Radzen.togglePopup(this.parentNode, '{PopupID}{column.GetFilterProperty()}')")">
|
||||
<i class="rzi">date_range</i>
|
||||
</button>
|
||||
var filterValue = column.GetFilterValue();
|
||||
var filterOperator = column.GetFilterOperator();
|
||||
@if (filterValue != null && filters.Any(d => d.Property == column.GetFilterProperty()))
|
||||
{
|
||||
<span class="rz-current-filter">@string.Format("{0:" + getFilterDateFormat(column) + "}", filterValue)</span>
|
||||
<i @onclick="@((args) => ClearFilter(column))" class="rzi rz-cell-filter-clear">close</i>
|
||||
}
|
||||
else if ((filterOperator == FilterOperator.IsNull || filterOperator == FilterOperator.IsNotNull) && filters.Any(d => d.Property == column.GetFilterProperty()))
|
||||
{
|
||||
<span class="rz-current-filter">@column.GetFilterOperatorText(filterOperator)</span>
|
||||
<i @onclick="@((args) => ClearFilter(column))" class="rzi rz-cell-filter-clear">close</i>
|
||||
}
|
||||
<div id="@($"{PopupID}{column.GetFilterProperty()}")" class="rz-overlaypanel rz-grid-date-filter"
|
||||
style="display:none;" tabindex="0">
|
||||
<div class="rz-overlaypanel-content">
|
||||
|
||||
<div class="rz-date-filter">
|
||||
|
||||
<div class="rz-listbox rz-inputtext ">
|
||||
<div class="rz-listbox-list-wrapper">
|
||||
<ul class="rz-listbox-list">
|
||||
@if (column.GetFilterOperators().Contains(FilterOperator.Equals))
|
||||
{
|
||||
<li class="@(DateFilterOperatorStyle(column, FilterOperator.Equals))" @onclick="@((args) => ApplyDateFilterByFilterOperator(column, FilterOperator.Equals))" style="display: block;">
|
||||
<span>@EqualsText</span>
|
||||
</li>
|
||||
}
|
||||
@if (column.GetFilterOperators().Contains(FilterOperator.NotEquals))
|
||||
{
|
||||
<li class="@(DateFilterOperatorStyle(column, FilterOperator.NotEquals))" @onclick="@((args) => ApplyDateFilterByFilterOperator(column, FilterOperator.NotEquals))" style="display: block;">
|
||||
<span>@NotEqualsText</span>
|
||||
</li>
|
||||
}
|
||||
@if (column.GetFilterOperators().Contains(FilterOperator.LessThan))
|
||||
{
|
||||
<li class="@(DateFilterOperatorStyle(column, FilterOperator.LessThan))" @onclick="@((args) => ApplyDateFilterByFilterOperator(column, FilterOperator.LessThan))" style="display: block;">
|
||||
<span>@LessThanText</span>
|
||||
</li>
|
||||
}
|
||||
@if (column.GetFilterOperators().Contains(FilterOperator.LessThanOrEquals))
|
||||
{
|
||||
<li class="@(DateFilterOperatorStyle(column, FilterOperator.LessThanOrEquals))" @onclick="@((args) => ApplyDateFilterByFilterOperator(column, FilterOperator.LessThanOrEquals))" style="display: block;">
|
||||
<span>@LessThanOrEqualsText</span>
|
||||
</li>
|
||||
}
|
||||
@if (column.GetFilterOperators().Contains(FilterOperator.GreaterThan))
|
||||
{
|
||||
<li class="@(DateFilterOperatorStyle(column, FilterOperator.GreaterThan))" @onclick="@((args) => ApplyDateFilterByFilterOperator(column, FilterOperator.GreaterThan))" style="display: block;">
|
||||
<span>@GreaterThanText</span>
|
||||
</li>
|
||||
}
|
||||
@if (column.GetFilterOperators().Contains(FilterOperator.GreaterThanOrEquals))
|
||||
{
|
||||
<li class="@(DateFilterOperatorStyle(column, FilterOperator.GreaterThanOrEquals))" @onclick="@((args) => ApplyDateFilterByFilterOperator(column, FilterOperator.GreaterThanOrEquals))" style="display: block;">
|
||||
<span>@GreaterThanOrEqualsText</span>
|
||||
</li>
|
||||
}
|
||||
@if (column.GetFilterOperators().Contains(FilterOperator.IsEmpty))
|
||||
{
|
||||
<li class="@(DateFilterOperatorStyle(column, FilterOperator.IsEmpty))" @onclick="@((args) => ApplyDateFilterByFilterOperator(column, FilterOperator.IsEmpty))" style="display: block;">
|
||||
<span>@IsEmptyText</span>
|
||||
</li>
|
||||
}
|
||||
@if (column.GetFilterOperators().Contains(FilterOperator.IsNotEmpty))
|
||||
{
|
||||
<li class="@(DateFilterOperatorStyle(column, FilterOperator.IsNotEmpty))" @onclick="@((args) => ApplyDateFilterByFilterOperator(column, FilterOperator.IsNotEmpty))" style="display: block;">
|
||||
<span>@IsNotEmptyText</span>
|
||||
</li>
|
||||
}
|
||||
@if (column.GetFilterOperators().Contains(FilterOperator.IsNull))
|
||||
{
|
||||
<li class="@(DateFilterOperatorStyle(column, FilterOperator.IsNull))" @onclick="@((args) => ApplyDateFilterByFilterOperator(column, FilterOperator.IsNull))" style="display: block;">
|
||||
<span>@IsNullText</span>
|
||||
</li>
|
||||
}
|
||||
@if (column.GetFilterOperators().Contains(FilterOperator.IsNotNull))
|
||||
{
|
||||
<li class="@(DateFilterOperatorStyle(column, FilterOperator.IsNotNull))" @onclick="@((args) => ApplyDateFilterByFilterOperator(column, FilterOperator.IsNotNull))" style="display: block;">
|
||||
<span>@IsNotNullText</span>
|
||||
</li>
|
||||
}
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<RadzenDatePicker TValue="@object" AllowInput=@(AllowFilterDateInput) InputAttributes="@(new Dictionary<string,object>(){ { "aria-label", column.Title + FilterValueArialLabel + column.GetFilterValue() }})"
|
||||
ShowTime="@column.ShowTimeForDateTimeFilter()" ShowTimeOkButton="false" Inline="true" DateFormat="@getFilterDateFormat(column)"
|
||||
Value="@column.GetFilterValue()" Change="@(args => { column.SetFilterValue(PropertyAccess.IsDateOnly(column.FilterPropertyType) ? PropertyAccess.DateOnlyFromDateTime(args.Value) : args.Value); SaveSettings(); })" />
|
||||
|
||||
</div>
|
||||
<div class="rz-grid-filter-buttons">
|
||||
<RadzenButton ButtonStyle="ButtonStyle.Base" class="rz-clear-filter" Click="@((args) => ClearFilter(column, true))" Text=@ClearFilterText title="@ClearFilterText" />
|
||||
<RadzenButton ButtonStyle="ButtonStyle.Primary" class="rz-apply-filter" Click="@((args) => ApplyFilter(column, true))" Text=@ApplyFilterText title="@ApplyFilterText" />
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
else
|
||||
{
|
||||
<RadzenDataGridFilterMenu Grid="@this" Column="@column" />
|
||||
<RadzenDatePicker Disabled=@(!column.CanSetFilterValue()) TValue="@object" Style="width:100%" AllowInput=@(AllowFilterDateInput) AllowClear="true" InputAttributes="@(new Dictionary<string,object>(){ { "aria-label", column.Title + FilterValueArialLabel + column.GetFilterValue() }})"
|
||||
ShowTime="false" ShowTimeOkButton="false" DateFormat="@getFilterDateFormat(column)"
|
||||
Value="@column.GetFilterValue()" Change="@(args => { if(!args.HasValue) { InvokeAsync(() => ClearFilter(column, true)); } else {column.SetFilterValue(PropertyAccess.IsDateOnly(column.FilterPropertyType) ? PropertyAccess.DateOnlyFromDateTime(args.Value) : args.Value); InvokeAsync(() => ApplyFilter(column, true));} })" />
|
||||
}
|
||||
}
|
||||
else if (PropertyAccess.IsNullableEnum(column.FilterPropertyType) || PropertyAccess.IsEnum(column.FilterPropertyType))
|
||||
{
|
||||
<RadzenDropDown Style="width:100%" AllowClear="true" AllowFiltering="false" TValue="@object"
|
||||
Value=@column.GetFilterValue() Multiple="false" Placeholder="@EnumFilterSelectText" TextProperty="Text" ValueProperty="Value"
|
||||
Data=@((PropertyAccess.IsNullableEnum(column.FilterPropertyType) ? new object[]{ new { Value = -1, Text = EnumNullFilterText}} : Enumerable.Empty<object>()).Concat(EnumExtensions.EnumAsKeyValuePair(Nullable.GetUnderlyingType(column.FilterPropertyType) ?? column.FilterPropertyType)))
|
||||
Change="@(args => {column.SetFilterValue(args);column.SetFilterOperator(object.Equals(args, -1) ? FilterOperator.IsNull : FilterOperator.Equals);InvokeAsync(() => ApplyFilter(column, true));})" />
|
||||
}
|
||||
else if (PropertyAccess.IsNumeric(column.FilterPropertyType))
|
||||
{
|
||||
if (filterMode == FilterMode.SimpleWithMenu)
|
||||
{
|
||||
<RadzenDataGridFilterMenu Grid="@this" Column="@column" />
|
||||
}
|
||||
@(DrawNumericFilter(column))
|
||||
}
|
||||
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
|
||||
{
|
||||
if (filterMode == FilterMode.SimpleWithMenu)
|
||||
{
|
||||
<RadzenDataGridFilterMenu Grid="@this" Column="@column" />
|
||||
}
|
||||
<input autocomplete="off" aria-label=@(column.Title + FilterValueArialLabel + column.GetFilterValue()) disabled=@(!column.CanSetFilterValue()) id="@(getFilterInputId(column))" @onchange="@((args) => OnFilter(args, column))" @onkeydown="@((args) => OnFilterKeyPress(args, column))" value="@column.GetFilterValue()" type="text" placeholder="@column.GetFilterPlaceholder()" class="rz-textbox" style="width: 100%;" />
|
||||
@if (column.GetFilterValue() != null && filters.Any(d => d.Property == column.GetFilterProperty()))
|
||||
{
|
||||
<i @onclick="@((args) => ClearFilter(column))" class="rzi rz-cell-filter-clear" style="position:absolute;inset-inline-end:10px;">close</i>
|
||||
}
|
||||
}
|
||||
</span>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
@RenderSimpleFilter(column, filterMode)
|
||||
}
|
||||
</th>
|
||||
}
|
||||
@@ -338,7 +180,7 @@
|
||||
<tbody>
|
||||
@if (Data != null)
|
||||
{
|
||||
@if (!ShowEmptyMessage || Count > 0 && (IsVirtualizationAllowed() ? Count > 0 : true) || LoadData.HasDelegate && Data.Count() > 0)
|
||||
@if (!ShowEmptyMessage || Count > 0 && (IsVirtualizationAllowed() ? Count > 0 && Data.Count() > 0 : true) || LoadData.HasDelegate && Data.Count() > 0)
|
||||
{
|
||||
if (columns.Count > 0)
|
||||
{
|
||||
@@ -434,7 +276,7 @@
|
||||
}
|
||||
else
|
||||
{
|
||||
<i class="rzi-circle-o-notch"></i>
|
||||
<i class="notranslate rzi-circle-o-notch"></i>
|
||||
}
|
||||
</div>
|
||||
}
|
||||
@@ -454,6 +296,214 @@
|
||||
}
|
||||
</CascadingValue>
|
||||
@code {
|
||||
internal RenderFragment RenderSimpleFilter(RadzenDataGridColumn<TItem> column, FilterMode filterMode)
|
||||
{
|
||||
return __builder =>
|
||||
{
|
||||
<text>
|
||||
@if (AllowFiltering && column.Filterable && column.Columns == null && (!string.IsNullOrEmpty(column.GetFilterProperty()) || column.FilterTemplate != null))
|
||||
{
|
||||
<div class="rz-cell-filter">
|
||||
<div class="rz-cell-filter-content">
|
||||
@if (column.FilterTemplate != null)
|
||||
{
|
||||
@column.FilterTemplate(column)
|
||||
}
|
||||
else
|
||||
{
|
||||
<span class="rz-cell-filter-label" style="height:35px; width:100%;" onclick="event.preventDefault()">
|
||||
@if (PropertyAccess.IsDate(column.FilterPropertyType))
|
||||
{
|
||||
if (filterMode == FilterMode.Simple)
|
||||
{
|
||||
<button aria-label="@FilterToggleAriaLabel" class="rz-button rz-button-md rz-button-icon-only rz-variant-flat rz-base rz-shade-default @(column.HasActiveFilter() ? "rz-grid-filter-active" : "")" onclick="@($"Radzen.togglePopup(this.parentNode, '{PopupID}{column.GetFilterProperty()}')")">
|
||||
<i class="notranslate rzi">date_range</i>
|
||||
</button>
|
||||
<span>
|
||||
@{ var filterValue = column.GetFilterValue();
|
||||
var filterOperator = column.GetFilterOperator();}
|
||||
@if (filterValue != null && filters.Any(d => d.Property == column.GetFilterProperty()))
|
||||
{
|
||||
<span class="rz-current-filter">@string.Format("{0:" + getFilterDateFormat(column) + "}", filterValue)</span>
|
||||
<i @onclick="@((args) => ClearFilter(column))" class="notranslate rzi rz-cell-filter-clear">close</i>
|
||||
}
|
||||
else if ((filterOperator == FilterOperator.IsNull || filterOperator == FilterOperator.IsNotNull) && filters.Any(d => d.Property == column.GetFilterProperty()))
|
||||
{
|
||||
<span class="rz-current-filter">@column.GetFilterOperatorText(filterOperator)</span>
|
||||
<i @onclick="@((args) => ClearFilter(column))" class="notranslate rzi rz-cell-filter-clear">close</i>
|
||||
}
|
||||
</span>
|
||||
<div id="@($"{PopupID}{column.GetFilterProperty()}")" class="rz-overlaypanel rz-grid-date-filter"
|
||||
style="display:none;" tabindex="0">
|
||||
<div class="rz-overlaypanel-content">
|
||||
|
||||
<div class="rz-date-filter">
|
||||
|
||||
<div class="rz-listbox rz-inputtext ">
|
||||
<div class="rz-listbox-list-wrapper">
|
||||
<ul class="rz-listbox-list">
|
||||
@if (column.GetFilterOperators().Contains(FilterOperator.Equals))
|
||||
{
|
||||
<li class="@(DateFilterOperatorStyle(column, FilterOperator.Equals))" @onclick="@((args) => ApplyDateFilterByFilterOperator(column, FilterOperator.Equals))" style="display: block;">
|
||||
<span>@EqualsText</span>
|
||||
</li>
|
||||
}
|
||||
@if (column.GetFilterOperators().Contains(FilterOperator.NotEquals))
|
||||
{
|
||||
<li class="@(DateFilterOperatorStyle(column, FilterOperator.NotEquals))" @onclick="@((args) => ApplyDateFilterByFilterOperator(column, FilterOperator.NotEquals))" style="display: block;">
|
||||
<span>@NotEqualsText</span>
|
||||
</li>
|
||||
}
|
||||
@if (column.GetFilterOperators().Contains(FilterOperator.LessThan))
|
||||
{
|
||||
<li class="@(DateFilterOperatorStyle(column, FilterOperator.LessThan))" @onclick="@((args) => ApplyDateFilterByFilterOperator(column, FilterOperator.LessThan))" style="display: block;">
|
||||
<span>@LessThanText</span>
|
||||
</li>
|
||||
}
|
||||
@if (column.GetFilterOperators().Contains(FilterOperator.LessThanOrEquals))
|
||||
{
|
||||
<li class="@(DateFilterOperatorStyle(column, FilterOperator.LessThanOrEquals))" @onclick="@((args) => ApplyDateFilterByFilterOperator(column, FilterOperator.LessThanOrEquals))" style="display: block;">
|
||||
<span>@LessThanOrEqualsText</span>
|
||||
</li>
|
||||
}
|
||||
@if (column.GetFilterOperators().Contains(FilterOperator.GreaterThan))
|
||||
{
|
||||
<li class="@(DateFilterOperatorStyle(column, FilterOperator.GreaterThan))" @onclick="@((args) => ApplyDateFilterByFilterOperator(column, FilterOperator.GreaterThan))" style="display: block;">
|
||||
<span>@GreaterThanText</span>
|
||||
</li>
|
||||
}
|
||||
@if (column.GetFilterOperators().Contains(FilterOperator.GreaterThanOrEquals))
|
||||
{
|
||||
<li class="@(DateFilterOperatorStyle(column, FilterOperator.GreaterThanOrEquals))" @onclick="@((args) => ApplyDateFilterByFilterOperator(column, FilterOperator.GreaterThanOrEquals))" style="display: block;">
|
||||
<span>@GreaterThanOrEqualsText</span>
|
||||
</li>
|
||||
}
|
||||
@if (column.GetFilterOperators().Contains(FilterOperator.IsEmpty))
|
||||
{
|
||||
<li class="@(DateFilterOperatorStyle(column, FilterOperator.IsEmpty))" @onclick="@((args) => ApplyDateFilterByFilterOperator(column, FilterOperator.IsEmpty))" style="display: block;">
|
||||
<span>@IsEmptyText</span>
|
||||
</li>
|
||||
}
|
||||
@if (column.GetFilterOperators().Contains(FilterOperator.IsNotEmpty))
|
||||
{
|
||||
<li class="@(DateFilterOperatorStyle(column, FilterOperator.IsNotEmpty))" @onclick="@((args) => ApplyDateFilterByFilterOperator(column, FilterOperator.IsNotEmpty))" style="display: block;">
|
||||
<span>@IsNotEmptyText</span>
|
||||
</li>
|
||||
}
|
||||
@if (column.GetFilterOperators().Contains(FilterOperator.IsNull))
|
||||
{
|
||||
<li class="@(DateFilterOperatorStyle(column, FilterOperator.IsNull))" @onclick="@((args) => ApplyDateFilterByFilterOperator(column, FilterOperator.IsNull))" style="display: block;">
|
||||
<span>@IsNullText</span>
|
||||
</li>
|
||||
}
|
||||
@if (column.GetFilterOperators().Contains(FilterOperator.IsNotNull))
|
||||
{
|
||||
<li class="@(DateFilterOperatorStyle(column, FilterOperator.IsNotNull))" @onclick="@((args) => ApplyDateFilterByFilterOperator(column, FilterOperator.IsNotNull))" style="display: block;">
|
||||
<span>@IsNotNullText</span>
|
||||
</li>
|
||||
}
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<RadzenDatePicker TValue="@object" AllowInput=@(AllowFilterDateInput) InputAttributes="@(new Dictionary<string,object>(){ { "aria-label", column.Title + FilterValueAriaLabel + column.GetFilterValue() }})"
|
||||
ShowTime="@column.ShowTimeForDateTimeFilter()" ShowTimeOkButton="false" Inline="true" DateFormat="@getFilterDateFormat(column)"
|
||||
Value="@column.GetFilterValue()" Change="@(args => { column.SetFilterValue(PropertyAccess.IsDateOnly(column.FilterPropertyType) ? PropertyAccess.DateOnlyFromDateTime(args.Value) : args.Value); SaveSettings(); })" />
|
||||
|
||||
</div>
|
||||
<div class="rz-grid-filter-buttons">
|
||||
<RadzenButton ButtonStyle="ButtonStyle.Base" class="rz-clear-filter" Click="@((args) => ClearFilter(column, true))" Text=@ClearFilterText title="@ClearFilterText" />
|
||||
<RadzenButton ButtonStyle="ButtonStyle.Primary" class="rz-apply-filter" Click="@((args) => ApplyFilter(column, true))" Text=@ApplyFilterText title="@ApplyFilterText" />
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
else
|
||||
{
|
||||
<RadzenDataGridFilterMenu Grid="@this" Column="@column" />
|
||||
@if (column.FilterValueTemplate != null)
|
||||
{
|
||||
@column.FilterValueTemplate(column)
|
||||
}
|
||||
else
|
||||
{
|
||||
<RadzenDatePicker Disabled=@(!column.CanSetFilterValue()) TValue="@object" Style="width:100%" AllowInput=@(AllowFilterDateInput) AllowClear="true" InputAttributes="@(new Dictionary<string,object>(){ { "aria-label", column.Title + FilterValueAriaLabel + column.GetFilterValue() }})"
|
||||
ShowTime="false" ShowTimeOkButton="false" DateFormat="@getFilterDateFormat(column)"
|
||||
Value="@column.GetFilterValue()" Change="@(args => { if(!args.HasValue) { InvokeAsync(() => ClearFilter(column, true)); } else {column.SetFilterValue(PropertyAccess.IsDateOnly(column.FilterPropertyType) ? PropertyAccess.DateOnlyFromDateTime(args.Value) : args.Value); InvokeAsync(() => ApplyFilter(column, true));} })" />
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (PropertyAccess.IsNullableEnum(column.FilterPropertyType) || PropertyAccess.IsEnum(column.FilterPropertyType))
|
||||
{
|
||||
@if (column.FilterValueTemplate != null)
|
||||
{
|
||||
@column.FilterValueTemplate(column)
|
||||
}
|
||||
else
|
||||
{
|
||||
<RadzenDropDown Style="width:100%" AllowClear="true" AllowFiltering="false" TValue="@object"
|
||||
Value=@column.GetFilterValue() Multiple="false" Placeholder="@EnumFilterSelectText" TextProperty="Text" ValueProperty="Value"
|
||||
Data=@((PropertyAccess.IsNullableEnum(column.FilterPropertyType) ? new object[]{ new { Value = Convert.ChangeType(-1, Enum.GetUnderlyingType(Nullable.GetUnderlyingType(column.FilterPropertyType) ?? column.FilterPropertyType)), Text = EnumNullFilterText}} : Enumerable.Empty<object>()).Concat(EnumExtensions.EnumAsKeyValuePair(Nullable.GetUnderlyingType(column.FilterPropertyType) ?? column.FilterPropertyType)))
|
||||
Change="@(args => {column.SetFilterValue(args);column.SetFilterOperator(object.Equals(args, -1) ? FilterOperator.IsNull : FilterOperator.Equals);InvokeAsync(() => ApplyFilter(column, true));})" />
|
||||
}
|
||||
}
|
||||
else if (PropertyAccess.IsNumeric(column.FilterPropertyType))
|
||||
{
|
||||
if (filterMode == FilterMode.SimpleWithMenu)
|
||||
{
|
||||
<RadzenDataGridFilterMenu Grid="@this" Column="@column" />
|
||||
}
|
||||
@if (column.FilterValueTemplate != null)
|
||||
{
|
||||
@column.FilterValueTemplate(column)
|
||||
}
|
||||
else
|
||||
{
|
||||
@(DrawNumericFilter(column))
|
||||
}
|
||||
}
|
||||
else if (column.FilterPropertyType == typeof(bool) || column.FilterPropertyType == typeof(bool?))
|
||||
{
|
||||
@if (column.FilterValueTemplate != null)
|
||||
{
|
||||
@column.FilterValueTemplate(column)
|
||||
}
|
||||
else
|
||||
{
|
||||
<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
|
||||
{
|
||||
if (filterMode == FilterMode.SimpleWithMenu)
|
||||
{
|
||||
<RadzenDataGridFilterMenu Grid="@this" Column="@column" />
|
||||
}
|
||||
@if (column.FilterValueTemplate != null)
|
||||
{
|
||||
@column.FilterValueTemplate(column)
|
||||
}
|
||||
else
|
||||
{
|
||||
<input autocomplete="off" aria-label=@(column.Title + FilterValueAriaLabel + column.GetFilterValue()) disabled=@(!column.CanSetFilterValue()) id="@(getFilterInputId(column))" @onchange="@((args) => OnFilter(args, column))" @onkeydown="@((args) => OnFilterKeyPress(args, column))" value="@column.GetFilterValue()" type="text" placeholder="@column.GetFilterPlaceholder()" class="rz-textbox" style="width: 100%;" />
|
||||
@if (column.GetFilterValue() != null && filters.Any(d => d.Property == column.GetFilterProperty()))
|
||||
{
|
||||
<i @onclick="@((args) => ClearFilter(column))" class="notranslate rzi rz-cell-filter-clear" style="position:absolute;inset-inline-end:10px;">close</i>
|
||||
}
|
||||
}
|
||||
}
|
||||
</span>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
</text>
|
||||
};
|
||||
}
|
||||
|
||||
internal void SetAttribute(Dictionary<string, object> attributes, string attributeName, object attributeValue)
|
||||
{
|
||||
var separator = attributeName == "class" ? " " : ";";
|
||||
@@ -547,7 +597,7 @@
|
||||
<a id="@(GetId() + "exp")" aria-label="@ExpandChildItemAriaLabel" class="@(getExpandIconCssClass(this, Item))" style="@(getExpandIconStyle(this, Item, rowArgs.Item1.Expandable))" @onclick:preventDefault="true" @onclick="_ => this.ExpandItem(Item)" @onclick:stopPropagation="true">
|
||||
<span class="@(this.ExpandedItemStyle(Item))"></span>
|
||||
</a>
|
||||
<span class="rz-cell-data" @attributes="@spanAttributes">
|
||||
<span class="@column.GetCellClass()" @attributes="@spanAttributes">
|
||||
@if (Item != null)
|
||||
{
|
||||
@if (this.IsRowInEditMode(Item) && column.EditTemplate != null)
|
||||
@@ -568,12 +618,29 @@
|
||||
}
|
||||
else
|
||||
{
|
||||
<span class="rz-cell-data" @attributes="@spanAttributes">
|
||||
<span class="@column.GetCellClass()" @attributes="@spanAttributes">
|
||||
@if (Item != null)
|
||||
{
|
||||
@if ((column.IsInEditMode(column.Property, Item) || this.IsRowInEditMode(Item)) && column.EditTemplate is not null)
|
||||
@if (this.IsRowInEditMode(Item) && column.EditTemplate != null)
|
||||
{
|
||||
@column.EditTemplate(Item)
|
||||
var isDefault = column.IsInEditMode == RadzenDataGridColumn<TItem>.DefaultIsInEditMode;
|
||||
|
||||
@if(isDefault)
|
||||
{
|
||||
@column.EditTemplate(Item)
|
||||
}
|
||||
else if (column.IsInEditMode(column.Property, Item))
|
||||
{
|
||||
@column.EditTemplate(Item)
|
||||
}
|
||||
else if (column.Template != null)
|
||||
{
|
||||
@column.Template(Item)
|
||||
}
|
||||
else
|
||||
{
|
||||
@column.GetValue(Item)
|
||||
}
|
||||
}
|
||||
else if (column.Template != null)
|
||||
{
|
||||
|
||||
@@ -7,9 +7,7 @@ using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Collections.Specialized;
|
||||
using System.Data.Common;
|
||||
using System.Linq;
|
||||
using System.Linq.Dynamic.Core;
|
||||
using System.Text.Json;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
@@ -34,6 +32,23 @@ namespace Radzen.Blazor
|
||||
#endif
|
||||
public partial class RadzenDataGrid<TItem> : PagedDataBoundComponent<TItem>
|
||||
{
|
||||
/// <summary>
|
||||
/// Returns the validity of the DataGrid.
|
||||
/// </summary>
|
||||
/// <value><c>true</c> if all validators in the DataGrid a valid; otherwise, <c>false</c>.</value>
|
||||
public bool IsValid
|
||||
{
|
||||
get
|
||||
{
|
||||
if (!editContexts.Any())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return editContexts.All(c => !c.Value.GetValidationMessages().Any());
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether this instance is virtualized.
|
||||
/// </summary>
|
||||
@@ -140,13 +155,13 @@ namespace Radzen.Blazor
|
||||
|
||||
if (Groups.Any())
|
||||
{
|
||||
query = view.AsQueryable().OrderBy(DynamicLinqCustomTypeProvider.ParsingConfig, Groups.Any() ? string.Join(',', Groups.Select(g => $"{(typeof(TItem) == typeof(object) ? g.Property : "np(" + g.Property + ")")}")) : "it");
|
||||
_groupedPagedView = query.GroupByMany(DynamicLinqCustomTypeProvider.ParsingConfig, Groups.Any() ? Groups.Select(g => $"{(typeof(TItem) == typeof(object) ? g.Property : "np(" + g.Property + ")")}").ToArray() : new string[] { "it" }).ToList();
|
||||
query = view.AsQueryable().OrderBy(Groups.Any() ? string.Join(',', Groups.Select(g => g.Property)) : null);
|
||||
_groupedPagedView = await Task.FromResult(query.GroupByMany(Groups.Any() ? Groups.Select(g => g.Property).ToArray() : new string[] { "it" }).ToList());
|
||||
|
||||
totalItemsCount = await Task.FromResult(_groupedPagedView.Count());
|
||||
}
|
||||
|
||||
_view = Enumerable.Empty<TItem>().AsQueryable();
|
||||
_view = view;
|
||||
|
||||
return new Microsoft.AspNetCore.Components.Web.Virtualization.ItemsProviderResult<GroupResult>(_groupedPagedView.Any() ? _groupedPagedView.Skip(request.StartIndex).Take(top) : _groupedPagedView, totalItemsCount);
|
||||
}
|
||||
@@ -305,11 +320,20 @@ namespace Radzen.Blazor
|
||||
/// <value><c>true</c> if DataGrid data cells will follow the header cells structure in composite columns; otherwise, <c>false</c>.</value>
|
||||
[Parameter]
|
||||
public bool AllowCompositeDataCells { get; set; } = false;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether DataGrid data body show empty message.
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
public bool ShowEmptyMessage { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets value if headers are shown.
|
||||
/// </summary>
|
||||
/// <value>If headers are shown value.</value>
|
||||
[Parameter]
|
||||
public bool ShowHeader { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether DataGrid is responsive.
|
||||
/// </summary>
|
||||
@@ -339,9 +363,9 @@ namespace Radzen.Blazor
|
||||
if (_groupedPagedView == null)
|
||||
{
|
||||
var orderBy = GetOrderBy();
|
||||
var query = Groups.Count(g => g.SortOrder == null) == Groups.Count || !string.IsNullOrEmpty(orderBy) ? View : View.OrderBy(DynamicLinqCustomTypeProvider.ParsingConfig, string.Join(',', Groups.Select(g => $"{(typeof(TItem) == typeof(object) ? g.Property : "np(" + g.Property + ")")} {(g.SortOrder == null ? "" : g.SortOrder == SortOrder.Ascending ? " asc" : " desc")}")));
|
||||
var query = Groups.Count(g => g.SortOrder == null) == Groups.Count || !string.IsNullOrEmpty(orderBy) ? View : View.OrderBy(string.Join(',', Groups.Select(g => $"{g.Property} {(g.SortOrder == null ? "" : g.SortOrder == SortOrder.Ascending ? " asc" : " desc")}")));
|
||||
var v = (AllowPaging && !LoadData.HasDelegate ? query.Skip(skip).Take(PageSize) : query).ToList().AsQueryable();
|
||||
_groupedPagedView = v.GroupByMany(DynamicLinqCustomTypeProvider.ParsingConfig, Groups.Select(g => $"{(typeof(TItem) == typeof(object) ? g.Property : "np(" + g.Property + ")")}").ToArray()).ToList();
|
||||
_groupedPagedView = v.GroupByMany(Groups.Select(g => g.Property).ToArray()).ToList();
|
||||
}
|
||||
return _groupedPagedView;
|
||||
}
|
||||
@@ -654,11 +678,11 @@ namespace Radzen.Blazor
|
||||
}
|
||||
}
|
||||
|
||||
var descriptor = sorts.Where(d => d.Property == column?.GetSortProperty()).FirstOrDefault();
|
||||
var descriptor = Sorts.Where(d => d.Property == column?.GetSortProperty()).FirstOrDefault();
|
||||
if (descriptor == null && column.SortOrder.HasValue)
|
||||
{
|
||||
descriptor = new SortDescriptor() { Property = column.GetSortProperty(), SortOrder = column.SortOrder.Value };
|
||||
sorts.Add(descriptor);
|
||||
Sorts.Add(descriptor);
|
||||
}
|
||||
|
||||
if (!allColumns.Contains(column))
|
||||
@@ -760,7 +784,7 @@ namespace Radzen.Blazor
|
||||
[Parameter]
|
||||
public EventCallback<DataGridPickedColumnsChangedEventArgs<TItem>> PickedColumnsChanged { get; set; }
|
||||
|
||||
string getFilterInputId(RadzenDataGridColumn<TItem> column)
|
||||
internal string getFilterInputId(RadzenDataGridColumn<TItem> column)
|
||||
{
|
||||
return string.Join("", $"{UniqueID}".Split('.')) + column.GetFilterProperty();
|
||||
}
|
||||
@@ -790,6 +814,7 @@ namespace Radzen.Blazor
|
||||
builder.AddAttribute(2, "ShowUpDown", column.ShowUpDownForNumericFilter());
|
||||
builder.AddAttribute(3, "Style", "width:100%");
|
||||
builder.AddAttribute(4, "InputAttributes", new Dictionary<string,object>(){ { "aria-label", column.Title + $"{(!isFirst ? " second " : " ")}filter value " + (isFirst ? column.GetFilterValue() : column.GetSecondFilterValue()) } });
|
||||
builder.AddAttribute(5, "id", getFilterInputId(column) + (isFirst ? "f" : "s"));
|
||||
|
||||
Action<object> action;
|
||||
if (force)
|
||||
@@ -807,34 +832,7 @@ namespace Radzen.Blazor
|
||||
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}";
|
||||
object filterValue = null;
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(value))
|
||||
{
|
||||
try
|
||||
{
|
||||
filterValue = Convert.ChangeType(value, Nullable.GetUnderlyingType(type));
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
filterValue = null;
|
||||
}
|
||||
}
|
||||
|
||||
column.SetFilterValue(filterValue, isFirst);
|
||||
SaveSettings();
|
||||
}));
|
||||
builder.AddAttribute(5, "Disabled", !column.CanSetFilterValue());
|
||||
}
|
||||
else if (FilterMode == FilterMode.SimpleWithMenu)
|
||||
{
|
||||
builder.AddAttribute(4, "Disabled", !column.CanSetFilterValue());
|
||||
}
|
||||
builder.AddAttribute(4, "Disabled", !column.CanSetFilterValue());
|
||||
|
||||
builder.CloseComponent();
|
||||
});
|
||||
@@ -1253,6 +1251,20 @@ namespace Radzen.Blazor
|
||||
[Parameter]
|
||||
public string DoesNotContainText { get; set; } = "Does not contain";
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the in operator text.
|
||||
/// </summary>
|
||||
/// <value>The in operator text.</value>
|
||||
[Parameter]
|
||||
public string InText { get; set; } = "In";
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the not in operator text.
|
||||
/// </summary>
|
||||
/// <value>The not in operator text.</value>
|
||||
[Parameter]
|
||||
public string NotInText { get; set; } = "Not in";
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the starts with text.
|
||||
/// </summary>
|
||||
@@ -1288,6 +1300,13 @@ namespace Radzen.Blazor
|
||||
[Parameter]
|
||||
public string IsNotEmptyText { get; set; } = "Is not empty";
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the custom filter operator text.
|
||||
/// </summary>
|
||||
/// <value>The custom filter operator text.</value>
|
||||
[Parameter]
|
||||
public string CustomText { get; set; } = "Custom";
|
||||
|
||||
internal class NumericFilterEventCallback
|
||||
{
|
||||
public static EventCallback<T> Create<T>(object receiver, Action<T> action)
|
||||
@@ -1471,49 +1490,49 @@ namespace Radzen.Blazor
|
||||
/// </summary>
|
||||
/// <value>The remove group button aria label text.</value>
|
||||
[Parameter]
|
||||
public string RemoveGroupArialLabel { get; set; } = "Remove group";
|
||||
public string RemoveGroupAriaLabel { get; set; } = "Remove group";
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the select visible columns aria label text.
|
||||
/// </summary>
|
||||
/// <value>The select visible columns aria label text.</value>
|
||||
[Parameter]
|
||||
public string SelectVisibleColumnsArialLabel { get; set; } = "select visible columns";
|
||||
public string SelectVisibleColumnsAriaLabel { get; set; } = "select visible columns";
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the column logical filter value aria label text.
|
||||
/// </summary>
|
||||
/// <value>The the column logical filter value aria label text.</value>
|
||||
[Parameter]
|
||||
public string LogicalOperatorArialLabel { get; set; } = " logical filter operator ";
|
||||
public string LogicalOperatorAriaLabel { get; set; } = " logical filter operator ";
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the column filter value aria label text.
|
||||
/// </summary>
|
||||
/// <value>The the column filter value aria label text.</value>
|
||||
[Parameter]
|
||||
public string FilterOperatorArialLabel { get; set; } = " filter operator ";
|
||||
public string FilterOperatorAriaLabel { get; set; } = " filter operator ";
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the column filter value aria label text.
|
||||
/// </summary>
|
||||
/// <value>The the column filter value aria label text.</value>
|
||||
[Parameter]
|
||||
public string SecondFilterOperatorArialLabel { get; set; } = " second filter operator ";
|
||||
public string SecondFilterOperatorAriaLabel { get; set; } = " second filter operator ";
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the column filter value aria label text.
|
||||
/// </summary>
|
||||
/// <value>The the column filter value aria label text.</value>
|
||||
[Parameter]
|
||||
public string FilterValueArialLabel { get; set; } = " filter value ";
|
||||
public string FilterValueAriaLabel { get; set; } = " filter value ";
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the column filter value aria label text.
|
||||
/// </summary>
|
||||
/// <value>The the column filter value aria label text.</value>
|
||||
[Parameter]
|
||||
public string SecondFilterValueArialLabel { get; set; } = " second filter value ";
|
||||
public string SecondFilterValueAriaLabel { get; set; } = " second filter value ";
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether user can pick all columns in column picker.
|
||||
@@ -1587,10 +1606,12 @@ namespace Radzen.Blazor
|
||||
}
|
||||
|
||||
int? indexOfColumnToReoder;
|
||||
string uniqueIDOfColumnToReoder;
|
||||
|
||||
internal async Task StartColumnReorder(MouseEventArgs args, int columnIndex)
|
||||
internal async Task StartColumnReorder(MouseEventArgs args, int columnIndex, string uniqueID)
|
||||
{
|
||||
indexOfColumnToReoder = columnIndex;
|
||||
uniqueIDOfColumnToReoder = uniqueID;
|
||||
await JSRuntime.InvokeVoidAsync("Radzen.startColumnReorder", getColumnUniqueId(columnIndex));
|
||||
}
|
||||
|
||||
@@ -1664,7 +1685,16 @@ namespace Radzen.Blazor
|
||||
|
||||
internal string GetOrderBy()
|
||||
{
|
||||
return string.Join(",", sorts.Select(d => allColumns.ToList().Where(c => c.GetSortProperty() == d.Property).FirstOrDefault()).Where(c => c != null).Select(c => c.GetSortOrderAsString(IsOData())));
|
||||
return string.Join(",", Sorts.Select(d => GetSortOrderAsString(d, IsOData())));
|
||||
}
|
||||
|
||||
internal string GetSortOrderAsString(SortDescriptor d, bool isOData)
|
||||
{
|
||||
var property = d.Property;
|
||||
if (string.IsNullOrEmpty(property))
|
||||
return "";
|
||||
var p = isOData ? property.Replace('.', '/') : PropertyAccess.GetProperty(property);
|
||||
return $"{p} {(d.SortOrder == Radzen.SortOrder.Ascending ? "asc" : "desc")}";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -1697,12 +1727,12 @@ namespace Radzen.Blazor
|
||||
var firstItem = view.FirstOrDefault();
|
||||
if (firstItem != null)
|
||||
{
|
||||
view = view.Cast(firstItem.GetType()).AsQueryable().OrderBy(orderBy).Cast<TItem>();
|
||||
view = QueryableExtension.Cast(view, firstItem.GetType()).AsQueryable().OrderBy(orderBy).Cast<TItem>();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
view = view.OrderBy(orderBy);
|
||||
view = view.OrderBy<TItem>(orderBy);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1728,7 +1758,7 @@ namespace Radzen.Blazor
|
||||
var cd = childData[item].Data.AsQueryable();
|
||||
if (!string.IsNullOrEmpty(orderBy))
|
||||
{
|
||||
cd = cd.OrderBy(orderBy);
|
||||
cd = cd.OrderBy<TItem>(orderBy);
|
||||
}
|
||||
|
||||
viewList.InsertRange(viewList.IndexOf(item) + 1, cd);
|
||||
@@ -1783,7 +1813,8 @@ namespace Radzen.Blazor
|
||||
var firstItem = view.FirstOrDefault();
|
||||
if (firstItem != null)
|
||||
{
|
||||
view = view.Cast(firstItem.GetType()).AsQueryable().OrderBy(orderBy).Cast<TItem>();
|
||||
view = QueryableExtension.Cast(view, firstItem.GetType());
|
||||
view = view.OrderBy(orderBy).Cast<TItem>();
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -2040,7 +2071,8 @@ namespace Radzen.Blazor
|
||||
c.SetVisible(null);
|
||||
});
|
||||
selectedColumns = allColumns.Where(c => c.Pickable && c.GetVisible()).ToList();
|
||||
sorts.Clear();
|
||||
Sorts.Clear();
|
||||
columns = allColumns.Where(c => c.Parent == null).ToList();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2152,7 +2184,7 @@ namespace Radzen.Blazor
|
||||
.ToList();
|
||||
|
||||
Query.Filters = filters;
|
||||
Query.Sorts = sorts;
|
||||
Query.Sorts = Sorts.ToList();
|
||||
if (LoadData.HasDelegate)
|
||||
{
|
||||
await LoadData.InvokeAsync(new Radzen.LoadDataArgs()
|
||||
@@ -2162,7 +2194,7 @@ namespace Radzen.Blazor
|
||||
OrderBy = orderBy,
|
||||
Filter = IsOData() ? allColumns.ToList().ToODataFilterString<TItem>() : filterString,
|
||||
Filters = filters,
|
||||
Sorts = sorts
|
||||
Sorts = Sorts.ToList()
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -2176,25 +2208,25 @@ namespace Radzen.Blazor
|
||||
/// Called when parameters set asynchronous.
|
||||
/// </summary>
|
||||
/// <returns>Task.</returns>
|
||||
protected override Task OnParametersSetAsync()
|
||||
protected override async Task OnParametersSetAsync()
|
||||
{
|
||||
if (Visible && !LoadData.HasDelegate && _view == null)
|
||||
{
|
||||
InvokeAsync(Reload);
|
||||
await InvokeAsync(Reload);
|
||||
}
|
||||
else
|
||||
{
|
||||
CalculatePager();
|
||||
}
|
||||
|
||||
return Task.CompletedTask;
|
||||
await Task.CompletedTask;
|
||||
}
|
||||
|
||||
internal Dictionary<RadzenDataGridGroupRow<TItem>, bool> collapsedGroupItems = new Dictionary<RadzenDataGridGroupRow<TItem>, bool>();
|
||||
|
||||
internal string ExpandedGroupItemStyle(RadzenDataGridGroupRow<TItem> item, bool? expandedOnLoad)
|
||||
{
|
||||
return collapsedGroupItems.Keys.Contains(item) || expandedOnLoad == false ? "rz-row-toggler rzi-grid-sort rzi-chevron-circle-right" : "rz-row-toggler rzi-grid-sort rzi-chevron-circle-down";
|
||||
return collapsedGroupItems.Keys.Contains(item) || expandedOnLoad == false ? "notranslate rz-row-toggler rzi-grid-sort rzi-chevron-circle-right" : "rz-row-toggler rzi-grid-sort rzi-chevron-circle-down";
|
||||
}
|
||||
|
||||
internal bool IsGroupItemExpanded(RadzenDataGridGroupRow<TItem> item)
|
||||
@@ -2266,7 +2298,7 @@ namespace Radzen.Blazor
|
||||
|
||||
internal string ExpandedItemStyle(TItem item)
|
||||
{
|
||||
return expandedItems.Keys.Any(i => ItemEquals(i, item)) ? "rz-row-toggler rzi-chevron-circle-down" : "rz-row-toggler rzi-chevron-circle-right";
|
||||
return expandedItems.Keys.Any(i => ItemEquals(i, item)) ? "notranslate rz-row-toggler rzi-chevron-circle-down" : "rz-row-toggler rzi-chevron-circle-right";
|
||||
}
|
||||
|
||||
internal Dictionary<TItem, bool> selectedItems = new Dictionary<TItem, bool>();
|
||||
@@ -2278,9 +2310,9 @@ namespace Radzen.Blazor
|
||||
return (RowSelect.HasDelegate || ValueChanged.HasDelegate || SelectionMode == DataGridSelectionMode.Multiple) && selectedItems.Keys.Any(i => ItemEquals(i, item)) ? $"rz-state-highlight rz-data-row {isInEditMode} " : $"rz-data-row {isInEditMode} ";
|
||||
}
|
||||
|
||||
internal Tuple<Radzen.RowRenderEventArgs<TItem>, IReadOnlyDictionary<string, object>> RowAttributes(TItem item)
|
||||
internal Tuple<Radzen.RowRenderEventArgs<TItem>, IReadOnlyDictionary<string, object>> RowAttributes(TItem item, int index)
|
||||
{
|
||||
var args = new Radzen.RowRenderEventArgs<TItem>() { Data = item, Expandable = Template != null || LoadChildData.HasDelegate };
|
||||
var args = new Radzen.RowRenderEventArgs<TItem>() { Data = item, Index = index, Expandable = Template != null || LoadChildData.HasDelegate };
|
||||
|
||||
if (RowRender != null)
|
||||
{
|
||||
@@ -2390,6 +2422,17 @@ namespace Radzen.Blazor
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Force load of the DataGrid Settings.
|
||||
/// </summary>
|
||||
public async Task ReloadSettings()
|
||||
{
|
||||
if (settings != null)
|
||||
{
|
||||
await LoadSettingsInternal(settings);
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override async Task OnAfterRenderAsync(bool firstRender)
|
||||
{
|
||||
@@ -2934,23 +2977,40 @@ namespace Radzen.Blazor
|
||||
/// </summary>
|
||||
/// <param name="item">The item.</param>
|
||||
public async System.Threading.Tasks.Task InsertRow(TItem item)
|
||||
{
|
||||
await InsertRowAtIndex(item);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Inserts new row after specific row item.
|
||||
/// </summary>
|
||||
/// <param name="itemToInsert">The item.</param>
|
||||
/// <param name="rowItem">Row item to insert after</param>
|
||||
public async System.Threading.Tasks.Task InsertAfterRow(TItem itemToInsert, TItem rowItem)
|
||||
{
|
||||
var list = this.PagedView.ToList();
|
||||
var index = list.IndexOf(rowItem);
|
||||
await InsertRowAtIndex(itemToInsert, index + 1);
|
||||
}
|
||||
|
||||
private async System.Threading.Tasks.Task InsertRowAtIndex(TItem item, int insertIndex = 0)
|
||||
{
|
||||
itemsToInsert.Add(item);
|
||||
if(!IsVirtualizationAllowed())
|
||||
if (!IsVirtualizationAllowed())
|
||||
{
|
||||
var list = this.PagedView.ToList();
|
||||
list.Insert(0, item);
|
||||
list.Insert(insertIndex, item);
|
||||
this._view = list.AsQueryable();
|
||||
this.Count++;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(virtualize != null)
|
||||
if (virtualize != null)
|
||||
{
|
||||
await virtualize.RefreshDataAsync();
|
||||
}
|
||||
|
||||
if(groupVirtualize != null)
|
||||
if (groupVirtualize != null)
|
||||
{
|
||||
await groupVirtualize.RefreshDataAsync();
|
||||
}
|
||||
@@ -2972,48 +3032,46 @@ namespace Radzen.Blazor
|
||||
return isOData != null ? isOData.Value : false;
|
||||
}
|
||||
|
||||
internal List<SortDescriptor> sorts = new List<SortDescriptor>();
|
||||
|
||||
internal void SetColumnSortOrder(RadzenDataGridColumn<TItem> column)
|
||||
{
|
||||
var CurrentSortDescriptor = Sorts.FirstOrDefault(d => d.Property == column?.GetSortProperty());
|
||||
if (!AllowMultiColumnSorting)
|
||||
{
|
||||
foreach (var c in allColumns.ToList().Where(c => c != column))
|
||||
{
|
||||
c.SetSortOrderInternal(null);
|
||||
}
|
||||
sorts.Clear();
|
||||
Sorts.Clear();
|
||||
}
|
||||
|
||||
var descriptor = sorts.Where(d => d.Property == column?.GetSortProperty()).FirstOrDefault();
|
||||
if (descriptor == null)
|
||||
if (CurrentSortDescriptor == null)
|
||||
{
|
||||
descriptor = new SortDescriptor() { Property = column.GetSortProperty() };
|
||||
CurrentSortDescriptor = new SortDescriptor() { Property = column.GetSortProperty() };
|
||||
}
|
||||
|
||||
if (column.GetSortOrder() == null)
|
||||
if (CurrentSortDescriptor.SortOrder == null)
|
||||
{
|
||||
column.SetSortOrderInternal(SortOrder.Ascending);
|
||||
descriptor.SortOrder = SortOrder.Ascending;
|
||||
CurrentSortDescriptor.SortOrder = SortOrder.Ascending;
|
||||
}
|
||||
else if (column.GetSortOrder() == SortOrder.Ascending)
|
||||
else if (CurrentSortDescriptor.SortOrder == SortOrder.Ascending)
|
||||
{
|
||||
column.SetSortOrderInternal(SortOrder.Descending);
|
||||
descriptor.SortOrder = SortOrder.Descending;
|
||||
CurrentSortDescriptor.SortOrder = SortOrder.Descending;
|
||||
}
|
||||
else if (column.GetSortOrder() == SortOrder.Descending)
|
||||
else if (CurrentSortDescriptor.SortOrder == SortOrder.Descending)
|
||||
{
|
||||
column.SetSortOrderInternal(null);
|
||||
if (sorts.Where(d => d.Property == column?.GetSortProperty()).Any())
|
||||
if (Sorts.Any(d => d.Property == column?.GetSortProperty()))
|
||||
{
|
||||
sorts.Remove(descriptor);
|
||||
Sorts.Remove(CurrentSortDescriptor);
|
||||
}
|
||||
descriptor = null;
|
||||
CurrentSortDescriptor = null;
|
||||
}
|
||||
|
||||
if (descriptor != null && !sorts.Where(d => d.Property == column?.GetSortProperty()).Any())
|
||||
if (CurrentSortDescriptor != null && !Sorts.Any(d => d.Property == column?.GetSortProperty()))
|
||||
{
|
||||
sorts.Add(descriptor);
|
||||
Sorts.Add(CurrentSortDescriptor);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3022,14 +3080,14 @@ namespace Radzen.Blazor
|
||||
if (args.Action == NotifyCollectionChangedAction.Add)
|
||||
{
|
||||
RadzenDataGridColumn<TItem> column;
|
||||
column = columns.Where(c => c.GetGroupProperty() == ((GroupDescriptor)args.NewItems[0]).Property).FirstOrDefault();
|
||||
column = columns.FirstOrDefault(c => c.GetGroupProperty() == ((GroupDescriptor)args.NewItems[0]).Property);
|
||||
|
||||
if(column == null)
|
||||
{
|
||||
column = allColumns.Where(c => c.GetGroupProperty() == ((GroupDescriptor)args.NewItems[0]).Property).FirstOrDefault();
|
||||
column = allColumns.FirstOrDefault(c => c.GetGroupProperty() == ((GroupDescriptor)args.NewItems[0]).Property);
|
||||
}
|
||||
|
||||
if (HideGroupedColumn)
|
||||
if (column != null && HideGroupedColumn)
|
||||
{
|
||||
column.SetVisible(false);
|
||||
if (!groupedColumns.Contains(column))
|
||||
@@ -3041,14 +3099,14 @@ namespace Radzen.Blazor
|
||||
else if (args.Action == NotifyCollectionChangedAction.Remove)
|
||||
{
|
||||
RadzenDataGridColumn<TItem> column;
|
||||
column = columns.Where(c => c.GetGroupProperty() == ((GroupDescriptor)args.OldItems[0]).Property).FirstOrDefault();
|
||||
column = columns.FirstOrDefault(c => c.GetGroupProperty() == ((GroupDescriptor)args.OldItems[0]).Property);
|
||||
|
||||
if (column == null)
|
||||
{
|
||||
column = allColumns.Where(c => c.GetGroupProperty() == ((GroupDescriptor)args.OldItems[0]).Property).FirstOrDefault();
|
||||
column = allColumns.FirstOrDefault(c => c.GetGroupProperty() == ((GroupDescriptor)args.OldItems[0]).Property);
|
||||
}
|
||||
|
||||
if (HideGroupedColumn)
|
||||
if (column != null && HideGroupedColumn)
|
||||
{
|
||||
column.SetVisible(true);
|
||||
if (groupedColumns.Contains(column))
|
||||
@@ -3099,18 +3157,12 @@ namespace Radzen.Blazor
|
||||
|
||||
internal async Task EndColumnDropToGroup()
|
||||
{
|
||||
if(indexOfColumnToReoder != null && AllowGrouping)
|
||||
if(indexOfColumnToReoder != null && uniqueIDOfColumnToReoder != null && AllowGrouping)
|
||||
{
|
||||
var functionName = $"Radzen['{getColumnUniqueId(indexOfColumnToReoder.Value)}end']";
|
||||
await JSRuntime.InvokeVoidAsync("eval", $"{functionName} && {functionName}()");
|
||||
|
||||
RadzenDataGridColumn<TItem> column;
|
||||
|
||||
column = columns.Where(c => c.GetVisible()).ElementAtOrDefault(indexOfColumnToReoder.Value);
|
||||
|
||||
//may be its a child column
|
||||
if (column == null)
|
||||
column = allColumns.Where(c => c.GetVisible()).ElementAtOrDefault(indexOfColumnToReoder.Value);
|
||||
var column = allColumns.Where(c => (c.UniqueID ?? c.Property) == uniqueIDOfColumnToReoder).FirstOrDefault();
|
||||
|
||||
if (column != null && column.Groupable && !string.IsNullOrEmpty(column.GetGroupProperty()))
|
||||
{
|
||||
@@ -3131,6 +3183,7 @@ namespace Radzen.Blazor
|
||||
}
|
||||
|
||||
indexOfColumnToReoder = null;
|
||||
uniqueIDOfColumnToReoder = null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3330,9 +3383,9 @@ namespace Radzen.Blazor
|
||||
public EventCallback<int> PageSizeChanged { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets DataGrid settings as JSON string.
|
||||
/// Saves DataGrid settings as JSON string.
|
||||
/// </summary>
|
||||
internal void SaveSettings()
|
||||
public void SaveSettings()
|
||||
{
|
||||
if (SettingsChanged.HasDelegate && canSaveSettings)
|
||||
{
|
||||
|
||||
@@ -5,7 +5,6 @@ using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Linq.Dynamic.Core;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Radzen.Blazor
|
||||
@@ -75,6 +74,8 @@ namespace Radzen.Blazor
|
||||
}
|
||||
}
|
||||
|
||||
internal IEnumerable<RadzenDataGridColumn<TItem>> VisibleColumns => ColumnsCollection.Where(c => c.GetVisible());
|
||||
|
||||
internal int GetLevel()
|
||||
{
|
||||
int i = 0;
|
||||
@@ -93,11 +94,11 @@ namespace Radzen.Blazor
|
||||
if (!Grid.AllowCompositeDataCells && isDataCell || Columns == null)
|
||||
return 1;
|
||||
|
||||
var span = ColumnsCollection.Concat(ColumnsCollection.SelectManyRecursive(c => c.ColumnsCollection)).Sum(c => c.ColumnsCollection.Count())
|
||||
- ColumnsCollection.SelectManyRecursive(c => c.ColumnsCollection).Count(c => c.ColumnsCollection.Any())
|
||||
+ ColumnsCollection.Where(c => c.ColumnsCollection.Count() == 0).Count();
|
||||
var span = VisibleColumns.Concat(VisibleColumns.SelectManyRecursive(c => c.VisibleColumns)).Sum(c => c.VisibleColumns.Count())
|
||||
- VisibleColumns.SelectManyRecursive(c => c.VisibleColumns).Count(c => c.VisibleColumns.Any())
|
||||
+ VisibleColumns.Where(c => c.VisibleColumns.Count() == 0).Count();
|
||||
|
||||
return span != 0 ? span : ColumnsCollection.Count;
|
||||
return span != 0 ? span : VisibleColumns.Count();
|
||||
}
|
||||
|
||||
internal int GetRowSpan(bool isDataCell = false)
|
||||
@@ -139,7 +140,11 @@ namespace Radzen.Blazor
|
||||
{
|
||||
if (Type == null)
|
||||
{
|
||||
_filterPropertyType = typeof(IEnumerable<object>);
|
||||
var fp = GetFilterProperty();
|
||||
var pt = !string.IsNullOrEmpty(fp) ?
|
||||
PropertyAccess.GetPropertyType(typeof(TItem), fp) : typeof(object);
|
||||
|
||||
_filterPropertyType = typeof(IEnumerable<>).MakeGenericType(pt);
|
||||
}
|
||||
|
||||
if (GetFilterOperator() == FilterOperator.Equals)
|
||||
@@ -171,13 +176,13 @@ namespace Radzen.Blazor
|
||||
propertyValueGetter = PropertyAccess.Getter<TItem, object>(Property);
|
||||
}
|
||||
|
||||
if (_filterPropertyType == typeof(string) && filterOperator != FilterOperator.Custom && filterOperator == null)
|
||||
if (_filterPropertyType == typeof(string) && filterOperator != FilterOperator.Custom && filterOperator == null && _filterOperator == null)
|
||||
{
|
||||
SetFilterOperator(FilterOperator.Contains);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int? orderIndex;
|
||||
|
||||
/// <summary>
|
||||
@@ -242,6 +247,11 @@ namespace Radzen.Blazor
|
||||
/// <returns>System.Boolean.</returns>
|
||||
public bool GetVisible()
|
||||
{
|
||||
if (Columns != null && ColumnsCollection.Any() && VisibleColumns.Count() == 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return _visible ?? Visible;
|
||||
}
|
||||
|
||||
@@ -381,6 +391,14 @@ namespace Radzen.Blazor
|
||||
[Parameter]
|
||||
public string MinWidth { get; set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the max-width.
|
||||
/// </summary>
|
||||
/// <value>The max-width.</value>
|
||||
[Parameter]
|
||||
public string MaxWidth { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the format string.
|
||||
/// </summary>
|
||||
@@ -423,6 +441,18 @@ namespace Radzen.Blazor
|
||||
[Parameter]
|
||||
public string GroupFooterCssClass { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the header white space style.
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
public WhiteSpace HeaderWhiteSpace { get; set; } = WhiteSpace.Truncate;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the white space style.
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
public WhiteSpace WhiteSpace { get; set; } = WhiteSpace.Truncate;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether this <see cref="RadzenDataGridColumn{TItem}"/> is filterable.
|
||||
/// </summary>
|
||||
@@ -504,7 +534,9 @@ namespace Radzen.Blazor
|
||||
/// Allows the column to override whether or not this column's the <see cref="EditTemplate" /> is visible at runtime.
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
public Func<string, TItem, bool> IsInEditMode { get; set; } = (property, item) => false;
|
||||
public Func<string, TItem, bool> IsInEditMode { get; set; } = DefaultIsInEditMode;
|
||||
|
||||
internal static Func<string, TItem, bool> DefaultIsInEditMode { get; set; } = (property, item) => false;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the header template.
|
||||
@@ -648,6 +680,11 @@ namespace Radzen.Blazor
|
||||
style.Add($"min-width:{MinWidth}");
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(MaxWidth))
|
||||
{
|
||||
style.Add($"max-width:{MaxWidth}");
|
||||
}
|
||||
|
||||
return string.Join(";", style);
|
||||
}
|
||||
|
||||
@@ -725,18 +762,9 @@ namespace Radzen.Blazor
|
||||
}
|
||||
}
|
||||
|
||||
internal string GetSortOrderAsString(bool isOData)
|
||||
{
|
||||
var property = GetSortProperty();
|
||||
if (string.IsNullOrEmpty(property))
|
||||
return "";
|
||||
var p = isOData ? property.Replace('.', '/') : PropertyAccess.GetProperty(property);
|
||||
return $"{p} {(GetSortOrder() == Radzen.SortOrder.Ascending ? "asc" : "desc")}";
|
||||
}
|
||||
|
||||
internal void SetSortOrder(SortOrder? order)
|
||||
{
|
||||
var descriptor = Grid.sorts.Where(d => d.Property == GetSortProperty()).FirstOrDefault();
|
||||
var descriptor = Grid.Sorts.Where(d => d.Property == GetSortProperty()).FirstOrDefault();
|
||||
if (descriptor == null)
|
||||
{
|
||||
descriptor = new SortDescriptor() { Property = GetSortProperty() };
|
||||
@@ -750,16 +778,16 @@ namespace Radzen.Blazor
|
||||
else
|
||||
{
|
||||
SetSortOrderInternal(null);
|
||||
if (Grid.sorts.Where(d => d.Property == GetSortProperty()).Any())
|
||||
if (Grid.Sorts.Where(d => d.Property == GetSortProperty()).Any())
|
||||
{
|
||||
Grid.sorts.Remove(descriptor);
|
||||
Grid.Sorts.Remove(descriptor);
|
||||
}
|
||||
descriptor = null;
|
||||
}
|
||||
|
||||
if (descriptor != null && !Grid.sorts.Where(d => d.Property == GetSortProperty()).Any())
|
||||
if (descriptor != null && !Grid.Sorts.Where(d => d.Property == GetSortProperty()).Any())
|
||||
{
|
||||
Grid.sorts.Add(descriptor);
|
||||
Grid.Sorts.Add(descriptor);
|
||||
}
|
||||
|
||||
sortOrder = new SortOrder?[] { order };
|
||||
@@ -879,10 +907,10 @@ namespace Radzen.Blazor
|
||||
|
||||
if (Grid != null)
|
||||
{
|
||||
var descriptor = Grid.sorts.Where(d => d.Property == GetSortProperty()).FirstOrDefault();
|
||||
var descriptor = Grid.Sorts.Where(d => d.Property == GetSortProperty()).FirstOrDefault();
|
||||
if (descriptor == null)
|
||||
{
|
||||
Grid.sorts.Add(new SortDescriptor() { Property = GetSortProperty(), SortOrder = sortOrder.FirstOrDefault() });
|
||||
Grid.Sorts.Add(new SortDescriptor() { Property = GetSortProperty(), SortOrder = sortOrder.FirstOrDefault() });
|
||||
Grid._view = null;
|
||||
}
|
||||
}
|
||||
@@ -892,7 +920,7 @@ namespace Radzen.Blazor
|
||||
{
|
||||
filterValue = parameters.GetValueOrDefault<object>(nameof(FilterValue));
|
||||
|
||||
if (FilterTemplate != null)
|
||||
if (FilterTemplate != null || FilterValueTemplate != null)
|
||||
{
|
||||
FilterValue = filterValue;
|
||||
Grid.SaveSettings();
|
||||
@@ -916,7 +944,7 @@ namespace Radzen.Blazor
|
||||
{
|
||||
secondFilterValue = parameters.GetValueOrDefault<object>(nameof(SecondFilterValue));
|
||||
|
||||
if (FilterTemplate != null)
|
||||
if (FilterTemplate != null || SecondFilterValueTemplate != null)
|
||||
{
|
||||
SecondFilterValue = secondFilterValue;
|
||||
Grid.SaveSettings();
|
||||
@@ -960,7 +988,7 @@ namespace Radzen.Blazor
|
||||
}
|
||||
}
|
||||
|
||||
if (parameters.DidParameterChange(nameof(FilterOperator), FilterOperator) || _filterOperator != null)
|
||||
if (filterOperator == null && (parameters.DidParameterChange(nameof(FilterOperator), FilterOperator) || _filterOperator != null))
|
||||
{
|
||||
filterOperator = _filterOperator ?? parameters.GetValueOrDefault<FilterOperator>(nameof(FilterOperator));
|
||||
}
|
||||
@@ -1039,6 +1067,24 @@ namespace Radzen.Blazor
|
||||
return logicalFilterOperator ?? LogicalFilterOperator;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get body column class.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
internal string GetCellClass()
|
||||
{
|
||||
return $"rz-cell-data rz-text-{Enum.GetName(typeof(WhiteSpace), WhiteSpace).ToLower()}";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get column header class.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
internal string GetHeaderClass()
|
||||
{
|
||||
return $"rz-column-title-content rz-text-{Enum.GetName(typeof(WhiteSpace), HeaderWhiteSpace).ToLower()}";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Set column filter value.
|
||||
/// </summary>
|
||||
@@ -1050,14 +1096,27 @@ namespace Radzen.Blazor
|
||||
value = offset;
|
||||
}
|
||||
|
||||
if (PropertyAccess.IsEnum(FilterPropertyType) || (PropertyAccess.IsNullableEnum(FilterPropertyType)))
|
||||
if ((FilterPropertyType == typeof(TimeOnly) || FilterPropertyType == typeof(TimeOnly?)) && value != null && value is string)
|
||||
{
|
||||
value = value is not null ? (int)value : null;
|
||||
var v = TimeOnly.Parse($"{value}");
|
||||
value = FilterPropertyType == typeof(TimeOnly) ? v : (TimeOnly?)v;
|
||||
}
|
||||
|
||||
if ((FilterPropertyType == typeof(Guid) || FilterPropertyType == typeof(Guid?)) && value != null && value is string)
|
||||
{
|
||||
var v = Guid.Parse($"{value}");
|
||||
value = FilterPropertyType == typeof(Guid) ? v : (Guid?)v;
|
||||
}
|
||||
|
||||
if (!QueryableExtension.IsEnumerable(value?.GetType() ?? typeof(object)) && (PropertyAccess.IsEnum(FilterPropertyType) || (PropertyAccess.IsNullableEnum(FilterPropertyType))))
|
||||
{
|
||||
Type enumType = Enum.GetUnderlyingType(Nullable.GetUnderlyingType(FilterPropertyType) ?? FilterPropertyType);
|
||||
value = value is not null ? Convert.ChangeType(value, enumType) : null;
|
||||
}
|
||||
|
||||
if (isFirst)
|
||||
{
|
||||
filterValue = CanSetCurrentValue(value) ? value :
|
||||
filterValue = CanSetCurrentValue(value) ? value :
|
||||
GetFilterOperator() == FilterOperator.IsEmpty || GetFilterOperator() == FilterOperator.IsNotEmpty ? string.Empty : null;
|
||||
}
|
||||
else
|
||||
@@ -1138,21 +1197,22 @@ namespace Radzen.Blazor
|
||||
/// </summary>
|
||||
public void ClearFilters()
|
||||
{
|
||||
ClearFilterValues();
|
||||
SetFilterValue(null);
|
||||
SetFilterValue(null, false);
|
||||
SetFilterOperator(null);
|
||||
SetSecondFilterOperator(null);
|
||||
|
||||
FilterValue = null;
|
||||
SecondFilterValue = null;
|
||||
FilterOperator = FilterOperator == FilterOperator.Custom
|
||||
var fo = FilterOperator == FilterOperator.Custom
|
||||
? FilterOperator.Custom
|
||||
: typeof(System.Collections.IEnumerable).IsAssignableFrom(FilterPropertyType)
|
||||
? !string.IsNullOrEmpty(FilterProperty) && FilterProperty != Property ? FilterOperator.In : FilterOperator.Contains
|
||||
: default(FilterOperator);
|
||||
SecondFilterOperator = default(FilterOperator);
|
||||
|
||||
SetFilterOperator(fo);
|
||||
SetSecondFilterOperator(null);
|
||||
|
||||
filterValue = null;
|
||||
secondFilterValue = null;
|
||||
|
||||
ClearFilterValues();
|
||||
|
||||
LogicalFilterOperator = default(LogicalFilterOperator);
|
||||
|
||||
}
|
||||
|
||||
FilterOperator? _filterOperator;
|
||||
@@ -1161,7 +1221,7 @@ namespace Radzen.Blazor
|
||||
/// </summary>
|
||||
/// <value>The filter operator.</value>
|
||||
[Parameter]
|
||||
public FilterOperator FilterOperator
|
||||
public FilterOperator FilterOperator
|
||||
{
|
||||
get
|
||||
{
|
||||
@@ -1173,6 +1233,24 @@ namespace Radzen.Blazor
|
||||
}
|
||||
}
|
||||
|
||||
IEnumerable<FilterOperator> _filterOperators;
|
||||
/// <summary>
|
||||
/// Gets or sets the filter operators.
|
||||
/// </summary>
|
||||
/// <value>The filter operators.</value>
|
||||
[Parameter]
|
||||
public IEnumerable<FilterOperator> FilterOperators
|
||||
{
|
||||
get
|
||||
{
|
||||
return _filterOperators;
|
||||
}
|
||||
set
|
||||
{
|
||||
_filterOperators = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the second filter operator.
|
||||
/// </summary>
|
||||
@@ -1264,6 +1342,8 @@ namespace Radzen.Blazor
|
||||
/// </summary>
|
||||
public virtual IEnumerable<FilterOperator> GetFilterOperators()
|
||||
{
|
||||
if (FilterOperators != null) return FilterOperators;
|
||||
|
||||
if (PropertyAccess.IsEnum(FilterPropertyType) || FilterPropertyType == typeof(bool))
|
||||
return new FilterOperator[] { FilterOperator.Equals, FilterOperator.NotEquals };
|
||||
|
||||
@@ -1292,6 +1372,8 @@ namespace Radzen.Blazor
|
||||
{
|
||||
switch (filterOperator)
|
||||
{
|
||||
case FilterOperator.Custom:
|
||||
return Grid?.CustomText;
|
||||
case FilterOperator.Contains:
|
||||
return Grid?.ContainsText;
|
||||
case FilterOperator.DoesNotContain:
|
||||
@@ -1358,6 +1440,10 @@ namespace Radzen.Blazor
|
||||
return "= ''";
|
||||
case FilterOperator.IsNotEmpty:
|
||||
return "≠ ''";
|
||||
case FilterOperator.In:
|
||||
return "∈";
|
||||
case FilterOperator.NotIn:
|
||||
return "∉";
|
||||
default:
|
||||
return $"{filterOperator}";
|
||||
}
|
||||
@@ -1419,10 +1505,10 @@ namespace Radzen.Blazor
|
||||
/// </summary>
|
||||
public int? GetSortIndex()
|
||||
{
|
||||
var descriptor = Grid.sorts.Where(s => s.Property == GetSortProperty()).FirstOrDefault();
|
||||
var descriptor = Grid.Sorts.Where(s => s.Property == GetSortProperty()).FirstOrDefault();
|
||||
if (descriptor != null)
|
||||
{
|
||||
return Grid.sorts.IndexOf(descriptor);
|
||||
return Grid.Sorts.IndexOf(descriptor);
|
||||
}
|
||||
|
||||
return null;
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
@using Microsoft.JSInterop
|
||||
@inject IJSRuntime JSRuntime
|
||||
<button title=@Column.GetFilterOperatorText(Column.GetFilterOperator()) class="@FilterIconStyle()" onclick="@($"Radzen.togglePopup(this.parentNode, '{Grid.PopupID}{Column.GetFilterProperty()}')")">
|
||||
<i class="rzi">@Grid.FilterIcon</i>
|
||||
<i class="notranslate rzi">@Grid.FilterIcon</i>
|
||||
@if (Column.GetFilterOperator() == FilterOperator.DoesNotContain)
|
||||
{
|
||||
<s>@Column.GetFilterOperatorSymbol(Column.GetFilterOperator())</s>
|
||||
@@ -17,7 +17,7 @@
|
||||
style="display:none;" tabindex="0">
|
||||
<div class="rz-overlaypanel-content">
|
||||
<ul class="rz-listbox-list">
|
||||
@if (Column.FilterPropertyType == typeof(string))
|
||||
@if (QueryableExtension.IsEnumerable(Column.FilterPropertyType))
|
||||
{
|
||||
@if (Column.GetFilterOperators().Contains(FilterOperator.Contains))
|
||||
{
|
||||
@@ -31,25 +31,37 @@
|
||||
<span class="rz-filter-menu-symbol"><s>@Column.GetFilterOperatorSymbol(FilterOperator.DoesNotContain)</s></span><span>@Grid.DoesNotContainText</span>
|
||||
</li>
|
||||
}
|
||||
@if (Column.GetFilterOperators().Contains(FilterOperator.StartsWith))
|
||||
@if (Column.GetFilterOperators().Contains(FilterOperator.In))
|
||||
{
|
||||
<li class="@(FilterOperatorStyle(Column, FilterOperator.In))" @onclick="@(args => ApplyFilter(FilterOperator.In))" style="display: block;">
|
||||
<span class="rz-filter-menu-symbol">@Column.GetFilterOperatorSymbol(FilterOperator.In)</span><span>@Grid.InText</span>
|
||||
</li>
|
||||
}
|
||||
@if (Column.GetFilterOperators().Contains(FilterOperator.NotIn))
|
||||
{
|
||||
<li class="@(FilterOperatorStyle(Column, FilterOperator.NotIn))" @onclick="@(args => ApplyFilter(FilterOperator.NotIn))" style="display: block;">
|
||||
<span class="rz-filter-menu-symbol"><s>@Column.GetFilterOperatorSymbol(FilterOperator.NotIn)</s></span><span>@Grid.NotInText</span>
|
||||
</li>
|
||||
}
|
||||
@if (Column.GetFilterOperators().Contains(FilterOperator.StartsWith) && Column.FilterPropertyType == typeof(string))
|
||||
{
|
||||
<li class="@(FilterOperatorStyle(Column, FilterOperator.StartsWith))" @onclick="@(args => ApplyFilter(FilterOperator.StartsWith))" style="display: block;">
|
||||
<span class="rz-filter-menu-symbol">@Column.GetFilterOperatorSymbol(FilterOperator.StartsWith)</span><span>@Grid.StartsWithText</span>
|
||||
</li>
|
||||
}
|
||||
@if (Column.GetFilterOperators().Contains(FilterOperator.EndsWith))
|
||||
@if (Column.GetFilterOperators().Contains(FilterOperator.EndsWith) && Column.FilterPropertyType == typeof(string))
|
||||
{
|
||||
<li class="@(FilterOperatorStyle(Column, FilterOperator.EndsWith))" @onclick="@(args => ApplyFilter(FilterOperator.EndsWith))" style="display: block;">
|
||||
<span class="rz-filter-menu-symbol">@Column.GetFilterOperatorSymbol(FilterOperator.EndsWith)</span><span>@Grid.EndsWithText</span>
|
||||
</li>
|
||||
}
|
||||
@if (Column.GetFilterOperators().Contains(FilterOperator.IsEmpty))
|
||||
@if (Column.GetFilterOperators().Contains(FilterOperator.IsEmpty) && Column.FilterPropertyType == typeof(string))
|
||||
{
|
||||
<li class="@(FilterOperatorStyle(Column, FilterOperator.IsEmpty))" @onclick="@(args => ApplyFilter(FilterOperator.IsEmpty))" style="display: block;">
|
||||
<span class="rz-filter-menu-symbol">@Column.GetFilterOperatorSymbol(FilterOperator.IsEmpty)</span><span>@Grid.IsEmptyText</span>
|
||||
</li>
|
||||
}
|
||||
@if (Column.GetFilterOperators().Contains(FilterOperator.IsNotEmpty))
|
||||
@if (Column.GetFilterOperators().Contains(FilterOperator.IsNotEmpty) && Column.FilterPropertyType == typeof(string))
|
||||
{
|
||||
<li class="@(FilterOperatorStyle(Column, FilterOperator.IsNotEmpty))" @onclick="@(args => ApplyFilter(FilterOperator.IsNotEmpty))" style="display: block;">
|
||||
<span class="rz-filter-menu-symbol">@Column.GetFilterOperatorSymbol(FilterOperator.IsNotEmpty)</span><span>@Grid.IsNotEmptyText</span>
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
@typeparam TItem
|
||||
@using System.Linq.Dynamic.Core
|
||||
@for (var i = 0; i < Grid.deepestChildColumnLevel + 1; i++)
|
||||
{
|
||||
<tr>
|
||||
@@ -32,9 +31,9 @@
|
||||
[Parameter]
|
||||
public IList<RadzenDataGridColumn<TItem>> Columns { get; set; }
|
||||
|
||||
GroupResult _groupResult;
|
||||
GroupResult _groupResult;
|
||||
[Parameter]
|
||||
public GroupResult GroupResult
|
||||
public GroupResult GroupResult
|
||||
{
|
||||
get
|
||||
{
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
@typeparam TItem
|
||||
@using System.Linq.Dynamic.Core
|
||||
@using System.Globalization
|
||||
@{
|
||||
var rowArgs = Grid?.GroupRowAttributes(this);
|
||||
@@ -86,7 +85,7 @@
|
||||
|
||||
GroupResult _groupResult;
|
||||
[Parameter]
|
||||
public GroupResult GroupResult
|
||||
public GroupResult GroupResult
|
||||
{
|
||||
get
|
||||
{
|
||||
|
||||
@@ -2,184 +2,195 @@
|
||||
@using Microsoft.JSInterop
|
||||
@using Radzen.Blazor.Rendering
|
||||
@using System.Globalization
|
||||
@using System.Linq.Dynamic.Core
|
||||
@using System.Collections
|
||||
@using Radzen
|
||||
|
||||
@if (RowIndex == Column.GetLevel())
|
||||
{
|
||||
<th rowspan="@(Column.GetRowSpan())" colspan="@(Column.GetColSpan())" @attributes="@Attributes" class="@CssClass" scope="col" style="@GetStyle()" @onmouseup=@(args => Grid.EndColumnReorder(args, ColumnIndex))>
|
||||
<div @onclick='@((args) => Grid.OnSort(args, Column))' @onkeydown="OnSortKeyPressed">
|
||||
@if ((Grid.AllowColumnReorder && Column.Reorderable || Grid.AllowGrouping && Column.Groupable))
|
||||
{
|
||||
<span id="@(Grid.getColumnUniqueId(ColumnIndex) + "-drag")" class="rz-column-drag"
|
||||
@onclick:preventDefault="true" @onclick:stopPropagation="true"
|
||||
@onmousedown:preventDefault="true"
|
||||
@onmousedown=@(args => Grid.StartColumnReorder(args, ColumnIndex))></span>
|
||||
}
|
||||
<span class="rz-column-title" title="@(Grid.ShowColumnTitleAsTooltip ? @Column.GetTitle() : Column.HeaderTooltip)">
|
||||
@if (Column.HeaderTemplate != null)
|
||||
<th rowspan="@(Column.GetRowSpan())" colspan="@(Column.GetColSpan())" @attributes="@Attributes" class="@CssClass" scope="col" style="@GetStyle()" @onmouseup=@(args => Grid.EndColumnReorder(args, ColumnIndex))>
|
||||
<div @onclick='@((args) => Grid.OnSort(args, Column))' @onkeydown="OnSortKeyPressed">
|
||||
@if ((Grid.AllowColumnReorder && Column.Reorderable || Grid.AllowGrouping && Column.Groupable))
|
||||
{
|
||||
<span class="rz-column-title-content" @onkeydown:stopPropagation>@Column.HeaderTemplate</span>
|
||||
}
|
||||
else
|
||||
{
|
||||
<span class="rz-column-title-content">@Column.GetTitle()</span>
|
||||
<span id="@(Grid.getColumnUniqueId(ColumnIndex) + "-drag")" class="rz-column-drag"
|
||||
@onclick:preventDefault="true" @onclick:stopPropagation="true"
|
||||
@onmousedown:preventDefault="true"
|
||||
@onmousedown=@(args => Grid.StartColumnReorder(args, ColumnIndex, Column.UniqueID ?? Column.Property))></span>
|
||||
}
|
||||
<span class="rz-column-title" title="@(Grid.ShowColumnTitleAsTooltip ? @Column.GetTitle() : Column.HeaderTooltip)">
|
||||
@if (Column.HeaderTemplate != null)
|
||||
{
|
||||
<span class="@Column.GetHeaderClass()" @onkeydown:stopPropagation>@Column.HeaderTemplate</span>
|
||||
}
|
||||
else
|
||||
{
|
||||
<span class="@Column.GetHeaderClass()">@Column.GetTitle()</span>
|
||||
}
|
||||
|
||||
@if (Grid.AllowSorting && Column.Sortable)
|
||||
{
|
||||
@if (Column.GetSortOrder() == SortOrder.Ascending)
|
||||
{
|
||||
<span class="rz-sortable-column-icon rzi-grid-sort rzi-sort rzi-sort-asc"></span>
|
||||
@if(Grid.ShowMultiColumnSortingIndex)
|
||||
{
|
||||
<RadzenBadge BadgeStyle="BadgeStyle.Info" Shade="Shade.Lighter" IsPill=true Text="@Column.getSortIndexAsString()" />
|
||||
}
|
||||
}
|
||||
else if (Column.GetSortOrder() == SortOrder.Descending)
|
||||
{
|
||||
<span class="rz-sortable-column-icon rzi-grid-sort rzi-sort rzi-sort-desc"></span>
|
||||
@if(Grid.ShowMultiColumnSortingIndex)
|
||||
@if (Grid.AllowSorting && Column.Sortable)
|
||||
{
|
||||
@if (Column.GetSortOrder() == SortOrder.Ascending)
|
||||
{
|
||||
<span class="notranslate rz-sortable-column-icon rzi-grid-sort rzi-sort rzi-sort-asc"></span>
|
||||
@if(Grid.ShowMultiColumnSortingIndex)
|
||||
{
|
||||
<RadzenBadge BadgeStyle="BadgeStyle.Info" Shade="Shade.Lighter" IsPill=true Text="@Column.getSortIndexAsString()" />
|
||||
}
|
||||
}
|
||||
else if (Column.GetSortOrder() == SortOrder.Descending)
|
||||
{
|
||||
<span class="notranslate rz-sortable-column-icon rzi-grid-sort rzi-sort rzi-sort-desc"></span>
|
||||
@if(Grid.ShowMultiColumnSortingIndex)
|
||||
{
|
||||
<RadzenBadge BadgeStyle="BadgeStyle.Info" Shade="Shade.Lighter" IsPill=true Text="@Column.getSortIndexAsString()" />
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
<span class="notranslate rz-sortable-column-icon rzi-grid-sort rzi-sort"></span>
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
</span>
|
||||
@if (Grid.AllowColumnResize && Column.Resizable && Column.Parent == null)
|
||||
{
|
||||
<span class="rz-sortable-column-icon rzi-grid-sort rzi-sort"></span>
|
||||
<div id="@(Grid.getColumnUniqueId(ColumnIndex) + "-resizer")" style="cursor:col-resize;float:right;"
|
||||
@onclick:preventDefault="true" @onclick:stopPropagation="true" class="rz-column-resizer"
|
||||
@onmousedown:preventDefault="true"
|
||||
@onmousedown=@StartColumnResize @onmouseup=@StopColumnResize> </div>
|
||||
}
|
||||
}
|
||||
</span>
|
||||
@if (Grid.AllowColumnResize && Column.Resizable && Column.Parent == null)
|
||||
{
|
||||
<div id="@(Grid.getColumnUniqueId(ColumnIndex) + "-resizer")" style="cursor:col-resize;float:right;"
|
||||
@onclick:preventDefault="true" @onclick:stopPropagation="true" class="rz-column-resizer"
|
||||
@onmousedown:preventDefault="true"
|
||||
@onmousedown=@StartColumnResize @onmouseup=@StopColumnResize> </div>
|
||||
}
|
||||
@{var filterMode = Column.FilterMode ?? Grid.FilterMode;}
|
||||
@if (Grid.AllowFiltering && Column.Filterable && (filterMode == FilterMode.Advanced || filterMode == FilterMode.CheckBoxList))
|
||||
{
|
||||
@{var filterMode = Column.FilterMode ?? Grid.FilterMode;}
|
||||
@if (Grid.AllowFiltering && Column.Filterable && (filterMode == FilterMode.Advanced || filterMode == FilterMode.CheckBoxList))
|
||||
{
|
||||
<i @ref=@filterButton @onclick:stopPropagation="true" @onmousedown=@ToggleFilter
|
||||
class="@getFilterIconCss(Column)" onclick=@getFilterOpen() @onclick:preventDefault="true">
|
||||
@Grid.FilterIcon
|
||||
class="@getFilterIconCss(Column)" onclick=@getFilterOpen() @onclick:preventDefault="true">
|
||||
@Grid.FilterIcon
|
||||
</i>
|
||||
|
||||
<Popup Lazy=@(Grid.FilterPopupRenderMode == PopupRenderMode.OnDemand) @ref=popup id="@($"{getColumnPopupID()}")" class="rz-overlaypanel"
|
||||
style="display:none;min-width:250px;" @onkeydown="OnFilterPopupKeyPressed">
|
||||
<div class="rz-overlaypanel-content">
|
||||
@if (Column.FilterTemplate != null)
|
||||
{
|
||||
@Column.FilterTemplate(Column)
|
||||
}
|
||||
else
|
||||
{
|
||||
<form id="@($"{getColumnPopupID()}-form")" @onsubmit="@(args => ApplyFilter())" class="rz-grid-filter">
|
||||
style="display:none;min-width:250px;" @onkeydown="OnFilterPopupKeyPressed">
|
||||
<div class="rz-overlaypanel-content">
|
||||
@if (Column.FilterTemplate != null)
|
||||
{
|
||||
@Column.FilterTemplate(Column)
|
||||
}
|
||||
else
|
||||
{
|
||||
<form id="@($"{getColumnPopupID()}-form")" @onsubmit="@(args => ApplyFilter())" class="rz-grid-filter">
|
||||
@if (filterMode == FilterMode.Advanced)
|
||||
{
|
||||
<span class="rz-grid-filter-label">@Grid.FilterText</span>
|
||||
<RadzenDropDown InputAttributes="@(new Dictionary<string,object>(){ { "aria-label", Grid.FilterOperatorArialLabel + Column.GetFilterOperatorText(Column.GetSecondFilterOperator()) }})"
|
||||
<span class="rz-grid-filter-label">@Grid.FilterText</span>
|
||||
<RadzenDropDown InputAttributes="@(new Dictionary<string,object>(){ { "aria-label", Grid.FilterOperatorAriaLabel + Column.GetFilterOperatorText(Column.GetSecondFilterOperator()) }})"
|
||||
@onclick:preventDefault="true" Data="@(Column.GetFilterOperators().Select(t => new { Value = Column.GetFilterOperatorText(t), Key = t }))" TextProperty="Value" ValueProperty="Key" TValue="FilterOperator" Value="@Column.GetFilterOperator()" Change="@(args => Column.SetFilterOperator((FilterOperator)args))" />
|
||||
@if (Column.FilterValueTemplate != null)
|
||||
{
|
||||
@Column.FilterValueTemplate(Column)
|
||||
}
|
||||
else if (PropertyAccess.IsNullableEnum(Column.FilterPropertyType) || PropertyAccess.IsEnum(Column.FilterPropertyType))
|
||||
{
|
||||
<RadzenDropDown Disabled="@(!Column.CanSetFilterValue())" AllowClear="false" AllowFiltering="false" TValue="@object"
|
||||
Value=@Column.GetFilterValue() Multiple="false" Placeholder="@Grid.EnumFilterSelectText" TextProperty="Text" ValueProperty="Value" Data=@EnumExtensions.EnumAsKeyValuePair(Nullable.GetUnderlyingType(Column.FilterPropertyType) ?? Column.FilterPropertyType, Grid.EnumFilterTranslationFunc)
|
||||
Change="@(args => Column.SetFilterValue(args))"
|
||||
InputAttributes="@(new Dictionary<string,object>(){ { "aria-label", Column.Title + Grid.FilterValueArialLabel + Column.GetFilterValue() }})" />
|
||||
}
|
||||
else if (PropertyAccess.IsNumeric(Column.FilterPropertyType))
|
||||
{
|
||||
@(Grid.DrawNumericFilter(Column, false))
|
||||
}
|
||||
else if (PropertyAccess.IsDate(Column.FilterPropertyType))
|
||||
{
|
||||
<RadzenDatePicker Disabled="@(!Column.CanSetFilterValue())" TValue="@object" ShowTime="@Column.ShowTimeForDateTimeFilter()" ShowTimeOkButton="true" DateFormat="@Grid.getFilterDateFormat(Column)"
|
||||
Value="@Column.GetFilterValue()" Change="@(args => Column.SetFilterValue(PropertyAccess.IsDateOnly(Column.FilterPropertyType) ? PropertyAccess.DateOnlyFromDateTime(args.Value) : args.Value))" AllowInput=@(Grid.AllowFilterDateInput)
|
||||
InputAttributes="@(new Dictionary<string,object>(){ { "aria-label", Column.Title + Grid.FilterValueArialLabel + Column.GetFilterValue() }})" />
|
||||
@if (Column.FilterValueTemplate != null)
|
||||
{
|
||||
@Column.FilterValueTemplate(Column)
|
||||
}
|
||||
else if (PropertyAccess.IsNullableEnum(Column.FilterPropertyType) || PropertyAccess.IsEnum(Column.FilterPropertyType))
|
||||
{
|
||||
<RadzenDropDown Disabled="@(!Column.CanSetFilterValue())" AllowClear="false" AllowFiltering="false" TValue="@object"
|
||||
Value=@Column.GetFilterValue() Multiple="false" Placeholder="@Grid.EnumFilterSelectText" TextProperty="Text" ValueProperty="Value" Data=@EnumExtensions.EnumAsKeyValuePair(Nullable.GetUnderlyingType(Column.FilterPropertyType) ?? Column.FilterPropertyType, Grid.EnumFilterTranslationFunc)
|
||||
Change="@(args => Column.SetFilterValue(args))"
|
||||
InputAttributes="@(new Dictionary<string,object>(){ { "aria-label", Column.Title + Grid.FilterValueAriaLabel + Column.GetFilterValue() }})" />
|
||||
}
|
||||
else if (PropertyAccess.IsNumeric(Column.FilterPropertyType))
|
||||
{
|
||||
@(Grid.DrawNumericFilter(Column, false))
|
||||
}
|
||||
else if (PropertyAccess.IsDate(Column.FilterPropertyType))
|
||||
{
|
||||
<RadzenDatePicker Disabled="@(!Column.CanSetFilterValue())" TValue="@object" ShowTime="@Column.ShowTimeForDateTimeFilter()" ShowTimeOkButton="true" DateFormat="@Grid.getFilterDateFormat(Column)"
|
||||
Value="@Column.GetFilterValue()" Change="@(args => Column.SetFilterValue(PropertyAccess.IsDateOnly(Column.FilterPropertyType) ? PropertyAccess.DateOnlyFromDateTime(args.Value) : args.Value))" AllowInput=@(Grid.AllowFilterDateInput)
|
||||
InputAttributes="@(new Dictionary<string,object>(){ { "aria-label", Column.Title + Grid.FilterValueAriaLabel + Column.GetFilterValue() }})" />
|
||||
|
||||
}
|
||||
else if (Column.FilterPropertyType == typeof(bool) || Column.FilterPropertyType == typeof(bool?))
|
||||
{
|
||||
<RadzenCheckBox Disabled="@(!Column.CanSetFilterValue())" InputAttributes="@(new Dictionary<string,object>(){ { "aria-label", Column.Title + Grid.FilterValueArialLabel + Column.GetFilterValue() }})" TriState="true" TValue="@object" Value="@Column.GetFilterValue()" Change="@(args => { Column.SetFilterValue(null); Column.SetFilterValue(args); Grid.SaveSettings(); InvokeAsync(() => Grid.Reload()); })" />
|
||||
}
|
||||
else
|
||||
{
|
||||
<RadzenTextBox Disabled="@(!Column.CanSetFilterValue())" id="@($"{getColumnPopupID()}-sf")" aria-label=@(Column.Title + Grid.FilterValueArialLabel + Column.GetFilterValue()) Value="@($"{Column.GetFilterValue()}")" Change="@(args => Column.SetFilterValue(args))" />
|
||||
}
|
||||
}
|
||||
else if (Column.FilterPropertyType == typeof(bool) || Column.FilterPropertyType == typeof(bool?))
|
||||
{
|
||||
<RadzenCheckBox Disabled="@(!Column.CanSetFilterValue())" InputAttributes="@(new Dictionary<string,object>(){ { "aria-label", Column.Title + Grid.FilterValueAriaLabel + Column.GetFilterValue() }})" TriState="true" TValue="@object" Value="@Column.GetFilterValue()" Change="@(args => { Column.SetFilterValue(null); Column.SetFilterValue(args); Grid.SaveSettings(); })" />
|
||||
}
|
||||
else
|
||||
{
|
||||
<RadzenTextBox Disabled="@(!Column.CanSetFilterValue())" id="@($"{getColumnPopupID()}-sf")" aria-label=@(Column.Title + Grid.FilterValueAriaLabel + Column.GetFilterValue()) Value="@($"{Column.GetFilterValue()}")" Change="@(args => Column.SetFilterValue(args))" />
|
||||
}
|
||||
|
||||
<RadzenDropDown @onclick:preventDefault="true" TextProperty="Text" ValueProperty="Value" Style="width: 90px" InputAttributes="@(new Dictionary<string,object>(){ { "aria-label", Column.Title + Grid.LogicalOperatorArialLabel + (Column.LogicalFilterOperator == LogicalFilterOperator.And ? Grid.AndOperatorText : Grid.OrOperatorText) }})"
|
||||
Data="@(Enum.GetValues(typeof(LogicalFilterOperator)).Cast<LogicalFilterOperator>().Select(t => new { Text = t == LogicalFilterOperator.And ? Grid.AndOperatorText : Grid.OrOperatorText, Value = t }))" TValue="LogicalFilterOperator" Value="@Column.LogicalFilterOperator" Change="@(args => Column.SetLogicalFilterOperator((LogicalFilterOperator)args))" />
|
||||
<RadzenDropDown @onclick:preventDefault="true" TextProperty="Text" ValueProperty="Value" Style="width: 90px" InputAttributes="@(new Dictionary<string,object>(){ { "aria-label", Column.Title + Grid.LogicalOperatorAriaLabel + (Column.LogicalFilterOperator == LogicalFilterOperator.And ? Grid.AndOperatorText : Grid.OrOperatorText) }})"
|
||||
Data="@(Enum.GetValues(typeof(LogicalFilterOperator)).Cast<LogicalFilterOperator>().Select(t => new { Text = t == LogicalFilterOperator.And ? Grid.AndOperatorText : Grid.OrOperatorText, Value = t }))" TValue="LogicalFilterOperator" Value="@Column.LogicalFilterOperator" Change="@(args => Column.SetLogicalFilterOperator((LogicalFilterOperator)args))" />
|
||||
|
||||
<RadzenDropDown InputAttributes="@(new Dictionary<string,object>(){ { "aria-label", Grid.SecondFilterOperatorArialLabel + Column.GetFilterOperatorText(Column.GetSecondFilterOperator()) }})" @onclick:preventDefault="true" Data="@(Column.GetFilterOperators().Select(t => new { Value = Column.GetFilterOperatorText(t), Key = t }))" TextProperty="Value" ValueProperty="Key" TValue="FilterOperator" Value="@Column.GetSecondFilterOperator()" Change="@(args => Column.SetSecondFilterOperator((FilterOperator)args))" />
|
||||
@if (Column.SecondFilterValueTemplate != null)
|
||||
{
|
||||
@Column.SecondFilterValueTemplate(Column)
|
||||
}
|
||||
else if (PropertyAccess.IsNullableEnum(Column.FilterPropertyType) || PropertyAccess.IsEnum(Column.FilterPropertyType))
|
||||
{
|
||||
<RadzenDropDown Disabled="@(!Column.CanSetFilterValue(false))" AllowClear="false" AllowFiltering="false" TValue="@object" InputAttributes="@(new Dictionary<string,object>(){ { "aria-label", Column.Title + Grid.SecondFilterValueArialLabel }})"
|
||||
Value=@Column.GetSecondFilterValue() Multiple="false" Placeholder="@Grid.EnumFilterSelectText" TextProperty="Text" ValueProperty="Value" Data=@EnumExtensions.EnumAsKeyValuePair(Nullable.GetUnderlyingType(Column.FilterPropertyType) ?? Column.FilterPropertyType, Grid.EnumFilterTranslationFunc)
|
||||
Change="@(args => Column.SetFilterValue(args,false))" />
|
||||
}
|
||||
else if (PropertyAccess.IsNumeric(Column.FilterPropertyType))
|
||||
{
|
||||
@(Grid.DrawNumericFilter(Column, false, false))
|
||||
}
|
||||
else if (PropertyAccess.IsDate(Column.FilterPropertyType))
|
||||
{
|
||||
<RadzenDatePicker Disabled="@(!Column.CanSetFilterValue(false))" TValue="@object" InputAttributes="@(new Dictionary<string,object>(){ { "aria-label", Column.Title + Grid.SecondFilterValueArialLabel + Column.GetSecondFilterValue() }})"
|
||||
ShowTime="@Column.ShowTimeForDateTimeFilter()" ShowTimeOkButton="true" DateFormat="@Grid.getFilterDateFormat(Column)"
|
||||
Value="@Column.GetSecondFilterValue()" Change="@(args => Column.SetFilterValue(PropertyAccess.IsDateOnly(Column.FilterPropertyType) ? PropertyAccess.DateOnlyFromDateTime(args.Value) : args.Value, false))" AllowInput=@(Grid.AllowFilterDateInput) />
|
||||
<RadzenDropDown InputAttributes="@(new Dictionary<string,object>(){ { "aria-label", Grid.SecondFilterOperatorAriaLabel + Column.GetFilterOperatorText(Column.GetSecondFilterOperator()) }})" @onclick:preventDefault="true" Data="@(Column.GetFilterOperators().Select(t => new { Value = Column.GetFilterOperatorText(t), Key = t }))" TextProperty="Value" ValueProperty="Key" TValue="FilterOperator" Value="@Column.GetSecondFilterOperator()" Change="@(args => Column.SetSecondFilterOperator((FilterOperator)args))" />
|
||||
@if (Column.SecondFilterValueTemplate != null)
|
||||
{
|
||||
@Column.SecondFilterValueTemplate(Column)
|
||||
}
|
||||
else if (PropertyAccess.IsNullableEnum(Column.FilterPropertyType) || PropertyAccess.IsEnum(Column.FilterPropertyType))
|
||||
{
|
||||
<RadzenDropDown Disabled="@(!Column.CanSetFilterValue(false))" AllowClear="false" AllowFiltering="false" TValue="@object" InputAttributes="@(new Dictionary<string,object>(){ { "aria-label", Column.Title + Grid.SecondFilterValueAriaLabel }})"
|
||||
Value=@Column.GetSecondFilterValue() Multiple="false" Placeholder="@Grid.EnumFilterSelectText" TextProperty="Text" ValueProperty="Value" Data=@EnumExtensions.EnumAsKeyValuePair(Nullable.GetUnderlyingType(Column.FilterPropertyType) ?? Column.FilterPropertyType, Grid.EnumFilterTranslationFunc)
|
||||
Change="@(args => Column.SetFilterValue(args,false))" />
|
||||
}
|
||||
else if (PropertyAccess.IsNumeric(Column.FilterPropertyType))
|
||||
{
|
||||
@(Grid.DrawNumericFilter(Column, false, false))
|
||||
}
|
||||
else if (PropertyAccess.IsDate(Column.FilterPropertyType))
|
||||
{
|
||||
<RadzenDatePicker Disabled="@(!Column.CanSetFilterValue(false))" TValue="@object" InputAttributes="@(new Dictionary<string,object>(){ { "aria-label", Column.Title + Grid.SecondFilterValueAriaLabel + Column.GetSecondFilterValue() }})"
|
||||
ShowTime="@Column.ShowTimeForDateTimeFilter()" ShowTimeOkButton="true" DateFormat="@Grid.getFilterDateFormat(Column)"
|
||||
Value="@Column.GetSecondFilterValue()" Change="@(args => Column.SetFilterValue(PropertyAccess.IsDateOnly(Column.FilterPropertyType) ? PropertyAccess.DateOnlyFromDateTime(args.Value) : args.Value, false))" AllowInput=@(Grid.AllowFilterDateInput) />
|
||||
|
||||
}
|
||||
else if (Column.FilterPropertyType == typeof(bool) || Column.FilterPropertyType == typeof(bool?))
|
||||
{
|
||||
<RadzenCheckBox Disabled="@(!Column.CanSetFilterValue(false))" InputAttributes="@(new Dictionary<string,object>(){ { "aria-label", Column.Title + Grid.SecondFilterValueArialLabel + Column.GetSecondFilterValue() }})" TriState="true" TValue="@object" Value="@Column.GetSecondFilterValue()" Change="@(args => { Column.SetFilterValue(args, false); Grid.SaveSettings(); })" />
|
||||
}
|
||||
else
|
||||
{
|
||||
<RadzenTextBox Disabled="@(!Column.CanSetFilterValue(false))" id="@($"{getColumnPopupID()}-sf2")" aria-label=@(Column.Title + Grid.SecondFilterValueArialLabel + Column.GetSecondFilterValue()) Value="@($"{Column.GetSecondFilterValue()}")" Change="@(args => Column.SetFilterValue(args, false))" />
|
||||
}
|
||||
else if (Column.FilterPropertyType == typeof(bool) || Column.FilterPropertyType == typeof(bool?))
|
||||
{
|
||||
<RadzenCheckBox Disabled="@(!Column.CanSetFilterValue(false))" InputAttributes="@(new Dictionary<string,object>(){ { "aria-label", Column.Title + Grid.SecondFilterValueAriaLabel + Column.GetSecondFilterValue() }})" TriState="true" TValue="@object" Value="@Column.GetSecondFilterValue()" Change="@(args => { Column.SetFilterValue(args, false); Grid.SaveSettings(); })" />
|
||||
}
|
||||
else
|
||||
{
|
||||
<RadzenTextBox Disabled="@(!Column.CanSetFilterValue(false))" id="@($"{getColumnPopupID()}-sf2")" aria-label=@(Column.Title + Grid.SecondFilterValueAriaLabel + Column.GetSecondFilterValue()) Value="@($"{Column.GetSecondFilterValue()}")" Change="@(args => Column.SetFilterValue(args, false))" />
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
<RadzenListBox AllowVirtualization="@Column.AllowCheckBoxListVirtualization" AllowClear="true" Multiple="true" Style="height: 300px"
|
||||
TValue="IEnumerable<object>" Value=@Column.GetFilterValue() Change="@ListBoxChange"
|
||||
Data=@filterValues Count=@filterValuesCount LoadData="@LoadFilterValues"
|
||||
AllowFiltering="@(!string.IsNullOrEmpty(Column.GetFilterProperty()) && PropertyAccess.GetPropertyType(typeof(TItem), Column.GetFilterProperty()) == typeof(string))"
|
||||
Disabled="@(!Column.CanSetFilterValue())" FilterCaseSensitivity="FilterCaseSensitivity.CaseInsensitive"
|
||||
InputAttributes="@(new Dictionary<string,object>(){ { "aria-label", Column.Title + Grid.FilterValueArialLabel + Column.GetFilterValue() }})">
|
||||
<Template>
|
||||
@if (context as Enum != null)
|
||||
{
|
||||
@EnumExtensions.GetDisplayDescription(context as Enum)
|
||||
}
|
||||
else
|
||||
{
|
||||
@(!string.IsNullOrEmpty(Column.FormatString) ? string.Format(Column.FormatProvider ?? Grid?.Culture ?? CultureInfo.CurrentCulture, Column.FormatString, context ?? "") : Convert.ToString(context ?? "", Grid?.Culture ?? CultureInfo.CurrentCulture))
|
||||
}
|
||||
</Template>
|
||||
</RadzenListBox>
|
||||
@if (Column.FilterValueTemplate != null)
|
||||
{
|
||||
@Column.FilterValueTemplate(Column)
|
||||
}
|
||||
else
|
||||
{
|
||||
<RadzenProgressBarCircular Style="position:absolute;width:100%;" Visible="@isLoading" Value="100" ShowValue="false" Mode="ProgressBarMode.Indeterminate" />
|
||||
<RadzenListBox AllowVirtualization="@Column.AllowCheckBoxListVirtualization" AllowClear="true" Multiple="true" Style="height: 300px"
|
||||
TValue="IEnumerable<object>" Value=@Column.GetFilterValue() Change="@ListBoxChange"
|
||||
Data=@filterValues Count=@filterValuesCount LoadData="@LoadFilterValues"
|
||||
AllowFiltering="@(!string.IsNullOrEmpty(Column.GetFilterProperty()) && PropertyAccess.GetPropertyType(typeof(TItem), Column.GetFilterProperty()) == typeof(string))"
|
||||
Disabled="@(!Column.CanSetFilterValue())" FilterCaseSensitivity="FilterCaseSensitivity.CaseInsensitive"
|
||||
InputAttributes="@(new Dictionary<string,object>(){ { "aria-label", Column.Title + Grid.FilterValueAriaLabel + Column.GetFilterValue() }})">
|
||||
<Template>
|
||||
@if (context as Enum != null)
|
||||
{
|
||||
@EnumExtensions.GetDisplayDescription(context as Enum)
|
||||
}
|
||||
else
|
||||
{
|
||||
@(!string.IsNullOrEmpty(Column.FormatString) ? string.Format(Column.FormatProvider ?? Grid?.Culture ?? CultureInfo.CurrentCulture, Column.FormatString, context ?? "") : Convert.ToString(context ?? "", Grid?.Culture ?? CultureInfo.CurrentCulture))
|
||||
}
|
||||
</Template>
|
||||
</RadzenListBox>
|
||||
}
|
||||
}
|
||||
</form>
|
||||
}
|
||||
</div>
|
||||
@if (Column.FilterTemplate == null)
|
||||
{
|
||||
<div class="rz-grid-filter-buttons">
|
||||
<RadzenButton ButtonStyle="ButtonStyle.Base" class="rz-clear-filter" Click="@ClearFilter" Text=@Grid.ClearFilterText title="@Grid.ClearFilterText" />
|
||||
<RadzenButton ButtonStyle="ButtonStyle.Primary" class="rz-apply-filter" form="@($"{getColumnPopupID()}-form")" ButtonType="ButtonType.Submit" Text=@Grid.ApplyFilterText title="@Grid.ApplyFilterText" />
|
||||
</div>
|
||||
}
|
||||
</Popup>
|
||||
</div>
|
||||
@if (Column.FilterTemplate == null)
|
||||
{
|
||||
<div class="rz-grid-filter-buttons">
|
||||
<RadzenButton ButtonStyle="ButtonStyle.Base" class="rz-clear-filter" Click="@ClearFilter" Text=@Grid.ClearFilterText title="@Grid.ClearFilterText" />
|
||||
<RadzenButton onmousedown="@getBlur()" ButtonStyle="ButtonStyle.Primary" class="rz-apply-filter" form="@($"{getColumnPopupID()}-form")" ButtonType="ButtonType.Submit" Text=@Grid.ApplyFilterText title="@Grid.ApplyFilterText" />
|
||||
</div>
|
||||
}
|
||||
</Popup>
|
||||
}
|
||||
</div>
|
||||
@if (Grid.allColumns.Any(c => c.Parent != null) && Grid.AllowFiltering && Column.Filterable && (filterMode == FilterMode.Simple || filterMode == FilterMode.SimpleWithMenu))
|
||||
{
|
||||
@Grid.RenderSimpleFilter(Column, filterMode)
|
||||
}
|
||||
</div>
|
||||
</th>
|
||||
</th>
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -188,7 +199,7 @@ else
|
||||
ColumnIndex = Grid.allColumns.IndexOf(column);//for child must have different columnindex
|
||||
|
||||
<RadzenDataGridHeaderCell RowIndex="@RowIndex" Grid="@Grid" Column="@column" Style="@column.GetStyle(true, true)" ColumnIndex="@ColumnIndex"
|
||||
CssClass="@($"rz-unselectable-text {(Grid.AllowSorting && column.Sortable ? "rz-sortable-column" : "")} {column.HeaderCssClass} {Grid.getFrozenColumnClass(column, Grid.ColumnsCollection.Where(c => c.GetVisible()).ToList())} {Grid.getCompositeCellCSSClass(column)} {Grid.getColumnAlignClass(column)}".Trim())" />
|
||||
CssClass="@($"rz-unselectable-text {(Grid.AllowSorting && column.Sortable ? "rz-sortable-column" : "")} {column.HeaderCssClass} {Grid.getFrozenColumnClass(column, Grid.ColumnsCollection.Where(c => c.GetVisible()).ToList())} {Grid.getCompositeCellCSSClass(column)} {Grid.getColumnAlignClass(column)}".Trim())" />
|
||||
}
|
||||
}
|
||||
@code {
|
||||
@@ -198,33 +209,28 @@ else
|
||||
int filterValuesCount;
|
||||
internal IEnumerable filterValues;
|
||||
string loadDataArgsString;
|
||||
bool isLoading = false;
|
||||
|
||||
async Task LoadFilterValues(LoadDataArgs loadDataArgs)
|
||||
{
|
||||
isLoading = true;
|
||||
|
||||
await Task.Yield();
|
||||
|
||||
var property = Column.Property != Column.FilterProperty && !string.IsNullOrEmpty(Column.FilterProperty) ? Column.Property :
|
||||
Column.GetFilterProperty();
|
||||
|
||||
var propertyType = PropertyAccess.GetPropertyType(typeof(TItem), property);
|
||||
|
||||
if (property.IndexOf(".") != -1)
|
||||
{
|
||||
property = $"np({property})";
|
||||
}
|
||||
|
||||
if (propertyType == typeof(string))
|
||||
{
|
||||
property = $@"({property} == null ? """" : {property})";
|
||||
}
|
||||
var propertyType = PropertyAccess.GetPropertyType(typeof(TItem), property) ?? Column.FilterPropertyType;
|
||||
|
||||
var loadDataArgsString = $"{loadDataArgs.Skip}|{loadDataArgs.Top}{loadDataArgs.Filter}";
|
||||
|
||||
if (Column.Grid.LoadColumnFilterData.HasDelegate)
|
||||
{
|
||||
var args = new DataGridLoadColumnFilterDataEventArgs<TItem>() { Column = Column, Filter = loadDataArgs.Filter };
|
||||
var args = new DataGridLoadColumnFilterDataEventArgs<TItem>() { Column = Column, Filter = loadDataArgs.Filter, Skip = loadDataArgs.Skip, Top = loadDataArgs.Top };
|
||||
|
||||
await Column.Grid.LoadColumnFilterData.InvokeAsync(args);
|
||||
|
||||
filterValues = args.Data.AsQueryable().Select(DynamicLinqCustomTypeProvider.ParsingConfig, property).Distinct().Cast(propertyType ?? typeof(object));
|
||||
filterValues = args.Data.AsQueryable().Select(property).Distinct();
|
||||
filterValuesCount = args.Count;
|
||||
}
|
||||
else if(!string.IsNullOrEmpty(property) && (filterValues == null || this.loadDataArgsString != loadDataArgsString) && Column.Grid.Data != null)
|
||||
@@ -235,8 +241,8 @@ else
|
||||
|
||||
if(!string.IsNullOrEmpty(loadDataArgs.Filter))
|
||||
{
|
||||
query = Radzen.QueryableExtension.Where(Column.Grid.Data.AsQueryable().Where<TItem>(Column.Grid.allColumns.Where(c => c != Column)),
|
||||
property, loadDataArgs.Filter, StringFilterOperator.Contains, FilterCaseSensitivity.CaseInsensitive);
|
||||
query = Column.Grid.Data.AsQueryable().Where<TItem>(Column.Grid.allColumns.Where(c => c != Column))
|
||||
.Where(property, loadDataArgs.Filter, StringFilterOperator.Contains, FilterCaseSensitivity.CaseInsensitive);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -245,35 +251,35 @@ else
|
||||
|
||||
if (Column.Property != Column.FilterProperty && !string.IsNullOrEmpty(Column.FilterProperty))
|
||||
{
|
||||
query = query
|
||||
.SelectMany(DynamicLinqCustomTypeProvider.ParsingConfig, property)
|
||||
.Select(DynamicLinqCustomTypeProvider.ParsingConfig, Column.FilterProperty)
|
||||
.Distinct().Cast(typeof(object));
|
||||
query = query.SelectMany(property).Select(Column.FilterProperty).Distinct().Cast<object>().OrderBy(i => i);
|
||||
propertyType = query.ElementType;
|
||||
}
|
||||
else
|
||||
{
|
||||
query = query.Select(DynamicLinqCustomTypeProvider.ParsingConfig, property).Distinct().Cast(propertyType ?? typeof(object));
|
||||
query = query.Select(property).Distinct().Cast<object>().OrderBy(i => i);
|
||||
}
|
||||
|
||||
filterValuesCount = query.Count();
|
||||
filterValuesCount = query.Cast<object>().Count();
|
||||
|
||||
if(loadDataArgs.Skip != null)
|
||||
{
|
||||
query = query.Skip(loadDataArgs.Skip.Value);
|
||||
query = query.Cast<object>().Skip(loadDataArgs.Skip.Value);
|
||||
}
|
||||
|
||||
if(loadDataArgs.Top != null)
|
||||
{
|
||||
query = query.Take(loadDataArgs.Top.Value);
|
||||
query = query.Cast<object>().Take(loadDataArgs.Top.Value);
|
||||
}
|
||||
|
||||
filterValues = query;
|
||||
filterValues = query.Cast(propertyType);
|
||||
|
||||
if (!Column.AllowCheckBoxListVirtualization)
|
||||
{
|
||||
await InvokeAsync(StateHasChanged);
|
||||
}
|
||||
}
|
||||
|
||||
isLoading = false;
|
||||
}
|
||||
|
||||
void ListBoxChange(object args)
|
||||
@@ -299,6 +305,11 @@ else
|
||||
propertyType = PropertyAccess.GetPropertyType(typeof(TItem), Column.GetFilterProperty());
|
||||
}
|
||||
|
||||
if (propertyType == null)
|
||||
{
|
||||
propertyType = Column.FilterPropertyType;
|
||||
}
|
||||
|
||||
Column.SetFilterValue(enumerable.Cast<object>().Any() ? propertyType != null ? enumerable.AsQueryable().Cast(propertyType) : enumerable : null);
|
||||
}
|
||||
|
||||
@@ -314,7 +325,7 @@ else
|
||||
await popup.ToggleAsync(filterButton);
|
||||
|
||||
Grid.allColumns
|
||||
.Where(c => c != Column && c.headerCell != null)
|
||||
.Where(c => c.GetVisible() && c.UniqueID != Column.UniqueID)
|
||||
.Select(c => c.headerCell).ToList()
|
||||
.ForEach(cell => InvokeAsync(cell.CloseFilter));
|
||||
}
|
||||
@@ -329,8 +340,43 @@ else
|
||||
await Grid.ClearFilter(Column, true);
|
||||
}
|
||||
|
||||
string getBlur()
|
||||
{
|
||||
return IsAdvancedNumeric() ? "Radzen.blur(this, event)" : null;
|
||||
}
|
||||
|
||||
bool IsAdvancedNumeric()
|
||||
{
|
||||
return (Column.FilterMode ?? Grid.FilterMode) == FilterMode.Advanced &&
|
||||
PropertyAccess.IsNumeric(Column.FilterPropertyType) &&
|
||||
!(PropertyAccess.IsEnum(Column.FilterPropertyType) || PropertyAccess.IsNullableEnum(Column.FilterPropertyType));
|
||||
}
|
||||
|
||||
async Task ApplyFilter()
|
||||
{
|
||||
if (IsAdvancedNumeric())
|
||||
{
|
||||
var targetType = Nullable.GetUnderlyingType(Column.FilterPropertyType) ?? Column.FilterPropertyType;
|
||||
|
||||
if (Column.FilterValueTemplate == null)
|
||||
{
|
||||
var firstInputValue = await Grid.GetJSRuntime().InvokeAsync<string>("Radzen.getNumericValue", Grid.getFilterInputId(Column) + "f");
|
||||
if (!object.Equals($"{Column.GetFilterValue()}", $"{firstInputValue}"))
|
||||
{
|
||||
Column.SetFilterValue(!string.IsNullOrEmpty(firstInputValue) ? Convert.ChangeType(firstInputValue, targetType) : null);
|
||||
}
|
||||
}
|
||||
|
||||
if (Column.SecondFilterValueTemplate == null)
|
||||
{
|
||||
var secondInputValue = await Grid.GetJSRuntime().InvokeAsync<string>("Radzen.getNumericValue", Grid.getFilterInputId(Column) + "s");
|
||||
if (!object.Equals($"{Column.GetSecondFilterValue()}", $"{secondInputValue}"))
|
||||
{
|
||||
Column.SetFilterValue(!string.IsNullOrEmpty(secondInputValue) ? Convert.ChangeType(secondInputValue, targetType) : null, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (Grid.FilterPopupRenderMode == PopupRenderMode.OnDemand)
|
||||
{
|
||||
await popup.CloseAsync();
|
||||
@@ -380,7 +426,7 @@ else
|
||||
private string getFilterIconCss(RadzenDataGridColumn<TItem> column)
|
||||
{
|
||||
var additionalStyle = Column.HasActiveFilter() ? "rz-grid-filter-active" : "";
|
||||
return $"rzi rz-grid-filter-icon {additionalStyle}";
|
||||
return $"notranslate rzi rz-grid-filter-icon {additionalStyle}";
|
||||
}
|
||||
|
||||
private Task OnSortKeyPressed(KeyboardEventArgs args)
|
||||
|
||||
@@ -3,9 +3,9 @@
|
||||
@implements IRadzenForm
|
||||
<CascadingValue Value=@EditContext>
|
||||
<CascadingValue Value=this>
|
||||
@{var rowArgs = Grid?.RowAttributes(Item); }
|
||||
@{var rowArgs = Grid?.RowAttributes(Item, Index); }
|
||||
@{var firstLevel = Grid.AllowCompositeDataCells ? 0 : Grid.deepestChildColumnLevel; }
|
||||
@for(var i = firstLevel; i < Grid.deepestChildColumnLevel + 1; i++)
|
||||
@for(var i = firstLevel; Grid.AllowCompositeDataCells ? i <= Grid.deepestChildColumnLevel + 1 : i < Grid.deepestChildColumnLevel + 1; i++)
|
||||
{
|
||||
<tr class="@(Grid.RowStyle(Item, Index))" @attributes="@rowArgs.Item2">
|
||||
@if (Grid.ShowGroupExpandColumn)
|
||||
@@ -25,7 +25,7 @@
|
||||
{
|
||||
<td class="rz-col-icon" rowspan="@(Grid.AllowCompositeDataCells ? (Grid.deepestChildColumnLevel + 1) : 1)">
|
||||
<span class="rz-column-title"></span>
|
||||
@if (rowArgs.Item1.Expandable)
|
||||
@if (rowArgs.Item1.Expandable && !Grid.LoadChildData.HasDelegate)
|
||||
{
|
||||
<a id="@(Grid.GridId() + Item.GetHashCode())" aria-label="@Grid.ExpandChildItemAriaLabel" @onclick:preventDefault="true" @onclick="@(_ => Grid.ExpandItem(Item))" @onclick:stopPropagation>
|
||||
<span class="@(Grid.ExpandedItemStyle(Item))"></span>
|
||||
|
||||
@@ -45,7 +45,7 @@
|
||||
}
|
||||
else
|
||||
{
|
||||
<i class="rzi-circle-o-notch"></i>
|
||||
<i class="notranslate rzi-circle-o-notch"></i>
|
||||
}
|
||||
</div>
|
||||
}
|
||||
|
||||
@@ -1,15 +1,5 @@
|
||||
using Microsoft.AspNetCore.Components;
|
||||
using Microsoft.AspNetCore.Components.Forms;
|
||||
using Microsoft.AspNetCore.Components.Web;
|
||||
using Microsoft.JSInterop;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Collections.Specialized;
|
||||
using System.Data.Common;
|
||||
using System.Linq;
|
||||
using System.Linq.Dynamic.Core;
|
||||
using System.Text.Json;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Radzen.Blazor
|
||||
|
||||
@@ -1,30 +1,26 @@
|
||||
@using Radzen
|
||||
@using Radzen.Blazor.Rendering
|
||||
@using Microsoft.AspNetCore.Components.Forms
|
||||
@using System.Linq.Expressions
|
||||
@using System.Globalization
|
||||
@using Microsoft.JSInterop
|
||||
|
||||
@typeparam TValue
|
||||
@inherits RadzenComponent
|
||||
@implements IRadzenFormComponent
|
||||
@if (Visible)
|
||||
{
|
||||
<div @ref="@Element" @attributes="Attributes" class="@($"rz-datepicker{(Disabled ? " rz-state-disabled" : "")}") @GetCssClass()" style="@getStyle()" id="@GetId()">
|
||||
<div @ref="@Element" @attributes="Attributes" class="@GetCssClass()" style="@getStyle()" id="@GetId()">
|
||||
@if (!Inline)
|
||||
{
|
||||
<input @ref="@input" @attributes="InputAttributes" disabled="@Disabled" readonly="@IsReadonly" value="@FormattedValue" tabindex="@(Disabled ? "-1" : $"{TabIndex}")"
|
||||
@onchange="@ParseDate" autocomplete="off" type="text" name="@Name" @onkeydown="@(args => OnKeyPress(args))" @onkeydown:preventDefault=preventKeyPress @onkeydown:stopPropagation
|
||||
class="rz-inputtext @InputClass @(IsReadonly ? "rz-readonly" : "") @(!ShowButton ? "rz-input-trigger" : "")" id="@Name" placeholder="@Placeholder" />
|
||||
class="rz-inputtext @InputClass @(ReadOnly ? "rz-readonly" : "") @(!ShowButton ? "rz-input-trigger" : "")" id="@Name" placeholder="@CurrentPlaceholder" />
|
||||
@if (ShowButton)
|
||||
{
|
||||
<button aria-label="@ToggleAriaLabel" @onmousedown=@OnToggle class="@($"rz-datepicker-trigger rz-button rz-button-icon-only{(Disabled ? " rz-state-disabled" : "")}")" tabindex="-1" type="button">
|
||||
<button aria-label="@ToggleAriaLabel" @onmousedown=@OnToggle class="@($"rz-datepicker-trigger rz-button rz-button-icon-only{(Disabled ? " rz-state-disabled" : "")} {ButtonClass}")" tabindex="-1" type="button">
|
||||
<span aria-hidden="true" class="@ButtonClasses"></span><span class="rz-button-text"></span>
|
||||
</button>
|
||||
}
|
||||
@if (AllowClear && HasValue)
|
||||
{
|
||||
<i class="rz-dropdown-clear-icon rzi rzi-times" @onclick="@Clear" @onclick:stopPropagation="true"></i>
|
||||
<i class="notranslate rz-dropdown-clear-icon rzi rzi-times" @onclick="@Clear" @onclick:stopPropagation="true"></i>
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,11 +29,11 @@
|
||||
@if (!TimeOnly)
|
||||
{
|
||||
<div class="rz-calendar-header">
|
||||
<a id="@(GetId() + "pm")" tabindex="-1" aria-label="@PrevMonthAriaLabel" @onclick:preventDefault="true" class="rz-button rz-button-md rz-variant-text rz-button-icon-only rz-secondary rz-shade-default rz-calendar-prev" @onclick="@(async () => { if (!Disabled) { try { if(CurrentDate.AddMonths(-1).Year >= YearFrom) {CurrentDate = CurrentDate.AddMonths(-1);}} catch (ArgumentOutOfRangeException) {}} })">
|
||||
<span class="rzi rz-calendar-prev-icon"></span>
|
||||
<a id="@(GetId() + "pm")" tabindex="-1" aria-label="@PrevMonthAriaLabel" @onclick:preventDefault="true" class="rz-button rz-button-md rz-variant-text rz-button-icon-only rz-secondary rz-shade-default rz-calendar-prev" @onclick="@(() => { if (!Disabled) { try { if(CurrentDate.AddMonths(-1).Year >= YearFrom) {CurrentDate = CurrentDate.AddMonths(-1);}} catch (ArgumentOutOfRangeException) {}} })">
|
||||
<span class="notranslate rzi rz-calendar-prev-icon"></span>
|
||||
</a>
|
||||
<a id="@(GetId() + "nm")" tabindex="-1" aria-label="@NextMonthAriaLabel" @onclick:preventDefault="true" class="rz-button rz-button-md rz-variant-text rz-button-icon-only rz-secondary rz-shade-default rz-calendar-next" @onclick="@(async () => { if (!Disabled) { try { if(CurrentDate.AddMonths(1).Year <= YearTo) {CurrentDate = CurrentDate.AddMonths(1);}} catch (ArgumentOutOfRangeException) {} } })">
|
||||
<span class="rzi rz-calendar-next-icon"></span>
|
||||
<a id="@(GetId() + "nm")" tabindex="-1" aria-label="@NextMonthAriaLabel" @onclick:preventDefault="true" class="rz-button rz-button-md rz-variant-text rz-button-icon-only rz-secondary rz-shade-default rz-calendar-next" @onclick="@(() => { if (!Disabled) { try { if(CurrentDate.AddMonths(1).Year <= YearTo) {CurrentDate = CurrentDate.AddMonths(1);}} catch (ArgumentOutOfRangeException) {} } })">
|
||||
<span class="notranslate rzi rz-calendar-next-icon"></span>
|
||||
</a>
|
||||
<div class="rz-calendar-title">
|
||||
<RadzenDropDown @ref="monthDropDown" class="rz-calendar-month-dropdown" TabIndex="@TabIndex"
|
||||
@@ -45,11 +41,7 @@
|
||||
Change="@((args) => { SetMonth(int.Parse(args.ToString())); })"/>
|
||||
<RadzenDropDown @ref="yearDropDown" class="rz-calendar-year-dropdown" TabIndex="@TabIndex"
|
||||
TValue="int" Value="@CurrentDate.Year" Disabled="@Disabled" Data="@years" TextProperty="Name" ValueProperty="Value"
|
||||
Change="@((args) => { SetYear(int.Parse(args.ToString())); })">
|
||||
<Template>
|
||||
@Culture.Calendar.GetYear(new DateTime(context.Value,1,1))
|
||||
</Template>
|
||||
</RadzenDropDown>
|
||||
Change="@((args) => { SetYear(int.Parse(args.ToString())); })" />
|
||||
</div>
|
||||
</div>
|
||||
@if(ShowDays)
|
||||
@@ -116,37 +108,37 @@
|
||||
{
|
||||
<div class="rz-timepicker" @onmousedown:stopPropagation>
|
||||
<RadzenNumeric InputAttributes="@(new Dictionary<string,object>(){ { "aria-label", "hour" }})" 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"
|
||||
Min="@(HourFormat == "12" ? 1 : -1)" Max="@(HourFormat == "12" ? 12 : 24)" Step="@HoursStep"
|
||||
Change="@UpdateHour" class="rz-hour-picker" @oninput=@OnUpdateHourInput Format="@(PadHours ? "00" : "")" Name="@($"{UniqueID}-h")" />
|
||||
<div class="rz-separator">
|
||||
<span>:</span>
|
||||
</div>
|
||||
<RadzenNumeric InputAttributes="@(new Dictionary<string,object>(){ { "aria-label", "minutes" }})" TValue="int" Disabled="@Disabled" Value="CurrentDate.Minute" TValue="double" Step="@MinutesStep" Min="0" Max="59"
|
||||
<RadzenNumeric InputAttributes="@(new Dictionary<string,object>(){ { "aria-label", "minutes" }})" TValue="int" Disabled="@Disabled" Value="CurrentDate.Minute" Step="@MinutesStep" Min="0" Max="59"
|
||||
Change="@UpdateMinutes" class="rz-minute-picker" @oninput=@OnUpdateHourMinutes Format="@(PadMinutes ? "00" : "")" Name="@($"{UniqueID}-m")"/>
|
||||
@if (ShowSeconds)
|
||||
{
|
||||
<div class="rz-separator">
|
||||
<span>:</span>
|
||||
</div>
|
||||
<RadzenNumeric InputAttributes="@(new Dictionary<string,object>(){ { "aria-label", "seconds" }})" TValue="int" Disabled="@Disabled" Value="CurrentDate.Second" TValue="double" Step="@SecondsStep" Min="0" Max="59"
|
||||
<RadzenNumeric InputAttributes="@(new Dictionary<string,object>(){ { "aria-label", "seconds" }})" TValue="int" Disabled="@Disabled" Value="CurrentDate.Second" Step="@SecondsStep" Min="0" Max="59"
|
||||
Change="@UpdateSeconds" class="rz-second-picker" @oninput=@OnUpdateHourSeconds Format="@(PadSeconds ? "00" : "")" Name="@($"{UniqueID}-s")"/>
|
||||
}
|
||||
@if (HourFormat == "12")
|
||||
{
|
||||
<div class="rz-ampm-picker">
|
||||
<a id="@(GetId() + "ampmup")" tabindex="@(Disabled ? "-1" : $"{TabIndex}")" aria-label="@ToggleAmPmAriaLabel" @onclick:preventDefault="true" @onclick="@ToggleAmPm">
|
||||
<span class="rzi rzi-chevron-up"></span>
|
||||
<span class="notranslate rzi rzi-chevron-up"></span>
|
||||
</a>
|
||||
<span>@CurrentDate.ToString("tt")</span>
|
||||
<a id="@(GetId() + "ampmdown")" tabindex="@(Disabled ? "-1" : $"{TabIndex}")" aria-label="@ToggleAmPmAriaLabel" @onclick:preventDefault="true" @onclick="@ToggleAmPm">
|
||||
<span class="rzi rzi-chevron-down"></span>
|
||||
<span class="notranslate rzi rzi-chevron-down"></span>
|
||||
</a>
|
||||
</div>
|
||||
}
|
||||
@if (ShowTimeOkButton)
|
||||
{
|
||||
<button aria-label="@OkAriaLabel" type="button" class="rz-button rz-button-md rz-secondary" tabindex="0" @onclick="@(args => OkClick())">
|
||||
<span class="rz-button-text">Ok</span>
|
||||
<span class="rz-button-text">@OkAriaLabel</span>
|
||||
</button>
|
||||
}
|
||||
</div>
|
||||
|
||||
@@ -7,7 +7,6 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Linq.Dynamic.Core;
|
||||
using System.Linq.Expressions;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
@@ -286,9 +285,39 @@ namespace Radzen.Blazor
|
||||
YearTo = max.HasValue ? max.Value.Year : int.Parse(YearRange.Split(':').Last());
|
||||
months = Enumerable.Range(1, 12).Select(i => new NameValue() { Name = Culture.DateTimeFormat.GetMonthName(i), Value = i }).ToList();
|
||||
years = Enumerable.Range(YearFrom, YearTo - YearFrom + 1)
|
||||
.Select(i => new NameValue() { Name = $"{i}", Value = i }).ToList();
|
||||
.Select(i => new NameValue() { Name = YearFormatter(i), Value = i }).ToList();
|
||||
}
|
||||
|
||||
private string FormatYear(int year)
|
||||
{
|
||||
year = Culture.Calendar.GetYear(new DateTime(year, 1, 1));
|
||||
|
||||
var date = new DateTime(year, 1, 1);
|
||||
|
||||
return date.ToString(YearFormat, Culture);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="RadzenDatePicker{TValue}"/> class.
|
||||
/// </summary>
|
||||
public RadzenDatePicker()
|
||||
{
|
||||
YearFormatter = FormatYear;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the year formatter. Set to <c>FormatYear</c> by default.
|
||||
/// If set, this function will take precedence over <see cref="YearFormat"/>.
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
public Func<int, string> YearFormatter { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets ot sets the year format. Set to <c>yyyy</c> by default.
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
public string YearFormat { get; set; } = "yyyy";
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether value can be cleared.
|
||||
/// </summary>
|
||||
@@ -316,6 +345,12 @@ namespace Radzen.Blazor
|
||||
/// <value>The input CSS class.</value>
|
||||
[Parameter]
|
||||
public string InputClass { get; set; }
|
||||
/// <summary>
|
||||
/// Gets or sets the button CSS class.
|
||||
/// </summary>
|
||||
/// <value>The button CSS class.</value>
|
||||
[Parameter]
|
||||
public string ButtonClass { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the Minimum Selectable Date.
|
||||
@@ -697,7 +732,7 @@ namespace Radzen.Blazor
|
||||
|
||||
private string ButtonClasses
|
||||
{
|
||||
get => $"rz-button-icon-left rzi rzi-{(TimeOnly ? "time" : "calendar")}";
|
||||
get => $"notranslate rz-button-icon-left rzi rzi-{(TimeOnly ? "time" : "calendar")}";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -744,6 +779,12 @@ namespace Radzen.Blazor
|
||||
[Parameter]
|
||||
public bool Disabled { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the FormFieldContext of the component
|
||||
/// </summary>
|
||||
[CascadingParameter]
|
||||
public IFormFieldContext FormFieldContext { get; set; } = null;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether days part is shown.
|
||||
/// </summary>
|
||||
@@ -911,6 +952,9 @@ namespace Radzen.Blazor
|
||||
return $"{(Inline ? "overflow:auto;" : "")}{(Style != null ? Style : "")}";
|
||||
}
|
||||
|
||||
/// <summary> Gets the current placeholder. Returns empty string if this component is inside a RadzenFormField.</summary>
|
||||
protected string CurrentPlaceholder => FormFieldContext?.AllowFloatingLabel == true ? " " : Placeholder;
|
||||
|
||||
/// <summary>
|
||||
/// Closes this instance popup.
|
||||
/// </summary>
|
||||
@@ -971,10 +1015,13 @@ namespace Radzen.Blazor
|
||||
/// <inheritdoc />
|
||||
protected override string GetComponentCssClass()
|
||||
{
|
||||
return ClassList.Create()
|
||||
return ClassList.Create("rz-datepicker")
|
||||
.Add("rz-datepicker-inline", Inline)
|
||||
.AddDisabled(Disabled)
|
||||
.Add("rz-state-empty", !HasValue)
|
||||
.Add(FieldIdentifier, EditContext)
|
||||
.ToString();
|
||||
|
||||
}
|
||||
|
||||
private async Task SetDay(DateTime newValue)
|
||||
@@ -1051,8 +1098,15 @@ namespace Radzen.Blazor
|
||||
shouldClose = !visible;
|
||||
}
|
||||
|
||||
var disabledChanged = parameters.DidParameterChange(nameof(Disabled), Disabled);
|
||||
|
||||
await base.SetParametersAsync(parameters);
|
||||
|
||||
if (disabledChanged)
|
||||
{
|
||||
FormFieldContext?.DisabledChanged(Disabled);
|
||||
}
|
||||
|
||||
if (shouldClose && !firstRender && IsJSRuntimeAvailable)
|
||||
{
|
||||
await JSRuntime.InvokeVoidAsync("Radzen.destroyPopup", PopupID);
|
||||
@@ -1143,14 +1197,20 @@ namespace Radzen.Blazor
|
||||
|
||||
string GetDayCssClass(DateTime date, DateRenderEventArgs dateArgs, bool forCell = true)
|
||||
{
|
||||
return ClassList.Create()
|
||||
var list = ClassList.Create()
|
||||
.Add("rz-state-default", !forCell)
|
||||
.Add("rz-calendar-other-month", CurrentDate.Month != date.Month)
|
||||
.Add("rz-state-active", !forCell && DateTimeValue.HasValue && DateTimeValue.Value.Date.CompareTo(date.Date) == 0)
|
||||
.Add("rz-calendar-today", !forCell && DateTime.Now.Date.CompareTo(date.Date) == 0)
|
||||
.Add("rz-state-focused", !forCell && FocusedDate.Date.CompareTo(date.Date) == 0)
|
||||
.Add("rz-state-disabled", !forCell && dateArgs.Disabled)
|
||||
.ToString();
|
||||
.Add("rz-state-disabled", !forCell && dateArgs.Disabled);
|
||||
|
||||
if (dateArgs.Attributes != null && dateArgs.Attributes.TryGetValue("class", out var @class) && !string.IsNullOrEmpty(Convert.ToString(@class)))
|
||||
{
|
||||
list.Add($"{@class}", true);
|
||||
}
|
||||
|
||||
return list.ToString();
|
||||
}
|
||||
async Task OnCalendarKeyPress(KeyboardEventArgs args)
|
||||
{
|
||||
@@ -1174,10 +1234,13 @@ namespace Radzen.Blazor
|
||||
{
|
||||
preventKeyPress = true;
|
||||
|
||||
await SetDay(FocusedDate);
|
||||
if (!DateAttributes(FocusedDate).Disabled)
|
||||
{
|
||||
await SetDay(FocusedDate);
|
||||
|
||||
await ClosePopup();
|
||||
await FocusAsync();
|
||||
await ClosePopup();
|
||||
await FocusAsync();
|
||||
}
|
||||
}
|
||||
else if (key == "Escape")
|
||||
{
|
||||
@@ -1250,6 +1313,8 @@ namespace Radzen.Blazor
|
||||
|
||||
internal async Task TogglePopup()
|
||||
{
|
||||
if (Inline) return;
|
||||
|
||||
if (PopupRenderMode == PopupRenderMode.Initial)
|
||||
{
|
||||
await JSRuntime.InvokeVoidAsync("Radzen.togglePopup", Element, PopupID, false, null, null, true, true);
|
||||
@@ -1262,6 +1327,8 @@ namespace Radzen.Blazor
|
||||
|
||||
async Task ClosePopup()
|
||||
{
|
||||
if (Inline) return;
|
||||
|
||||
if (PopupRenderMode == PopupRenderMode.Initial)
|
||||
{
|
||||
await JSRuntime.InvokeVoidAsync("Radzen.closePopup", PopupID);
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
@if (sideDialogOptions.ShowClose)
|
||||
{
|
||||
<a id="@(sideDialogOptions.GetHashCode() + "cl")" aria-label="@CloseSideDialogAriaLabel" @onclick:preventDefault="true" class="rz-dialog-side-titlebar-close" @onclick="@(_ => Service.CloseSide(null))" role="button" tabindex="@sideDialogOptions.CloseTabIndex">
|
||||
<span class="rzi rzi-times"></span>
|
||||
<span class="notranslate rzi rzi-times"></span>
|
||||
</a>
|
||||
}
|
||||
</div>
|
||||
|
||||
@@ -106,7 +106,7 @@
|
||||
}
|
||||
|
||||
<div class="rz-dropdown-trigger rz-corner-right">
|
||||
<span class="rz-dropdown-trigger-icon rzi rzi-chevron-down"></span>
|
||||
<span class="notranslate rz-dropdown-trigger-icon rzi rzi-chevron-down"></span>
|
||||
</div>
|
||||
|
||||
<div id="@PopupID" class="@(Multiple ? "rz-multiselect-panel" : "rz-dropdown-panel")"
|
||||
@@ -137,8 +137,8 @@
|
||||
<div class="rz-helper-hidden-accessible">
|
||||
<input readonly="readonly" type="checkbox" id="@($"{(Name ?? UniqueID + "sa")}")" aria-label="@SearchAriaLabel" aria-checked="@(IsAllSelected().ToString().ToLowerInvariant())">
|
||||
</div>
|
||||
<div class="@(IsAllSelected() ? "rz-chkbox-box rz-state-active" : "rz-chkbox-box")">
|
||||
<span class="@(IsAllSelected() ? "rz-chkbox-icon rzi rzi-check" : "rz-chkbox-icon")"></span>
|
||||
<div class="@(IsAllSelected() ? "notranslate rz-chkbox-box rz-state-active" : "notranslate rz-chkbox-box")">
|
||||
<span class="@(IsAllSelected() ? "notranslate rz-chkbox-icon rzi rzi-check" : "notranslate rz-chkbox-icon")"></span>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
@@ -152,12 +152,12 @@
|
||||
<input id="@SearchID" tabindex="@(Disabled ? "-1" : $"{TabIndex}")" class="rz-inputtext" role="textbox" type="text"
|
||||
onclick="Radzen.preventDefaultAndStopPropagation(event)" aria-label="@SearchAriaLabel"
|
||||
@ref="@search" @oninput=@(args => { searchText = $"{args.Value}"; SearchTextChanged.InvokeAsync(searchText);})
|
||||
@onchange="@((args) => OnFilter(args))" @onkeydown="@((args) => OnFilterKeyPress(args))" value="@searchText" />
|
||||
<span class="rz-multiselect-filter-icon rzi rzi-search"></span>
|
||||
@onchange="@((args) => OnFilter(args))" @onkeydown="@((args) => OnFilterKeyPress(args))" value="@searchText" autocomplete="@FilterAutoCompleteType" />
|
||||
<span class="notranslate rz-multiselect-filter-icon rzi rzi-search"></span>
|
||||
</div>
|
||||
}
|
||||
<a id="@(GetId() + "clear")" class="rz-multiselect-close " @onclick="@ClearAll" @onclick:stopPropagation="true">
|
||||
<span class="rzi rzi-times"></span>
|
||||
<span class="notranslate rzi rzi-times"></span>
|
||||
</a>
|
||||
</div>
|
||||
}
|
||||
@@ -180,7 +180,7 @@
|
||||
</div>
|
||||
@if (AllowClear && (!Multiple && HasValue || Multiple && selectedItems.Count > 0))
|
||||
{
|
||||
<i class="rz-dropdown-clear-icon rzi rzi-times" @onclick="@ClearAll" @onclick:stopPropagation="true"></i>
|
||||
<i class="notranslate rz-dropdown-clear-icon rzi rzi-times" @onclick="@ClearAll" @onclick:stopPropagation="true"></i>
|
||||
}
|
||||
</div>
|
||||
}
|
||||
@@ -191,10 +191,10 @@
|
||||
return __builder => {
|
||||
<text>
|
||||
<div class="rz-dropdown-filter-container">
|
||||
<input aria-label="@SearchAriaLabel" id="@SearchID" @ref="@search" tabindex="@(Disabled ? "-1" : $"{TabIndex}")" placeholder="@FilterPlaceholder" class="rz-dropdown-filter rz-inputtext" autocomplete="off" aria-autocomplete="none" type="text"
|
||||
<input aria-label="@SearchAriaLabel" id="@SearchID" @ref="@search" tabindex="@(Disabled ? "-1" : $"{TabIndex}")" placeholder="@FilterPlaceholder" class="rz-dropdown-filter rz-inputtext" autocomplete="@FilterAutoCompleteType" aria-autocomplete="none" type="text"
|
||||
@onchange="@OnFilter" @onkeydown="@OnFilterKeyPress"
|
||||
@bind:event="oninput" @bind:get="searchText" @bind:set="@(args => { searchText = $"{args}"; SearchTextChanged.InvokeAsync(searchText);})" />
|
||||
<span class="rz-dropdown-filter-icon rzi rzi-search"></span>
|
||||
<span class="notranslate rz-dropdown-filter-icon rzi rzi-search"></span>
|
||||
</div>
|
||||
</text>
|
||||
};
|
||||
@@ -202,10 +202,10 @@
|
||||
return __builder => {
|
||||
<text>
|
||||
<div class="rz-dropdown-filter-container">
|
||||
<input aria-label="@SearchAriaLabel" id="@SearchID" @ref="@search" tabindex="@(Disabled ? "-1" : $"{TabIndex}")" placeholder="@FilterPlaceholder" class="rz-dropdown-filter rz-inputtext" autocomplete="off" aria-autocomplete="none" type="text"
|
||||
<input aria-label="@SearchAriaLabel" id="@SearchID" @ref="@search" tabindex="@(Disabled ? "-1" : $"{TabIndex}")" placeholder="@FilterPlaceholder" class="rz-dropdown-filter rz-inputtext" autocomplete="@FilterAutoCompleteType" aria-autocomplete="none" type="text"
|
||||
@onchange="@OnFilter" @onkeydown="@OnFilterKeyPress" value="@searchText"
|
||||
@oninput="@((ChangeEventArgs args) => { searchText = $"{args.Value}"; SearchTextChanged.InvokeAsync(searchText);})" />
|
||||
<span class="rz-dropdown-filter-icon rzi rzi-search"></span>
|
||||
<span class="notranslate rz-dropdown-filter-icon rzi rzi-search"></span>
|
||||
</div>
|
||||
</text>
|
||||
};
|
||||
|
||||
@@ -19,6 +19,7 @@ namespace Radzen.Blazor
|
||||
/// </example>
|
||||
public partial class RadzenDropDown<TValue> : DropDownBase<TValue>
|
||||
{
|
||||
bool isOpen;
|
||||
/// <summary>
|
||||
/// Specifies additional custom attributes that will be rendered by the input.
|
||||
/// </summary>
|
||||
@@ -68,6 +69,13 @@ namespace Radzen.Blazor
|
||||
[Parameter]
|
||||
public string FilterPlaceholder { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or Sets the filter autocomplete type.
|
||||
/// </summary>
|
||||
/// <value>The filter autocomplete type. Default: Off</value>
|
||||
[Parameter]
|
||||
public AutoCompleteType FilterAutoCompleteType { get; set; } = AutoCompleteType.Off;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the row render callback. Use it to set row attributes.
|
||||
/// </summary>
|
||||
@@ -110,8 +118,8 @@ namespace Radzen.Blazor
|
||||
of = OpenOnFocus;
|
||||
OpenOnFocus = false;
|
||||
}
|
||||
|
||||
await JSRuntime.InvokeVoidAsync("Radzen.closePopup", PopupID);
|
||||
isOpen = false;
|
||||
await JSRuntime.InvokeVoidAsync("Radzen.closePopup", PopupID, Reference, nameof(OnClose));
|
||||
|
||||
if (key == "Enter")
|
||||
{
|
||||
@@ -131,7 +139,20 @@ namespace Radzen.Blazor
|
||||
if (Disabled)
|
||||
return;
|
||||
|
||||
await JSRuntime.InvokeVoidAsync(OpenOnFocus ? "Radzen.openPopup" : "Radzen.togglePopup", Element, PopupID, true);
|
||||
if (!isOpen)
|
||||
{
|
||||
await Open.InvokeAsync(null);
|
||||
}
|
||||
|
||||
isOpen = true;
|
||||
if (OpenOnFocus)
|
||||
{
|
||||
await JSRuntime.InvokeVoidAsync("Radzen.openPopup", Element, PopupID, true, null, null, null, Reference, nameof(OnClose));
|
||||
}
|
||||
else
|
||||
{
|
||||
await JSRuntime.InvokeVoidAsync("Radzen.togglePopup", Element, PopupID, true, Reference, nameof(OnClose));
|
||||
}
|
||||
await JSRuntime.InvokeVoidAsync("Radzen.focusElement", isFilter ? UniqueID : SearchID);
|
||||
|
||||
if (list != null && selectedIndex != -1)
|
||||
@@ -191,6 +212,18 @@ namespace Radzen.Blazor
|
||||
[Parameter]
|
||||
public string SelectAllText { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Callback for when a dropdown is opened.
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
public EventCallback Open { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Callback for when a dropdown is closed.
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
public EventCallback Close { get; set; }
|
||||
|
||||
private bool visibleChanged = false;
|
||||
private bool disabledChanged = false;
|
||||
private bool firstRender = true;
|
||||
@@ -277,7 +310,8 @@ namespace Radzen.Blazor
|
||||
{
|
||||
if (!Multiple && !isFromKey)
|
||||
{
|
||||
await JSRuntime.InvokeVoidAsync("Radzen.closePopup", PopupID);
|
||||
isOpen = false;
|
||||
await JSRuntime.InvokeVoidAsync("Radzen.closePopup", PopupID, Reference, nameof(OnClose));
|
||||
}
|
||||
|
||||
if (ClearSearchAfterSelection)
|
||||
@@ -330,9 +364,20 @@ namespace Radzen.Blazor
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called when popup is closed.
|
||||
/// </summary>
|
||||
[JSInvokable]
|
||||
public async Task OnClose()
|
||||
{
|
||||
isOpen = false;
|
||||
await Close.InvokeAsync();
|
||||
}
|
||||
|
||||
internal async Task PopupClose()
|
||||
{
|
||||
await JSRuntime.InvokeVoidAsync("Radzen.closePopup", PopupID);
|
||||
isOpen = false;
|
||||
await JSRuntime.InvokeVoidAsync("Radzen.closePopup", PopupID, Reference, nameof(OnClose));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -37,7 +37,7 @@
|
||||
}
|
||||
else if ((selectedItems.Count > 0 || SelectedValue is IEnumerable && !(SelectedValue is string)) && Multiple)
|
||||
{
|
||||
var itemsToUse = SelectedValue is IEnumerable && !(SelectedValue is string) ? ((IEnumerable)SelectedValue).Cast<object>().ToList() : selectedItems;
|
||||
var itemsToUse = SelectedValue is IEnumerable && !(SelectedValue is string) ? ((IEnumerable)SelectedValue).Cast<object>().ToHashSet() : selectedItems;
|
||||
@if (itemsToUse.Count < MaxSelectedLabels && Chips)
|
||||
{
|
||||
<div class="rz-dropdown-chips-wrapper">
|
||||
@@ -108,7 +108,7 @@
|
||||
}
|
||||
|
||||
<div class="rz-dropdown-trigger rz-corner-right">
|
||||
<span class="rz-dropdown-trigger-icon rzi rzi-chevron-down"></span>
|
||||
<span class="notranslate rz-dropdown-trigger-icon rzi rzi-chevron-down"></span>
|
||||
</div>
|
||||
|
||||
<div id="@PopupID" class="@(Multiple ? "rz-multiselect-panel" : "rz-dropdown-panel")"
|
||||
@@ -127,13 +127,13 @@
|
||||
@if (ShowSearch)
|
||||
{
|
||||
<button tabindex="0" class="rz-button rz-button-md rz-button-icon-only rz-primary" type="button" title="@SearchTextPlaceholder" @onclick="@((args) => OnFilter(new ChangeEventArgs()))">
|
||||
<i class="rz-button-icon-left rzi">search</i>
|
||||
<i class="notranslate rz-button-icon-left rzi">search</i>
|
||||
</button>
|
||||
}
|
||||
@if (ShowAdd)
|
||||
{
|
||||
<button tabindex="0" class="rz-button rz-button-md rz-button-icon-only rz-primary" style="margin-left: 5px" type="button" title="@AddAriaLabel" @onclick="@OnAddClick">
|
||||
<i class="rz-button-icon-left rzi">add</i>
|
||||
<i class="notranslate rz-button-icon-left rzi">add</i>
|
||||
</button>
|
||||
}
|
||||
</div>
|
||||
@@ -189,7 +189,7 @@
|
||||
|
||||
@if (AllowClear && (!Multiple && HasValue || Multiple && (selectedItems.Count > 0 || SelectedValue is IEnumerable)))
|
||||
{
|
||||
<i class="rz-dropdown-clear-icon rzi rzi-times" @onclick="@Clear" @onclick:stopPropagation="true"></i>
|
||||
<i class="notranslate rz-dropdown-clear-icon rzi rzi-times" @onclick="@Clear" @onclick:stopPropagation="true"></i>
|
||||
}
|
||||
</div>
|
||||
}
|
||||
|
||||
@@ -5,7 +5,6 @@ using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Linq.Dynamic.Core;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Radzen.Blazor
|
||||
@@ -202,6 +201,13 @@ namespace Radzen.Blazor
|
||||
[Parameter]
|
||||
public bool ShowAdd { get; set; } = false;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets preserving the selected row index on pageing.
|
||||
/// </summary>
|
||||
/// <value>Row selection preservation on pageing.</value>
|
||||
[Parameter]
|
||||
public bool PreserveRowSelectionOnPaging { get; set; } = false;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the page numbers count.
|
||||
/// </summary>
|
||||
@@ -347,6 +353,7 @@ namespace Radzen.Blazor
|
||||
/// </summary>
|
||||
protected ElementReference popup;
|
||||
|
||||
bool isFirstRender;
|
||||
/// <summary>
|
||||
/// Called when [after render asynchronous].
|
||||
/// </summary>
|
||||
@@ -354,6 +361,8 @@ namespace Radzen.Blazor
|
||||
/// <returns>Task.</returns>
|
||||
protected override async Task OnAfterRenderAsync(bool firstRender)
|
||||
{
|
||||
isFirstRender = firstRender;
|
||||
|
||||
if (firstRender)
|
||||
{
|
||||
if(Visible && LoadData.HasDelegate && Data == null)
|
||||
@@ -390,7 +399,7 @@ namespace Radzen.Blazor
|
||||
if (!LoadData.HasDelegate)
|
||||
{
|
||||
searchText = null;
|
||||
await OnLoadData(new Radzen.LoadDataArgs() { Skip = 0, Top = PageSize });
|
||||
await OnLoadData(new Radzen.LoadDataArgs() { Skip = 0, Top = PageSize, OrderBy = "" });
|
||||
}
|
||||
}
|
||||
|
||||
@@ -405,7 +414,7 @@ namespace Radzen.Blazor
|
||||
|
||||
if (!string.IsNullOrEmpty(searchText) && !LoadData.HasDelegate)
|
||||
{
|
||||
await OnLoadData(new Radzen.LoadDataArgs() { Skip = skip, Top = PageSize });
|
||||
await OnLoadData(new Radzen.LoadDataArgs() { Skip = skip, Top = PageSize, OrderBy = "" });
|
||||
}
|
||||
}
|
||||
|
||||
@@ -415,7 +424,7 @@ namespace Radzen.Blazor
|
||||
public async Task Reload()
|
||||
{
|
||||
searchText = null;
|
||||
await OnLoadData(new Radzen.LoadDataArgs() { Skip = 0, Top = PageSize });
|
||||
await OnLoadData(new Radzen.LoadDataArgs() { Skip = 0, Top = PageSize, OrderBy = "" });
|
||||
}
|
||||
|
||||
private string GetPropertyFilterExpression(string property, string filterCaseSensitivityOperator)
|
||||
@@ -440,6 +449,7 @@ namespace Radzen.Blazor
|
||||
}
|
||||
|
||||
string prevSearch;
|
||||
string prevOrder = "";
|
||||
int? skip;
|
||||
async Task OnLoadData(LoadDataArgs args)
|
||||
{
|
||||
@@ -458,10 +468,13 @@ namespace Radzen.Blazor
|
||||
if (query == null)
|
||||
return;
|
||||
|
||||
var filterOperator = FilterOperator == StringFilterOperator.Contains ?
|
||||
Radzen.FilterOperator.Contains :
|
||||
FilterOperator == StringFilterOperator.StartsWith ? Radzen.FilterOperator.StartsWith :
|
||||
FilterOperator == StringFilterOperator.EndsWith ? Radzen.FilterOperator.EndsWith : Radzen.FilterOperator.Equals;
|
||||
|
||||
if (!string.IsNullOrEmpty(searchText))
|
||||
{
|
||||
string filterCaseSensitivityOperator = FilterCaseSensitivity == FilterCaseSensitivity.CaseInsensitive ? ".ToLower()" : "";
|
||||
|
||||
if (AllowFilteringByAllStringColumns && grid != null)
|
||||
{
|
||||
if (AllowFilteringByWord)
|
||||
@@ -470,16 +483,16 @@ namespace Radzen.Blazor
|
||||
|
||||
foreach (string word in words)
|
||||
{
|
||||
query = query.Where(DynamicLinqCustomTypeProvider.ParsingConfig, string.Join(" || ", grid.ColumnsCollection.Where(c => c.Filterable && IsColumnFilterPropertyTypeString(c))
|
||||
.Select(c => GetPropertyFilterExpression(c.GetFilterProperty(), filterCaseSensitivityOperator))),
|
||||
FilterCaseSensitivity == FilterCaseSensitivity.CaseInsensitive ? word.ToLower() : word);
|
||||
query = query.Where(grid.ColumnsCollection.Where(c => c.Filterable && IsColumnFilterPropertyTypeString(c))
|
||||
.Select(c => new FilterDescriptor() { Property = c.GetFilterProperty(), FilterValue = word, FilterOperator = filterOperator }),
|
||||
LogicalFilterOperator.Or, FilterCaseSensitivity);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
query = query.Where(DynamicLinqCustomTypeProvider.ParsingConfig, string.Join(" || ", grid.ColumnsCollection.Where(c => c.Filterable && IsColumnFilterPropertyTypeString(c))
|
||||
.Select(c => GetPropertyFilterExpression(c.GetFilterProperty(), filterCaseSensitivityOperator))),
|
||||
FilterCaseSensitivity == FilterCaseSensitivity.CaseInsensitive ? searchText.ToLower() : searchText);
|
||||
query = query.Where(grid.ColumnsCollection.Where(c => c.Filterable && IsColumnFilterPropertyTypeString(c))
|
||||
.Select(c => new FilterDescriptor() { Property = c.GetFilterProperty(), FilterValue = searchText, FilterOperator = filterOperator }),
|
||||
LogicalFilterOperator.Or, FilterCaseSensitivity);
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -490,33 +503,48 @@ namespace Radzen.Blazor
|
||||
|
||||
foreach (string word in words)
|
||||
{
|
||||
query = query.Where(DynamicLinqCustomTypeProvider.ParsingConfig, $"{GetPropertyFilterExpression(TextProperty, filterCaseSensitivityOperator)}",
|
||||
FilterCaseSensitivity == FilterCaseSensitivity.CaseInsensitive ? word.ToLower() : word);
|
||||
query = query.Where(TextProperty, word, FilterOperator, FilterCaseSensitivity);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
query = query.Where(DynamicLinqCustomTypeProvider.ParsingConfig, $"{GetPropertyFilterExpression(TextProperty, filterCaseSensitivityOperator)}",
|
||||
FilterCaseSensitivity == FilterCaseSensitivity.CaseInsensitive ? searchText.ToLower() : searchText);
|
||||
query = query.Where(TextProperty, searchText, FilterOperator, FilterCaseSensitivity);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(args.OrderBy))
|
||||
{
|
||||
query = query.OrderBy(DynamicLinqCustomTypeProvider.ParsingConfig, args.OrderBy);
|
||||
query = query.OrderBy(args.OrderBy);
|
||||
}
|
||||
|
||||
count = await Task.FromResult(query.Count());
|
||||
count = await Task.FromResult(query.Cast<object>().Count());
|
||||
|
||||
pagedData = await Task.FromResult(QueryableExtension.ToList(query.Skip(skip.HasValue ? skip.Value : 0).Take(args.Top.HasValue ? args.Top.Value : PageSize)).Cast<object>());
|
||||
pagedData = await Task.FromResult(query.Cast<object>().Skip(skip.HasValue ? skip.Value : 0).Take(args.Top.HasValue ? args.Top.Value : PageSize).ToList());
|
||||
|
||||
_internalView = query;
|
||||
|
||||
if (prevOrder != args.OrderBy)
|
||||
{
|
||||
prevOrder = args.OrderBy;
|
||||
await JSRuntime.InvokeVoidAsync("eval");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
await LoadData.InvokeAsync(new Radzen.LoadDataArgs() { Skip = skip, Top = args.Top, OrderBy = args.OrderBy, Filter = searchText });
|
||||
}
|
||||
|
||||
if(PreserveRowSelectionOnPaging && selectedIndex != -1)
|
||||
{
|
||||
var items = (LoadData.HasDelegate ? Data != null ? Data : Enumerable.Empty<object>() : (pagedData != null ? pagedData : Enumerable.Empty<object>())).OfType<object>().ToList();
|
||||
selectedIndex = Math.Clamp(selectedIndex, 0, items.Count - 1);
|
||||
|
||||
await JSRuntime.InvokeAsync<int[]>("Radzen.focusTableRow", grid.GridId(), "ArrowDown", selectedIndex - 1, null);
|
||||
|
||||
await grid.OnRowSelect(items[selectedIndex], false);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
IEnumerable _internalView = Enumerable.Empty<object>();
|
||||
@@ -559,7 +587,11 @@ namespace Radzen.Blazor
|
||||
|
||||
if (!string.IsNullOrEmpty(ValueProperty))
|
||||
{
|
||||
var item = Query.Where(DynamicLinqCustomTypeProvider.ParsingConfig, $@"{ValueProperty} == @0", value).FirstOrDefault();
|
||||
var item = Query.Where(new FilterDescriptor[]
|
||||
{
|
||||
new FilterDescriptor() { Property = ValueProperty, FilterValue = value }
|
||||
}, LogicalFilterOperator.And, FilterCaseSensitivity.Default).FirstOrDefault();
|
||||
|
||||
if (item != null && SelectedItem != item)
|
||||
{
|
||||
SelectedItem = item;
|
||||
@@ -580,6 +612,15 @@ namespace Radzen.Blazor
|
||||
SelectedItemChanged.InvokeAsync(SelectedItem);
|
||||
selectedItems.Clear();
|
||||
selectedItems.Add(SelectedItem);
|
||||
try
|
||||
{
|
||||
if (grid != null && !isFirstRender)
|
||||
{
|
||||
InvokeAsync(() => grid.SelectRow(SelectedItem, false));
|
||||
JSRuntime.InvokeAsync<int[]>("Radzen.focusTableRow", grid.GridId(), "ArrowDown", Items.ToList().IndexOf(SelectedItem) - 1, null);
|
||||
}
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -592,8 +633,12 @@ namespace Radzen.Blazor
|
||||
{
|
||||
foreach (object v in valueList)
|
||||
{
|
||||
var item = Query.Where(DynamicLinqCustomTypeProvider.ParsingConfig, $@"{ValueProperty} == @0", v).FirstOrDefault();
|
||||
if (item != null && !selectedItems.AsQueryable().Where(DynamicLinqCustomTypeProvider.ParsingConfig, $@"object.Equals(it.{ValueProperty},@0)", v).Any())
|
||||
var item = Query.Where(new FilterDescriptor[]
|
||||
{
|
||||
new FilterDescriptor() { Property = ValueProperty, FilterValue = v }
|
||||
}, LogicalFilterOperator.And, FilterCaseSensitivity.Default).FirstOrDefault();
|
||||
|
||||
if (item != null && !selectedItems.AsQueryable().Where(i => object.Equals(GetItemOrValueFromProperty(i, ValueProperty), v)).Any())
|
||||
{
|
||||
selectedItems.Add(item);
|
||||
}
|
||||
@@ -603,10 +648,7 @@ namespace Radzen.Blazor
|
||||
{
|
||||
foreach (object v in valueList)
|
||||
{
|
||||
if (selectedItems.IndexOf(v) == -1)
|
||||
{
|
||||
selectedItems.Add(v);
|
||||
}
|
||||
selectedItems.Add(v);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -629,6 +671,8 @@ namespace Radzen.Blazor
|
||||
if (Disabled)
|
||||
return;
|
||||
|
||||
var canRequest = searchText != null;
|
||||
|
||||
searchText = null;
|
||||
internalValue = default(TValue);
|
||||
selectedItem = null;
|
||||
@@ -644,7 +688,10 @@ namespace Radzen.Blazor
|
||||
await grid.SelectRow(null);
|
||||
}
|
||||
|
||||
await OnLoadData(new Radzen.LoadDataArgs() { Skip = 0, Top = PageSize });
|
||||
if (canRequest)
|
||||
{
|
||||
await OnLoadData(new Radzen.LoadDataArgs() { Skip = 0, Top = PageSize, OrderBy = "" });
|
||||
}
|
||||
|
||||
StateHasChanged();
|
||||
}
|
||||
@@ -669,7 +716,7 @@ namespace Radzen.Blazor
|
||||
if (shouldChange)
|
||||
{
|
||||
selectedIndex = newSelectedIndex;
|
||||
await JSRuntime.InvokeAsync<int[]>("Radzen.focusTableRow", grid.GridId(), key, selectedIndex - 1, null);
|
||||
await JSRuntime.InvokeAsync<int[]>("Radzen.focusTableRow", grid.GridId(), key, selectedIndex + (key == "ArrowUp" ? 1 : -1), null);
|
||||
await grid.OnRowSelect(items[selectedIndex], false);
|
||||
}
|
||||
|
||||
@@ -896,8 +943,11 @@ namespace Radzen.Blazor
|
||||
await SelectItem(item);
|
||||
}
|
||||
}
|
||||
|
||||
async Task CloseAndFocus()
|
||||
/// <summary>
|
||||
/// Closes the dropdown popup and sets focus to the input element.
|
||||
/// </summary>
|
||||
/// <returns>A task that represents the asynchronous operation.</returns>
|
||||
public async Task CloseAndFocus()
|
||||
{
|
||||
if (!Disabled && !Multiple)
|
||||
{
|
||||
|
||||
@@ -14,8 +14,8 @@ Disabled = itemArgs.Disabled;
|
||||
@onclick:preventDefault @onclick="args=>SelectItem(args,true)"
|
||||
@attributes="@(itemArgs.Attributes.Any() ? itemArgs.Attributes : Attributes)">
|
||||
<div class="rz-chkbox ">
|
||||
<div class="@(DropDown.IsSelected(Item) ? "rz-chkbox-box rz-state-active" : "rz-chkbox-box") @(Disabled ? " rz-state-disabled " : "")">
|
||||
<span class="@(DropDown.IsSelected(Item) ? "rz-chkbox-icon rzi rzi-check" : "rz-chkbox-icon")"></span>
|
||||
<div class="@(DropDown.IsSelected(Item) ? "notranslate rz-chkbox-box rz-state-active" : "notranslate rz-chkbox-box") @(Disabled ? " rz-state-disabled " : "")">
|
||||
<span class="@(DropDown.IsSelected(Item) ? "notranslate rz-chkbox-icon rzi rzi-check" : "notranslate rz-chkbox-icon")"></span>
|
||||
</div>
|
||||
</div>
|
||||
<span class="rz-multiselect-item-content">
|
||||
|
||||
@@ -18,18 +18,29 @@ namespace Radzen.Blazor
|
||||
[CascadingParameter]
|
||||
RadzenDropZoneContainer<TItem> Container { get; set; }
|
||||
|
||||
void OnDragStart()
|
||||
void EnsurePayload(DragEventArgs args = null)
|
||||
{
|
||||
dragCssClass = "rz-dragging";
|
||||
Container.Payload = new RadzenDropZoneItemEventArgs<TItem>()
|
||||
{
|
||||
FromZone = Zone,
|
||||
Item = Item
|
||||
Item = Item,
|
||||
DataTransfer = args?.DataTransfer
|
||||
};
|
||||
}
|
||||
|
||||
void OnDragStart()
|
||||
{
|
||||
dragCssClass = "rz-dragging";
|
||||
EnsurePayload();
|
||||
}
|
||||
|
||||
void OnDragOver(DragEventArgs args)
|
||||
{
|
||||
if (Container.Payload == null)
|
||||
{
|
||||
EnsurePayload(args);
|
||||
}
|
||||
|
||||
Container.Payload.ToItem = Item;
|
||||
|
||||
var canDrop = Zone.CanDrop();
|
||||
@@ -51,6 +62,10 @@ namespace Radzen.Blazor
|
||||
|
||||
async Task OnDrop(DragEventArgs args)
|
||||
{
|
||||
if (Container.Payload == null)
|
||||
{
|
||||
EnsurePayload(args);
|
||||
}
|
||||
cssClass = "";
|
||||
Container.Payload.ToItem = Item;
|
||||
await Zone.OnDropInternal();
|
||||
|
||||
@@ -14,16 +14,16 @@
|
||||
tabindex="0" @onkeypress="@(args => OnKeyPress(args, Toggle(new EventArgs())))" @onkeypress:preventDefault=preventKeyPress @onkeypress:stopPropagation>
|
||||
@if (collapsed)
|
||||
{
|
||||
<span class="rz-fieldset-toggler rzi rzi-w rzi-plus"></span>
|
||||
<span class="notranslate rz-fieldset-toggler rzi rzi-w rzi-plus"></span>
|
||||
}
|
||||
else
|
||||
{
|
||||
<span class="rz-fieldset-toggler rzi rzi-w rzi-minus"></span>
|
||||
<span class="notranslate rz-fieldset-toggler rzi rzi-w rzi-minus"></span>
|
||||
}
|
||||
|
||||
@if (!string.IsNullOrEmpty(Icon))
|
||||
{
|
||||
<i class="rzi" style="@(!string.IsNullOrEmpty(IconColor) ? $"color:{IconColor}" : null)">@((MarkupString)Icon)</i><span>@Text</span>
|
||||
<i class="notranslate rzi" style="@(!string.IsNullOrEmpty(IconColor) ? $"color:{IconColor}" : null)">@((MarkupString)Icon)</i><span>@Text</span>
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -36,7 +36,7 @@
|
||||
{
|
||||
@if (!string.IsNullOrEmpty(Icon))
|
||||
{
|
||||
<i class="rzi" style="@(!string.IsNullOrEmpty(IconColor) ? $"color:{IconColor}" : null)">@((MarkupString)Icon)</i><span>@Text</span>
|
||||
<i class="notranslate rzi" style="@(!string.IsNullOrEmpty(IconColor) ? $"color:{IconColor}" : null)">@((MarkupString)Icon)</i><span>@Text</span>
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -153,6 +153,11 @@ namespace Radzen.Blazor
|
||||
[JSInvokable("RadzenUpload.OnChange")]
|
||||
public async System.Threading.Tasks.Task OnChange(IEnumerable<PreviewFileInfo> files)
|
||||
{
|
||||
if(files == null || !files.Any())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var file = files.FirstOrDefault();
|
||||
|
||||
FileSize = file.Size;
|
||||
|
||||
@@ -130,7 +130,7 @@ namespace Radzen.Blazor
|
||||
{
|
||||
if (!firstRender)
|
||||
{
|
||||
await JSRuntime.InvokeVoidAsync("Radzen.updateMap", UniqueID, Zoom, Center);
|
||||
await JSRuntime.InvokeVoidAsync("Radzen.updateMap", UniqueID, ApiKey, Zoom, Center);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -207,12 +207,12 @@ namespace Radzen.Blazor
|
||||
if (firstRender)
|
||||
{
|
||||
await JSRuntime.InvokeVoidAsync("Radzen.createMap", Element, Reference, UniqueID, ApiKey, MapId, Zoom, Center,
|
||||
data.Select(m => new { Title = m.Title, Label = m.Label, Position = m.Position }), Options, FitBoundsToMarkersOnUpdate);
|
||||
data.Select(m => new { Title = m.Title, Label = m.Label, Position = m.Position }), Options, FitBoundsToMarkersOnUpdate, Culture.TwoLetterISOLanguageName);
|
||||
}
|
||||
else
|
||||
{
|
||||
await JSRuntime.InvokeVoidAsync("Radzen.updateMap", UniqueID, null, null,
|
||||
data.Select(m => new { Title = m.Title, Label = m.Label, Position = m.Position }), Options, FitBoundsToMarkersOnUpdate);
|
||||
await JSRuntime.InvokeVoidAsync("Radzen.updateMap", UniqueID, ApiKey, null, null,
|
||||
data.Select(m => new { Title = m.Title, Label = m.Label, Position = m.Position }), Options, FitBoundsToMarkersOnUpdate, Culture.TwoLetterISOLanguageName);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -28,6 +28,13 @@ namespace Radzen.Blazor
|
||||
[Parameter]
|
||||
public string AlternateText { get; set; } = "gravatar";
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the size. Defaulted to 36 (pixels).
|
||||
/// </summary>
|
||||
/// <value>The size of the image in pixels.</value>
|
||||
[Parameter]
|
||||
public int Size { get; set; } = 36;
|
||||
|
||||
/// <summary>
|
||||
/// Gets gravatar URL.
|
||||
/// </summary>
|
||||
@@ -38,9 +45,8 @@ namespace Radzen.Blazor
|
||||
var md5Email = MD5.Calculate(System.Text.Encoding.ASCII.GetBytes(Email != null ? Email : ""));
|
||||
|
||||
var style = "retro";
|
||||
var width = "36";
|
||||
|
||||
return $"https://secure.gravatar.com/avatar/{md5Email}?d={style}&s={width}";
|
||||
return $"https://secure.gravatar.com/avatar/{md5Email}?d={style}&s={Size}";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -405,7 +405,7 @@ namespace Radzen.Blazor
|
||||
/// <inheritdoc />
|
||||
protected override string GetComponentCssClass()
|
||||
{
|
||||
return "rz-html-editor";
|
||||
return GetClassList("rz-html-editor").ToString();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
@using Radzen.Blazor.Rendering
|
||||
@inherits RadzenHtmlEditorColorBase
|
||||
|
||||
<EditorColorPicker Title=@Title @bind-Value=@Value Icon="opacity" Change=@OnChange ShowHSV=@ShowHSV ShowRGBA=@ShowRGBA
|
||||
<EditorColorPicker Title=@Title @bind-Value=@value Icon="opacity" Change=@OnChange ShowHSV=@ShowHSV ShowRGBA=@ShowRGBA
|
||||
ShowColors=@ShowColors ShowButton=@ShowButton HexText=@HexText RedText=@RedText GreenText=@GreenText
|
||||
BlueText=@BlueText AlphaText=@AlphaText ButtonText=@ButtonText>
|
||||
@ChildContent
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Components;
|
||||
|
||||
namespace Radzen.Blazor
|
||||
@@ -24,7 +25,7 @@ namespace Radzen.Blazor
|
||||
/// Specifies the default background color. Set to <c>"rgb(0, 0, 255)"</c> by default;
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
public string Value { get; set; } = "rgb(0, 0, 255)";
|
||||
public override string Value { get; set; } = "rgb(0, 0, 255)";
|
||||
/// <summary>
|
||||
/// Specifies the title (tooltip) displayed when the user hovers the tool. Set to <c>"Background color"</c> by default.
|
||||
/// </summary>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
@using Radzen.Blazor.Rendering
|
||||
@inherits RadzenHtmlEditorColorBase
|
||||
|
||||
<EditorColorPicker Title=@Title @bind-Value=@Value Icon="title" Change=@OnChange ShowHSV=@ShowHSV ShowRGBA=@ShowRGBA
|
||||
<EditorColorPicker Title=@Title @bind-Value=@value Icon="title" Change=@OnChange ShowHSV=@ShowHSV ShowRGBA=@ShowRGBA
|
||||
ShowColors=@ShowColors ShowButton=@ShowButton HexText=@HexText RedText=@RedText GreenText=@GreenText
|
||||
BlueText=@BlueText AlphaText=@AlphaText ButtonText=@ButtonText>
|
||||
@ChildContent
|
||||
|
||||
@@ -24,7 +24,7 @@ namespace Radzen.Blazor
|
||||
/// Specifies the default text color. Set to <c>"rgb(255, 0, 0)"</c> by default;
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
public string Value { get; set; } = "rgb(255, 0, 0)";
|
||||
public override string Value { get; set; } = "rgb(255, 0, 0)";
|
||||
/// <summary>
|
||||
/// Specifies the title (tooltip) displayed when the user hovers the tool. Set to <c>"Text color"</c> by default.
|
||||
/// </summary>
|
||||
|
||||
@@ -84,5 +84,36 @@ namespace Radzen.Blazor
|
||||
{
|
||||
await Editor.ExecuteCommandAsync(CommandName, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The default value of the color picker.
|
||||
/// </summary>
|
||||
public abstract string Value { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The internal state of the component.
|
||||
/// </summary>
|
||||
protected string value;
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void OnInitialized()
|
||||
{
|
||||
value = Value;
|
||||
|
||||
base.OnInitialized();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override async Task SetParametersAsync(ParameterView parameters)
|
||||
{
|
||||
var valueChanged = parameters.DidParameterChange(nameof(Value), Value);
|
||||
|
||||
await base.SetParametersAsync(parameters);
|
||||
|
||||
if (valueChanged)
|
||||
{
|
||||
value = Value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,7 +35,7 @@ namespace Radzen.Blazor
|
||||
/// <inheritdoc />
|
||||
protected override string GetComponentCssClass()
|
||||
{
|
||||
return $"rzi{(IconStyle.HasValue ? $" rzi-{IconStyle.Value.ToString().ToLowerInvariant()}" : "")}";
|
||||
return $"notranslate rzi{(IconStyle.HasValue ? $" rzi-{IconStyle.Value.ToString().ToLowerInvariant()}" : "")}";
|
||||
}
|
||||
|
||||
string getStyle()
|
||||
|
||||
@@ -2,14 +2,14 @@
|
||||
@inherits RadzenComponent
|
||||
@if (Visible)
|
||||
{
|
||||
<NavLink style="@Style" href="@Path" @attributes="Attributes" class="@GetCssClass()" target="@Target" id="@GetId()" Match="@Match">
|
||||
<NavLink style="@Style" href="@GetPath()" @attributes="Attributes" class="@GetCssClass()" target="@GetTarget()" id="@GetId()" Match="@Match" >
|
||||
@if (!string.IsNullOrEmpty(Icon))
|
||||
{
|
||||
<i class="rzi" style="@(!string.IsNullOrEmpty(IconColor) ? $"color:{IconColor}" : null)">@((MarkupString)Icon)</i>
|
||||
<i class="notranslate rzi" style="@(!string.IsNullOrEmpty(IconColor) ? $"color:{IconColor}" : null)">@((MarkupString)Icon)</i>
|
||||
}
|
||||
@if (!string.IsNullOrEmpty(Image))
|
||||
{
|
||||
<img class="rzi" src="@Image" alt="@ImageAlternateText" />
|
||||
<img class="notranslate rzi" src="@Image" alt="@ImageAlternateText" />
|
||||
}
|
||||
<span @ref="@Element" class="rz-link-text">@if (ChildContent != null) {@ChildContent} else {@Text}</span>
|
||||
</NavLink>
|
||||
|
||||
@@ -13,12 +13,6 @@ namespace Radzen.Blazor
|
||||
/// </example>
|
||||
public partial class RadzenLink : RadzenComponent
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override string GetComponentCssClass()
|
||||
{
|
||||
return "rz-link";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the text.
|
||||
/// </summary>
|
||||
@@ -81,5 +75,35 @@ namespace Radzen.Blazor
|
||||
/// <value>The navigation link match.</value>
|
||||
[Parameter]
|
||||
public NavLinkMatch Match { get; set; } = NavLinkMatch.Prefix;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets whether the link is disabled.
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
public bool Disabled { get; set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override string GetComponentCssClass()
|
||||
{
|
||||
return Disabled ? "rz-link rz-link-disabled" : "rz-link";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the path.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
protected string GetPath()
|
||||
{
|
||||
return !Disabled ? Path : null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the target.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
protected string GetTarget()
|
||||
{
|
||||
return !Disabled ? Target : null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,8 +27,8 @@
|
||||
<div class="rz-helper-hidden-accessible">
|
||||
<input id="@($"{UniqueID}sa")" readonly="readonly" type="checkbox" aria-label="@SelectAllText" aria-checked="@(IsAllSelected().ToString().ToLowerInvariant())">
|
||||
</div>
|
||||
<div class="@(IsAllSelected() ? "rz-chkbox-box rz-state-active" : "rz-chkbox-box")">
|
||||
<span class="@(IsAllSelected() ? "rz-chkbox-icon rzi rzi-check" : "rz-chkbox-icon")"></span>
|
||||
<div class="@(IsAllSelected() ? "notranslate rz-chkbox-box rz-state-active" : "notranslate rz-chkbox-box")">
|
||||
<span class="@(IsAllSelected() ? "notranslate rz-chkbox-icon rzi rzi-check" : "notranslate rz-chkbox-icon")"></span>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
@@ -41,7 +41,7 @@
|
||||
{
|
||||
<div class="rz-listbox-filter-container">
|
||||
@RenderFilter()
|
||||
<span class="rz-listbox-filter-icon rzi rzi-search"></span>
|
||||
<span class="notranslate rz-listbox-filter-icon rzi rzi-search"></span>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user