mirror of
https://github.com/radzenhq/radzen-blazor.git
synced 2026-02-04 05:35:44 +00:00
Compare commits
1810 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
045ac03837 | ||
|
|
6439845d32 | ||
|
|
0b0721b9d3 | ||
|
|
f1ba65affa | ||
|
|
e60bdbf80c | ||
|
|
2269b500f3 | ||
|
|
089f2e964c | ||
|
|
1e477f71ef | ||
|
|
430e8efd42 | ||
|
|
bddd7e5417 | ||
|
|
10deb4c51a | ||
|
|
530c3a5576 | ||
|
|
4e5cb34051 | ||
|
|
e7c5eb6bee | ||
|
|
f2cb6ed1a6 | ||
|
|
ce745204f7 | ||
|
|
8b3c9f2f72 | ||
|
|
2aa1c85972 | ||
|
|
766e5db363 | ||
|
|
c1504e104d | ||
|
|
3705b740c9 | ||
|
|
85889ee338 | ||
|
|
32254fbed8 | ||
|
|
62fbac2d19 | ||
|
|
6b02bb973f | ||
|
|
1ad15035de | ||
|
|
dd7a21010a | ||
|
|
f69ab641f7 | ||
|
|
27308b59ea | ||
|
|
f1aa9fe906 | ||
|
|
112b28342a | ||
|
|
2f9fe92b6c | ||
|
|
4a45c78512 | ||
|
|
0c78f66c21 | ||
|
|
be6f934e7b | ||
|
|
79fa11f2c9 | ||
|
|
349966a7c3 | ||
|
|
4867825367 | ||
|
|
36686afe04 | ||
|
|
9547896074 | ||
|
|
4ecb737ea7 | ||
|
|
0147f398ec | ||
|
|
3fd0420b52 | ||
|
|
decba39373 | ||
|
|
15972a9203 | ||
|
|
94c0a52824 | ||
|
|
d583f52d7e | ||
|
|
9b243f90ee | ||
|
|
18168e4577 | ||
|
|
a18e5454ce | ||
|
|
7bf16f2891 | ||
|
|
8491387a15 | ||
|
|
123ae18a64 | ||
|
|
f3a19597fc | ||
|
|
6c6ccbf07c | ||
|
|
09af9a2576 | ||
|
|
cf813d7eb4 | ||
|
|
f0ca523dfb | ||
|
|
6a08443853 | ||
|
|
030b9b0c82 | ||
|
|
8a0b511649 | ||
|
|
7853b830ae | ||
|
|
77eb7f7821 | ||
|
|
65e71ac56f | ||
|
|
a2a1bcb77b | ||
|
|
e8fadc638c | ||
|
|
507a8330b7 | ||
|
|
1dc1c99c33 | ||
|
|
0cd89585e2 | ||
|
|
c54148c291 | ||
|
|
f7d7fa5031 | ||
|
|
d959bd6c34 | ||
|
|
92240d3e8b | ||
|
|
0c634a4fa6 | ||
|
|
c8e2414a70 | ||
|
|
a6956b34db | ||
|
|
055c2ec202 | ||
|
|
1c0e03eadc | ||
|
|
f8c44cf2d3 | ||
|
|
d99eeb1e1e | ||
|
|
c42a4d9d1c | ||
|
|
2b8eb11bc3 | ||
|
|
f4f62c6edf | ||
|
|
142f75e662 | ||
|
|
1bc19921ff | ||
|
|
d901b795f7 | ||
|
|
de19e3abec | ||
|
|
ee1ab72d0a | ||
|
|
c699dd71af | ||
|
|
3452bafd4b | ||
|
|
0aabac338d | ||
|
|
a9a25a9197 | ||
|
|
aa295e9688 | ||
|
|
9cf21b1192 | ||
|
|
7efb6fc125 | ||
|
|
a050af7985 | ||
|
|
25e3fd90c5 | ||
|
|
e79384a3c4 | ||
|
|
c784af67da | ||
|
|
74d4681f33 | ||
|
|
eaa939eda3 | ||
|
|
a3b21debb0 | ||
|
|
db9168e179 | ||
|
|
d68a5106a5 | ||
|
|
5244d7af1e | ||
|
|
0ee095617e | ||
|
|
8d7d022576 | ||
|
|
098cf78753 | ||
|
|
4131811e32 | ||
|
|
260cd62329 | ||
|
|
b6b8ce55c6 | ||
|
|
1d3e5a60e2 | ||
|
|
b2397cfd54 | ||
|
|
15ef3bdadb | ||
|
|
c353e713cc | ||
|
|
1eaaad320f | ||
|
|
e0c0071d8b | ||
|
|
0a7c274f33 | ||
|
|
d4621f8b8a | ||
|
|
5b0c1fd16e | ||
|
|
6b5847f149 | ||
|
|
b227d89a01 | ||
|
|
a4191556ea | ||
|
|
a7d90c0b39 | ||
|
|
6edef4ec97 | ||
|
|
17f7ae7daa | ||
|
|
03d33f2074 | ||
|
|
8787d8ad43 | ||
|
|
69f98aa756 | ||
|
|
9620faafe1 | ||
|
|
2ba0b164fc | ||
|
|
77b9b2e8ce | ||
|
|
58be436aaa | ||
|
|
5995eb8b8e | ||
|
|
0e4f942b15 | ||
|
|
c14f773ed4 | ||
|
|
3ef08a53d1 | ||
|
|
67d32c5a96 | ||
|
|
e351793043 | ||
|
|
f0a987e7a2 | ||
|
|
c0354961f7 | ||
|
|
4c8c8dcdab | ||
|
|
cae80096e1 | ||
|
|
45d4fcc0bf | ||
|
|
da5380a472 | ||
|
|
b27544663e | ||
|
|
75c35aa9e5 | ||
|
|
ad0fd8d5c8 | ||
|
|
c60cd1fabb | ||
|
|
7cfb6258d5 | ||
|
|
ff1bc2577f | ||
|
|
07ab3621b3 | ||
|
|
0af3f3fcce | ||
|
|
cb8a70744d | ||
|
|
c6a8d3e251 | ||
|
|
d871292d39 | ||
|
|
255febcd70 | ||
|
|
c7d8f77fb4 | ||
|
|
248de4ef0f | ||
|
|
56ae5d2c33 | ||
|
|
2cc575d74b | ||
|
|
b0b68d16a4 | ||
|
|
45fd510e15 | ||
|
|
0376a58374 | ||
|
|
b1d1d2c7f8 | ||
|
|
6de14c91e4 | ||
|
|
a04cbeba78 | ||
|
|
82610e281d | ||
|
|
e9b3213d8b | ||
|
|
313ee50bf2 | ||
|
|
fca72e3fad | ||
|
|
97657da95d | ||
|
|
f32240ba65 | ||
|
|
1d8d20a7d7 | ||
|
|
5fba2685b1 | ||
|
|
2c39551560 | ||
|
|
265ca8b433 | ||
|
|
8c4b33ec17 | ||
|
|
937bf6f57a | ||
|
|
e2f142ed28 | ||
|
|
9a835690aa | ||
|
|
5f4ec1c446 | ||
|
|
7b11516520 | ||
|
|
4a6543b0c6 | ||
|
|
fa197c1b7f | ||
|
|
ab4ab7e63b | ||
|
|
b88a8e605a | ||
|
|
519d8fc64a | ||
|
|
8032fde262 | ||
|
|
02b4b0b9b6 | ||
|
|
933c820f20 | ||
|
|
8476fdb77f | ||
|
|
ae1f280062 | ||
|
|
d58dd28051 | ||
|
|
a212382da6 | ||
|
|
b1819ff755 | ||
|
|
2317305f0e | ||
|
|
da5f7e27c4 | ||
|
|
4c4dd71195 | ||
|
|
61c3d3c34a | ||
|
|
59d4e30469 | ||
|
|
e0dd34df2b | ||
|
|
41366d9376 | ||
|
|
1779b8d67e | ||
|
|
b673cbe411 | ||
|
|
1a595c5043 | ||
|
|
bce5ae88ee | ||
|
|
b81d15cdef | ||
|
|
ec6747ac09 | ||
|
|
5cd35bbfb5 | ||
|
|
1b07509e18 | ||
|
|
35211b94db | ||
|
|
0e9338a0e4 | ||
|
|
95b099d62c | ||
|
|
b295963d8d | ||
|
|
884ca797d8 | ||
|
|
3664b4acec | ||
|
|
95f33310bf | ||
|
|
a1500051b9 | ||
|
|
be1a6cc985 | ||
|
|
32525a0204 | ||
|
|
8b64c8afd3 | ||
|
|
2795413fc1 | ||
|
|
8db9fc3f17 | ||
|
|
d7c2fb8a02 | ||
|
|
6c9d09f6c3 | ||
|
|
1482fe3e1b | ||
|
|
c2f0422a68 | ||
|
|
4b3a7af308 | ||
|
|
7b2cd6e4b0 | ||
|
|
60dbe28dca | ||
|
|
3dde8c5905 | ||
|
|
9207ef357f | ||
|
|
ce7ea27255 | ||
|
|
c3eb701c56 | ||
|
|
180c1fe185 | ||
|
|
9b3138102d | ||
|
|
e43412c02f | ||
|
|
a223fad28c | ||
|
|
9ade31a813 | ||
|
|
fd91024b8d | ||
|
|
0d9526ed72 | ||
|
|
d4e51a1b51 | ||
|
|
ded26df5d0 | ||
|
|
a3ba44771f | ||
|
|
83f4ac980e | ||
|
|
5da102c058 | ||
|
|
27608327af | ||
|
|
fcbbd53dd8 | ||
|
|
76aaab319c | ||
|
|
6ea6a46c15 | ||
|
|
c0f3e62a10 | ||
|
|
5f71660c7a | ||
|
|
e6b15de5a4 | ||
|
|
bf74569906 | ||
|
|
b70f1f84be | ||
|
|
a2209e73fc | ||
|
|
f77ebe3af7 | ||
|
|
8c4370780d | ||
|
|
e4b352f1ce | ||
|
|
a679e33d54 | ||
|
|
e477ce3d9a | ||
|
|
f15d7ac445 | ||
|
|
d36af364bf | ||
|
|
b0ebcf86e6 | ||
|
|
247ec75c9e | ||
|
|
3b43bf3579 | ||
|
|
2be6d5cdef | ||
|
|
fef7526af4 | ||
|
|
88ee26ecf8 | ||
|
|
947c602cb0 | ||
|
|
fd0cf4e4e3 | ||
|
|
0d11bffa82 | ||
|
|
c9a9c48de3 | ||
|
|
fbbcb58e3f | ||
|
|
ed9dbea34a | ||
|
|
9ccca42011 | ||
|
|
d7bc92e465 | ||
|
|
5d29ebfde2 | ||
|
|
efa14f2dcd | ||
|
|
2e07802a05 | ||
|
|
34a83a46d9 | ||
|
|
9db5c68a64 | ||
|
|
5dac84c511 | ||
|
|
ce834c9b18 | ||
|
|
0af5f626bc | ||
|
|
0d68186dfe | ||
|
|
65e226d02d | ||
|
|
15d0654cd7 | ||
|
|
f7c36efab8 | ||
|
|
09e372f37b | ||
|
|
a020e06c3d | ||
|
|
650f2caf42 | ||
|
|
bfaa5a9878 | ||
|
|
7d22fc727b | ||
|
|
e78db0d549 | ||
|
|
4a610d9868 | ||
|
|
2c08ab1e52 | ||
|
|
70c26493c4 | ||
|
|
e5f45550d4 | ||
|
|
80c196d863 | ||
|
|
516ee4b762 | ||
|
|
7371e15ebb | ||
|
|
b6f6f79c00 | ||
|
|
d8dd38dcdd | ||
|
|
1384c2b477 | ||
|
|
2006a44fdd | ||
|
|
f7c04c9f7e | ||
|
|
1dbb36bd77 | ||
|
|
54cabebbfa | ||
|
|
f31c2296dd | ||
|
|
6f66fd9597 | ||
|
|
8c33bd828a | ||
|
|
068352de91 | ||
|
|
f5c166906b | ||
|
|
514772f5c2 | ||
|
|
2e0c2aa8bc | ||
|
|
bfd641f1b1 | ||
|
|
1c45af855d | ||
|
|
5d7cf75bed | ||
|
|
04ee23b7b5 | ||
|
|
99c3c71be8 | ||
|
|
0c2fb54d14 | ||
|
|
eaf875dfd5 | ||
|
|
29e61087ac | ||
|
|
ef989e7909 | ||
|
|
ab1fd464cf | ||
|
|
4a042b73b8 | ||
|
|
b416a7de09 | ||
|
|
ebec631cde | ||
|
|
cd6a751a68 | ||
|
|
f90692b526 | ||
|
|
b4ff72d424 | ||
|
|
61de002e0e | ||
|
|
6c063c856c | ||
|
|
a075a0b29b | ||
|
|
0e85e70470 | ||
|
|
0e84d1dad1 | ||
|
|
092b3bf9c2 | ||
|
|
87cf688e27 | ||
|
|
892cab3adf | ||
|
|
c547f50dc8 | ||
|
|
952bcecb12 | ||
|
|
1da97c3cd6 | ||
|
|
b9abc13364 | ||
|
|
fcd2ffa630 | ||
|
|
1f769bc7b5 | ||
|
|
e84a5ad62a | ||
|
|
5a481aeb5e | ||
|
|
24cea1d8d2 | ||
|
|
134f368953 | ||
|
|
8a6749e38b | ||
|
|
0722639001 | ||
|
|
e372dd8ddf | ||
|
|
c66022eaa8 | ||
|
|
3b873fc06c | ||
|
|
f2ac7cca28 | ||
|
|
d21d909de6 | ||
|
|
7c476ec104 | ||
|
|
3716772a06 | ||
|
|
c1100a5c62 | ||
|
|
0ae1332480 | ||
|
|
222debc335 | ||
|
|
7702ac5475 | ||
|
|
b4f4b10332 | ||
|
|
fb795a22c8 | ||
|
|
e5a4af88cc | ||
|
|
f68508a9ef | ||
|
|
1e4adf115c | ||
|
|
dbc8a2b7b2 | ||
|
|
f339bfe45d | ||
|
|
a78b88c2a4 | ||
|
|
4a338ad94e | ||
|
|
03d0e38f15 | ||
|
|
7da16b469c | ||
|
|
c80fcc5494 | ||
|
|
0286396175 | ||
|
|
edf381c914 | ||
|
|
58d85518f0 | ||
|
|
32e8ebf4f8 | ||
|
|
c8cba6ba91 | ||
|
|
fba5487231 | ||
|
|
9d81fbcbcb | ||
|
|
40c55b3515 | ||
|
|
e5aaaff32e | ||
|
|
6071b138f0 | ||
|
|
71174f5d40 | ||
|
|
bb4ca4ff9e | ||
|
|
93f42e9a67 | ||
|
|
2b6c1ec771 | ||
|
|
958546fd0c | ||
|
|
d263494229 | ||
|
|
12d51318a8 | ||
|
|
aa8861643f | ||
|
|
0f0e4e35ce | ||
|
|
79f63a794d | ||
|
|
47e01dadb7 | ||
|
|
3bfa2bd9e4 | ||
|
|
b1aac49824 | ||
|
|
16fdfa3cb1 | ||
|
|
9c43badbfc | ||
|
|
96689b8e67 | ||
|
|
95b2a56f80 | ||
|
|
6c33f6ff08 | ||
|
|
ab515920de | ||
|
|
46fd65f98a | ||
|
|
e9986c9667 | ||
|
|
fec40dd91c | ||
|
|
e8bffd8dc6 | ||
|
|
59e6271373 | ||
|
|
0dbb0b6e12 | ||
|
|
5d1c166606 | ||
|
|
366463ac4e | ||
|
|
ed5d4f5fcd | ||
|
|
787bc2243f | ||
|
|
8b5fccdd0d | ||
|
|
fa79467c19 | ||
|
|
5a4577b7ec | ||
|
|
0c82c60c03 | ||
|
|
84e33ec18a | ||
|
|
779be53910 | ||
|
|
cda6e3c204 | ||
|
|
c73aee1633 | ||
|
|
d486b8b4cf | ||
|
|
31909ba17b | ||
|
|
27dc30ca57 | ||
|
|
f5b7ddcf0e | ||
|
|
f1aac3e9e2 | ||
|
|
0f626dada2 | ||
|
|
74f4c74f47 | ||
|
|
3e93ab0fac | ||
|
|
4ac4ec58a8 | ||
|
|
af552414ac | ||
|
|
728d7c5d24 | ||
|
|
ee17b54872 | ||
|
|
373a557ad2 | ||
|
|
062eeb8ac0 | ||
|
|
473a7fc647 | ||
|
|
4ddd9dd874 | ||
|
|
05dd048410 | ||
|
|
c2c4afa094 | ||
|
|
be2567f478 | ||
|
|
e9e9c9f702 | ||
|
|
1e3d653d1c | ||
|
|
63f3f3899e | ||
|
|
08362d1bb6 | ||
|
|
f1d3d78f89 | ||
|
|
5f084b9d7c | ||
|
|
224d694ffa | ||
|
|
1be4b06d33 | ||
|
|
155c3a4b50 | ||
|
|
371f912c1d | ||
|
|
41c47fbc58 | ||
|
|
167030c15c | ||
|
|
7403a07614 | ||
|
|
fd0bad9a91 | ||
|
|
c2381ac3f5 | ||
|
|
ee18fbac19 | ||
|
|
b83ec99e4f | ||
|
|
72bd03d368 | ||
|
|
a6ee68efe8 | ||
|
|
795ca64ac0 | ||
|
|
ee26df3b68 | ||
|
|
bc0cf84297 | ||
|
|
049f846980 | ||
|
|
67308b8e3a | ||
|
|
8c9cdb28d0 | ||
|
|
dd30b30b34 | ||
|
|
6446097840 | ||
|
|
589cf2afd8 | ||
|
|
fb1928d5ec | ||
|
|
552b41f855 | ||
|
|
e2a036192a | ||
|
|
b6c5f670b3 | ||
|
|
ecac1c5b78 | ||
|
|
1d3f124845 | ||
|
|
d0b39df3e2 | ||
|
|
beb52670fa | ||
|
|
c924407569 | ||
|
|
bb72002452 | ||
|
|
78f045ddf2 | ||
|
|
ba49220e43 | ||
|
|
857bceba76 | ||
|
|
859280c2d7 | ||
|
|
e8ac5dbe8d | ||
|
|
86ec75b05e | ||
|
|
6b00fdb19e | ||
|
|
b9707ea486 | ||
|
|
f9dd71c05a | ||
|
|
0720a9b8f0 | ||
|
|
0289733f7f | ||
|
|
50ed8ad1e5 | ||
|
|
a10fabd927 | ||
|
|
0dd9fdf7e6 | ||
|
|
ade5f386b6 | ||
|
|
315b135a3b | ||
|
|
bc3d1daf11 | ||
|
|
50d738c7b6 | ||
|
|
0a23ac1401 | ||
|
|
9cbfb4ccbe | ||
|
|
7c1a76d38e | ||
|
|
b501b86656 | ||
|
|
f118cff5c0 | ||
|
|
66d7a9e520 | ||
|
|
a3424ce020 | ||
|
|
7cb72b25be | ||
|
|
f3584b02ac | ||
|
|
f2aaf9cc26 | ||
|
|
ea0bab5bd6 | ||
|
|
78be6f9839 | ||
|
|
a7df5c7fac | ||
|
|
516a6be98e | ||
|
|
7077e30d94 | ||
|
|
21b4053b8b | ||
|
|
85c634480d | ||
|
|
54eefe2295 | ||
|
|
b32dbc3ac5 | ||
|
|
4a5d089e5d | ||
|
|
22cad5a2ab | ||
|
|
acbebd7102 | ||
|
|
301ae12169 | ||
|
|
f04bdcee69 | ||
|
|
d4b78fbf87 | ||
|
|
500fbc9190 | ||
|
|
420f7e9b4e | ||
|
|
b273c6083f | ||
|
|
8877c705c5 | ||
|
|
1e30f794fe | ||
|
|
29ad82db7c | ||
|
|
a9046be00c | ||
|
|
a70efc95c6 | ||
|
|
b4b8774110 | ||
|
|
d87e03b0cf | ||
|
|
af07ccb87e | ||
|
|
dc43918a77 | ||
|
|
a04b131394 | ||
|
|
874f18fa6a | ||
|
|
fdc93e5130 | ||
|
|
6109e18fe6 | ||
|
|
27aca28523 | ||
|
|
2ac4aacee5 | ||
|
|
824a741634 | ||
|
|
819722e7da | ||
|
|
959d442690 | ||
|
|
b20868328f | ||
|
|
679c729985 | ||
|
|
bc2ca273a5 | ||
|
|
8a2612878d | ||
|
|
dd76d149ee | ||
|
|
2770d0fbec | ||
|
|
55b2c1e186 | ||
|
|
c4c291056b | ||
|
|
b80b81ada6 | ||
|
|
a0f3d44832 | ||
|
|
d9e4c00ccf | ||
|
|
c34a186eaf | ||
|
|
be27c930d3 | ||
|
|
66818872c2 | ||
|
|
cc1ac368b3 | ||
|
|
03e22098ca | ||
|
|
724b5eb1e0 | ||
|
|
45a1ce4b55 | ||
|
|
3e5cb2e30b | ||
|
|
d0a4c6aaf1 | ||
|
|
be4bcb7390 | ||
|
|
a63c3aa4c2 | ||
|
|
e8e43d97f2 | ||
|
|
9939ff4452 | ||
|
|
b69bbc899e | ||
|
|
f0cba24cc7 | ||
|
|
fd5fa0e798 | ||
|
|
1ba1d53884 | ||
|
|
00a118b901 | ||
|
|
ba2ea55884 | ||
|
|
70b4c3dd0f | ||
|
|
412e19252c | ||
|
|
73e1974583 | ||
|
|
25c57d645b | ||
|
|
a6c6021923 | ||
|
|
2886ac9d7c | ||
|
|
c121414767 | ||
|
|
35f02ef7a9 | ||
|
|
ffeb972a82 | ||
|
|
f20a74674f | ||
|
|
03396fbbe2 | ||
|
|
54a5c0805e | ||
|
|
486cb66b6c | ||
|
|
e5d7a344c7 | ||
|
|
60fe0ed25f | ||
|
|
04741c702a | ||
|
|
6e190fe903 | ||
|
|
5bb3e65eb9 | ||
|
|
c3b29ffcd1 | ||
|
|
a889c3e97b | ||
|
|
bd578ca7cd | ||
|
|
2a9a115c31 | ||
|
|
4d1848a5e1 | ||
|
|
4bd8f777e0 | ||
|
|
4654a9011b | ||
|
|
22a5dc148a | ||
|
|
88dc4c0607 | ||
|
|
0a7c47fa70 | ||
|
|
e6f311ebba | ||
|
|
88d09f0fef | ||
|
|
7467d87e36 | ||
|
|
b50e793a9c | ||
|
|
1147390576 | ||
|
|
539785f079 | ||
|
|
b99b516346 | ||
|
|
c0dc4f4236 | ||
|
|
5b8f664530 | ||
|
|
cc490692ad | ||
|
|
5ef415c87d | ||
|
|
ff3c67409d | ||
|
|
582a9bae31 | ||
|
|
95f51ed935 | ||
|
|
0dca22c219 | ||
|
|
eaf67e197b | ||
|
|
b8db918348 | ||
|
|
c865073605 | ||
|
|
192ccbec25 | ||
|
|
b8b3b29d01 | ||
|
|
00ea9a4393 | ||
|
|
267392d0b7 | ||
|
|
e5f041208f | ||
|
|
82010353c6 | ||
|
|
7daf4d1f58 | ||
|
|
ebb940ee0e | ||
|
|
1ce8c98837 | ||
|
|
257948cbe1 | ||
|
|
8971e0aa1a | ||
|
|
2209b050b0 | ||
|
|
b5a876a93e | ||
|
|
4c64ee24d5 | ||
|
|
1a3376374f | ||
|
|
ee88560090 | ||
|
|
aae7eba068 | ||
|
|
6715bc34d8 | ||
|
|
55d0ea5e22 | ||
|
|
11c692b146 | ||
|
|
ab47bd2e7b | ||
|
|
6dd9933d55 | ||
|
|
d08d398b47 | ||
|
|
aa3903d8f0 | ||
|
|
26f9030cef | ||
|
|
0500a10671 | ||
|
|
c3ae2d3eda | ||
|
|
e502c51886 | ||
|
|
063c1aa6c0 | ||
|
|
5e5db9193e | ||
|
|
26a38fc56c | ||
|
|
aad0558a9c | ||
|
|
a911f975da | ||
|
|
a99c8fbc88 | ||
|
|
79525227a9 | ||
|
|
66b8eb72bf | ||
|
|
1eff269b80 | ||
|
|
2dc01b528c | ||
|
|
30e200896d | ||
|
|
7d2e827e6f | ||
|
|
94e6b3086b | ||
|
|
0849e90574 | ||
|
|
d3eef33371 | ||
|
|
1cee0d10e5 | ||
|
|
3f044b407a | ||
|
|
b25ce3760b | ||
|
|
6e810761f8 | ||
|
|
6dea80e13e | ||
|
|
a715616a6a | ||
|
|
e87db432d5 | ||
|
|
0b4b89dcbd | ||
|
|
0e980051e3 | ||
|
|
4bd489a530 | ||
|
|
ed02c0dbc1 | ||
|
|
81e2432426 | ||
|
|
3a14099831 | ||
|
|
84712967b0 | ||
|
|
1fc70b7591 | ||
|
|
b9f8345964 | ||
|
|
fcd9e674d5 | ||
|
|
2cf2dfaea5 | ||
|
|
797be4e57c | ||
|
|
2478f1478f | ||
|
|
58cd508be4 | ||
|
|
9ca094f4f8 | ||
|
|
9ed9878193 | ||
|
|
c878a47f92 | ||
|
|
42d7a8860a | ||
|
|
718824f359 | ||
|
|
3b5b649530 | ||
|
|
8702af0c42 | ||
|
|
b038157f2f | ||
|
|
0033bdd570 | ||
|
|
99b40cac43 | ||
|
|
7fa91f98c6 | ||
|
|
a6e3f48044 | ||
|
|
d25921f6c8 | ||
|
|
e1986dc8eb | ||
|
|
ebba5b860f | ||
|
|
4beff8932e | ||
|
|
e26bd9adfb | ||
|
|
2eadc7b5ea | ||
|
|
a15aeade6a | ||
|
|
1990b7fad5 | ||
|
|
d81d5a37f8 | ||
|
|
1c1da0b080 | ||
|
|
4063bce178 | ||
|
|
b4d33c6472 | ||
|
|
44005c607d | ||
|
|
c17852a583 | ||
|
|
f94b22666b | ||
|
|
3c8c690a79 | ||
|
|
6f416ffe79 | ||
|
|
e4f8fe9ea2 | ||
|
|
003738149e | ||
|
|
6f39223787 | ||
|
|
06649c2207 | ||
|
|
18f51becd8 | ||
|
|
916792abea | ||
|
|
c8f8e019f6 | ||
|
|
7b6c6bb930 | ||
|
|
b826993a0d | ||
|
|
00385c8e15 | ||
|
|
5b982766fb | ||
|
|
be27dfd918 | ||
|
|
a82089aff3 | ||
|
|
215ba8bfbf | ||
|
|
7b1e9185f7 | ||
|
|
8c756e99c1 | ||
|
|
d2384e74cd | ||
|
|
b2ff2852bd | ||
|
|
3b4505af27 | ||
|
|
87eee126e5 | ||
|
|
6234f04457 | ||
|
|
c8e808082f | ||
|
|
b2f2642c82 | ||
|
|
0f77730011 | ||
|
|
b062d56928 | ||
|
|
a3f8552b80 | ||
|
|
8faf5a81ca | ||
|
|
7d7c0ae320 | ||
|
|
2bd8b71927 | ||
|
|
19a323ec77 | ||
|
|
29ee95165e | ||
|
|
c618a31e44 | ||
|
|
f972de507f | ||
|
|
51a0be31d5 | ||
|
|
d986c12564 | ||
|
|
1ae17b121e | ||
|
|
afb294f170 | ||
|
|
2b63fa343a | ||
|
|
35121f1141 | ||
|
|
9d0f26fede | ||
|
|
f0289b73b8 | ||
|
|
1009619ecd | ||
|
|
f30b1b1e08 | ||
|
|
d151f39a22 | ||
|
|
be6d4accff | ||
|
|
69e71202ee | ||
|
|
fece284aee | ||
|
|
4bcb44bcb2 | ||
|
|
0891dbf5a8 | ||
|
|
b5b5a86025 | ||
|
|
3fcbe831d7 | ||
|
|
d253151296 | ||
|
|
4e9beb86b0 | ||
|
|
7f85b49f3f | ||
|
|
1ea8c56631 | ||
|
|
5d76cbee26 | ||
|
|
682e4af619 | ||
|
|
c446476fbc | ||
|
|
e18a05001e | ||
|
|
0685f8b9c0 | ||
|
|
bdd1d4e8c1 | ||
|
|
bf6923f909 | ||
|
|
faa37c3322 | ||
|
|
1fe5b07f86 | ||
|
|
7a9ad3933b | ||
|
|
df2e447362 | ||
|
|
b2033f3dcd | ||
|
|
186bce852d | ||
|
|
e1494441b0 | ||
|
|
1b67c130c7 | ||
|
|
628b980655 | ||
|
|
0e04a17380 | ||
|
|
cee1a14ebd | ||
|
|
3862205053 | ||
|
|
9696f044a0 | ||
|
|
b61a0f2c94 | ||
|
|
afb2e3a8a2 | ||
|
|
65cc0a0ed5 | ||
|
|
dba6f2ec6a | ||
|
|
b39ea03ba6 | ||
|
|
528483b905 | ||
|
|
fb7434f1b4 | ||
|
|
a239e6405b | ||
|
|
d5c00b81d7 | ||
|
|
590f6c8c8b | ||
|
|
edf2495a9f | ||
|
|
ed0a034414 | ||
|
|
3e33e0d0e1 | ||
|
|
c9e1c2711e | ||
|
|
1f0420dc1f | ||
|
|
f0320c6ff9 | ||
|
|
904eb1364c | ||
|
|
e5ef184515 | ||
|
|
2a4111643c | ||
|
|
53ffe057b2 | ||
|
|
b2632e1727 | ||
|
|
84554d6dea | ||
|
|
6fd8f8380b | ||
|
|
5330929efd | ||
|
|
c67bc9938c | ||
|
|
f41f0e94be | ||
|
|
74b1c6f4ed | ||
|
|
54d7e20baa | ||
|
|
221d88c52c | ||
|
|
eb3c8050fe | ||
|
|
fdab854799 | ||
|
|
ba32761a0c | ||
|
|
6d002838a5 | ||
|
|
d8f53db387 | ||
|
|
f15db1637e | ||
|
|
5f98e2fdc5 | ||
|
|
603dc9f9c6 | ||
|
|
0692079384 | ||
|
|
e046cdce45 | ||
|
|
595419df77 | ||
|
|
1a641afaa8 | ||
|
|
29c73ae90f | ||
|
|
e055f99f63 | ||
|
|
888d4797d0 | ||
|
|
b95d63e974 | ||
|
|
195abb59ff | ||
|
|
306ceba474 | ||
|
|
2be1476130 | ||
|
|
ca80356c27 | ||
|
|
eed34d9b7d | ||
|
|
1144ab32b7 | ||
|
|
0061e609d4 | ||
|
|
680b64c98f | ||
|
|
325048efcb | ||
|
|
aedb293d50 | ||
|
|
6cdc1943fb | ||
|
|
9ff40875c2 | ||
|
|
3a851d59fe | ||
|
|
64de7abada | ||
|
|
6d9feebedd | ||
|
|
441658eb7a | ||
|
|
01a441a99c | ||
|
|
1d10141c1d | ||
|
|
952313acee | ||
|
|
d537b742dc | ||
|
|
f3b706bcc2 | ||
|
|
2a57af944f | ||
|
|
3f42b93300 | ||
|
|
59a58eb886 | ||
|
|
d91d5bcd9b | ||
|
|
c6a08c79e1 | ||
|
|
d550b65bc7 | ||
|
|
42418ef393 | ||
|
|
12f4156ae0 | ||
|
|
ff58873fcb | ||
|
|
925c72f6aa | ||
|
|
345d853e2d | ||
|
|
10b064dc40 | ||
|
|
75a7187a87 | ||
|
|
6182e00c31 | ||
|
|
e3ba93a6b8 | ||
|
|
109d8cacbc | ||
|
|
3bcc18f035 | ||
|
|
92baa1affb | ||
|
|
32a9457de3 | ||
|
|
32c147fa16 | ||
|
|
d61d75f8bb | ||
|
|
eae6cd5396 | ||
|
|
6f16f230d1 | ||
|
|
f458a057e8 | ||
|
|
d013300fa3 | ||
|
|
d6b8394044 | ||
|
|
c1fa630602 | ||
|
|
28a03dadaf | ||
|
|
29cfc2ea6b | ||
|
|
f4c776f10e | ||
|
|
04be6bc38b | ||
|
|
4f0bbeeab0 | ||
|
|
5a356a8d75 | ||
|
|
7f35f46eaa | ||
|
|
ea7be67d83 | ||
|
|
8f0d65766d | ||
|
|
a140f318a2 | ||
|
|
d0a2d1644f | ||
|
|
e69b153e1c | ||
|
|
d19d383738 | ||
|
|
253f288323 | ||
|
|
d6ce0536ca | ||
|
|
0168c01915 | ||
|
|
7329fec67a | ||
|
|
5fea22294e | ||
|
|
669124a6b3 | ||
|
|
c44d141c07 | ||
|
|
0b30e00b8c | ||
|
|
1e7bd1bf48 | ||
|
|
c2c4d6aa02 | ||
|
|
7e0c64191c | ||
|
|
323e4e971a | ||
|
|
99b4f8f8fc | ||
|
|
7c1cf76c5c | ||
|
|
305e1b7af6 | ||
|
|
6880a70227 | ||
|
|
0482969755 | ||
|
|
4c9b429dae | ||
|
|
60b8400e29 | ||
|
|
7260be98d6 | ||
|
|
be94094de7 | ||
|
|
645077f39b | ||
|
|
b42940441d | ||
|
|
fc7071c04e | ||
|
|
de887a4e3f | ||
|
|
7f629309c7 | ||
|
|
fa45e209d5 | ||
|
|
40aec6cd0d | ||
|
|
969ae7aeca | ||
|
|
a64bbd34f3 | ||
|
|
79acf83d6f | ||
|
|
786e8d0be1 | ||
|
|
2757850f28 | ||
|
|
7c6f39f3b5 | ||
|
|
70723d0437 | ||
|
|
bd9b0f798b | ||
|
|
0c406b2ad8 | ||
|
|
822891541c | ||
|
|
bf064fd4e3 | ||
|
|
6c9e055d42 | ||
|
|
7455d1bfb2 | ||
|
|
7b923b6625 | ||
|
|
bcd18e9395 | ||
|
|
082d577834 | ||
|
|
68bf4f9df3 | ||
|
|
9348698aac | ||
|
|
979025f7d9 | ||
|
|
9aa09050da | ||
|
|
f331de4185 | ||
|
|
1ce067c854 | ||
|
|
e6d537f0f8 | ||
|
|
6a69a8d21a | ||
|
|
415cc09a06 | ||
|
|
fb482e133e | ||
|
|
c8134ce2ec | ||
|
|
a59c062dda | ||
|
|
fe604d3439 | ||
|
|
53ad8466ad | ||
|
|
9e3c844231 | ||
|
|
85a10e7c72 | ||
|
|
902dc5bdd1 | ||
|
|
666cbc9e47 | ||
|
|
745fae3f76 | ||
|
|
bb2c4d4c3f | ||
|
|
f8c8d6725c | ||
|
|
54747dc800 | ||
|
|
63b6c0cab4 | ||
|
|
92c85a0791 | ||
|
|
83f47bfe6e | ||
|
|
2f034e98c0 | ||
|
|
cb416c3583 | ||
|
|
584353a240 | ||
|
|
729456c2a0 | ||
|
|
a02a2e5332 | ||
|
|
78f0204d86 | ||
|
|
b76ef5ca80 | ||
|
|
788fc01cfb | ||
|
|
4dc9360b34 | ||
|
|
6c0e1b7f01 | ||
|
|
27b91642f2 | ||
|
|
0c7be4b2c7 | ||
|
|
e41ba71828 | ||
|
|
2b2b6b98f1 | ||
|
|
8f6b20abd1 | ||
|
|
21a69c4a61 | ||
|
|
e7b671283a | ||
|
|
d46a7a50b5 | ||
|
|
dfae4e0848 | ||
|
|
a0f7e924e5 | ||
|
|
fd2f3c7dbe | ||
|
|
da442dc02b | ||
|
|
eaea900100 | ||
|
|
449662f858 | ||
|
|
def2219f41 | ||
|
|
4670fc477d | ||
|
|
cea4572843 | ||
|
|
b769d4644a | ||
|
|
3d9b117a74 | ||
|
|
3b1a5f227e | ||
|
|
a66a2d936e | ||
|
|
8b5c334d47 | ||
|
|
5597cf6753 | ||
|
|
9d2d83d8d1 | ||
|
|
bc695479fa | ||
|
|
c0f7f2accd | ||
|
|
08309d6162 | ||
|
|
b217036ad0 | ||
|
|
a276652cbc | ||
|
|
39f643330a | ||
|
|
2967cc917c | ||
|
|
78d22b3165 | ||
|
|
989036bdf2 | ||
|
|
926e9ff92c | ||
|
|
4696567514 | ||
|
|
e153a30186 | ||
|
|
e8bbd3dace | ||
|
|
d2d1344858 | ||
|
|
6be828079d | ||
|
|
7a07a5c646 | ||
|
|
ee649ebeb9 | ||
|
|
67fe2a5a67 | ||
|
|
6ac193c139 | ||
|
|
b7492a6dfa | ||
|
|
224e86f673 | ||
|
|
f014e155d6 | ||
|
|
7aa37cd6cb | ||
|
|
b1cc09fcb6 | ||
|
|
4717293666 | ||
|
|
a80cd0720f | ||
|
|
e238676efc | ||
|
|
e1df231137 | ||
|
|
f40d10b35c | ||
|
|
ea20e5445e | ||
|
|
4a6f2dbdc3 | ||
|
|
11ff01bc61 | ||
|
|
2a292e6a82 | ||
|
|
dc11242b77 | ||
|
|
4ec8f5fc28 | ||
|
|
690f3ed87c | ||
|
|
04e8f6f2e3 | ||
|
|
e96ab86198 | ||
|
|
eae010a23b | ||
|
|
d9d829e37d | ||
|
|
53680fc774 | ||
|
|
46b8378297 | ||
|
|
a26b4f779e | ||
|
|
c2e8c87f3b | ||
|
|
c99e82bd8e | ||
|
|
1398e54896 | ||
|
|
2d93e5bb1c | ||
|
|
6b901d42f7 | ||
|
|
0cc8a968ed | ||
|
|
3f2914c6fa | ||
|
|
9e01786278 | ||
|
|
78ec625cd5 | ||
|
|
02855e3ac4 | ||
|
|
2fc65f135d | ||
|
|
88085ca5a6 | ||
|
|
fe26a82d66 | ||
|
|
e98678b1f7 | ||
|
|
ef2b4d785a | ||
|
|
b721f3e3ce | ||
|
|
13cc0fc08c | ||
|
|
65fe95d464 | ||
|
|
80a887b0d0 | ||
|
|
bed1915da4 | ||
|
|
65cde0af99 | ||
|
|
a0a2b8b265 | ||
|
|
ed01254c84 | ||
|
|
e03864ac03 | ||
|
|
83796c5aa4 | ||
|
|
0e329def1a | ||
|
|
27859cf183 | ||
|
|
5560e7ee3d | ||
|
|
72bab915b1 | ||
|
|
f5fefcdd55 | ||
|
|
160634ea38 | ||
|
|
50fb5a96d8 | ||
|
|
79c7ea16d8 | ||
|
|
a166db0ea1 | ||
|
|
2b905615d1 | ||
|
|
a18c1b5e0c | ||
|
|
c066043ceb | ||
|
|
41d64f1b7c | ||
|
|
36023fdc35 | ||
|
|
8437cf279d | ||
|
|
d2e19cf3c7 | ||
|
|
9a90be6e79 | ||
|
|
903a4c78e2 | ||
|
|
19049bfea8 | ||
|
|
0c4e92ebec | ||
|
|
aefe937adc | ||
|
|
63eda04815 | ||
|
|
18c7783942 | ||
|
|
6c17e1e9c5 | ||
|
|
955355460e | ||
|
|
51a110b9a3 | ||
|
|
43da6c3656 | ||
|
|
411c916a26 | ||
|
|
c0cc14ec99 | ||
|
|
4f8dd8844c | ||
|
|
36f8f43aad | ||
|
|
534d7f570e | ||
|
|
599e514afc | ||
|
|
42054827a2 | ||
|
|
bfe517ef75 | ||
|
|
c585f3455d | ||
|
|
fe1d3dd82b | ||
|
|
92d503335b | ||
|
|
782f93169d | ||
|
|
0c12177091 | ||
|
|
cc90ff97e3 | ||
|
|
525230cf2d | ||
|
|
2df9ef3fca | ||
|
|
9de1b6d9d2 | ||
|
|
94b096259a | ||
|
|
4e7011f12b | ||
|
|
ff123ddcb4 | ||
|
|
9d98fefdef | ||
|
|
573bddb1ae | ||
|
|
8386848e0e | ||
|
|
5ba0220a74 | ||
|
|
d24cadcf00 | ||
|
|
fbe53df424 | ||
|
|
eb0347073e | ||
|
|
45907bdcca | ||
|
|
b5b8aaf731 | ||
|
|
d4eb749729 | ||
|
|
3e09882b0c | ||
|
|
a443b57ead | ||
|
|
3a430b3586 | ||
|
|
f09f8ba4eb | ||
|
|
c6a1560a0f | ||
|
|
805f596f1f | ||
|
|
bcee601d4c | ||
|
|
ea009e802b | ||
|
|
e421eaaf1a | ||
|
|
997cd88db8 | ||
|
|
ccc8fbde05 | ||
|
|
0fdf7721a7 | ||
|
|
96f1863711 | ||
|
|
ea9c7543d9 | ||
|
|
b69a02c878 | ||
|
|
4d9c792a25 | ||
|
|
7a6992845a | ||
|
|
f2deb8f402 | ||
|
|
c067b162b9 | ||
|
|
f1415d7583 | ||
|
|
14f23e79f1 | ||
|
|
a5a55e207c | ||
|
|
990337e4f4 | ||
|
|
c35cce7b34 | ||
|
|
cb36e60af7 | ||
|
|
65baef92b1 | ||
|
|
c624db6833 | ||
|
|
8aed964f47 | ||
|
|
3874cb93e1 | ||
|
|
f966d7ab99 | ||
|
|
2079705626 | ||
|
|
e0a56d350b | ||
|
|
181aa4f43b | ||
|
|
302ba9be44 | ||
|
|
77422c8dda | ||
|
|
eead43e0d9 | ||
|
|
87927d04aa | ||
|
|
aa1b4b2785 | ||
|
|
a7f1d7181d | ||
|
|
c4a50efa43 | ||
|
|
b30f7d95e2 | ||
|
|
845b8aac1b | ||
|
|
d449469a99 | ||
|
|
776ae01c7b | ||
|
|
a9951fc624 | ||
|
|
d8dfcd9cf7 | ||
|
|
fac6744ead | ||
|
|
0a539d1328 | ||
|
|
3e137d1c0e | ||
|
|
8391556f8f | ||
|
|
365374e73e | ||
|
|
19a118c096 | ||
|
|
62a5505c9d | ||
|
|
60dcb66805 | ||
|
|
51e6306c19 | ||
|
|
683453f63a | ||
|
|
366e042c60 | ||
|
|
e599d96b7f | ||
|
|
6f3fde82ef | ||
|
|
8ba561b55b | ||
|
|
79ac8e8cd8 | ||
|
|
cb809156f2 | ||
|
|
d8aa4dde98 | ||
|
|
938fd759c1 | ||
|
|
2740f54331 | ||
|
|
6f929e48b8 | ||
|
|
308db7888a | ||
|
|
657a5c5416 | ||
|
|
d12f3921f9 | ||
|
|
601957ba2a | ||
|
|
e12ffb1a75 | ||
|
|
25543b363b | ||
|
|
3e8ab559b2 | ||
|
|
9059f3f60b | ||
|
|
aa4ce25bda | ||
|
|
5ecd9e0782 | ||
|
|
ba84cc7ea6 | ||
|
|
7edae77736 | ||
|
|
b5f414623e | ||
|
|
58c92c94f6 | ||
|
|
3f0509b0b9 | ||
|
|
33858d2679 | ||
|
|
5d3b4fab0b | ||
|
|
6f998cffe9 | ||
|
|
1f520b904f | ||
|
|
94c49deaf7 | ||
|
|
4360896634 | ||
|
|
8513edc118 | ||
|
|
6dc08ede91 | ||
|
|
8f05520c2f | ||
|
|
0c3878a8fc | ||
|
|
e0d9fa6e95 | ||
|
|
ef5f613b0b | ||
|
|
8617557084 | ||
|
|
55c0fe05cc | ||
|
|
bdaaa9643e | ||
|
|
883ab83c91 | ||
|
|
6df9a499ef | ||
|
|
2bbb6919b6 | ||
|
|
44e0102073 | ||
|
|
a772a2dd51 | ||
|
|
8cd812cf33 | ||
|
|
dbf30f4869 | ||
|
|
3b5ec52a06 | ||
|
|
740e39fb46 | ||
|
|
44fff4fc0a | ||
|
|
acc3a0c9d4 | ||
|
|
e9f7f9d027 | ||
|
|
3ff9bcf853 | ||
|
|
18dd011a84 | ||
|
|
5ccfd4e838 | ||
|
|
b0baad56e7 | ||
|
|
0732938d1d | ||
|
|
1df2d8da9b | ||
|
|
dfdc7567f5 | ||
|
|
3453b7f84c | ||
|
|
59137196c6 | ||
|
|
8d686da3fb | ||
|
|
10aa459ebd | ||
|
|
a3737624fe | ||
|
|
70dd7d8744 | ||
|
|
8d52a98504 | ||
|
|
994166c88f | ||
|
|
2a9252b53b | ||
|
|
e8ff2a36be | ||
|
|
9ac700b758 | ||
|
|
1bf994384d | ||
|
|
0258389b61 | ||
|
|
8491807987 | ||
|
|
e95d07fee1 | ||
|
|
7b0d07e116 | ||
|
|
5228ed8543 | ||
|
|
8f5550576f | ||
|
|
c51e4b5411 | ||
|
|
ef3918f50c | ||
|
|
2b29e5371d | ||
|
|
249815607e | ||
|
|
b9f9138ae4 | ||
|
|
00296bacf2 | ||
|
|
18e6771fcc | ||
|
|
0c8131ebb3 | ||
|
|
831f0209ae | ||
|
|
488fc2719f | ||
|
|
ba98d6dfef | ||
|
|
45d9b69191 | ||
|
|
5205c94c73 | ||
|
|
953bc6370a | ||
|
|
7ffd7b10f5 | ||
|
|
2a054bce6e | ||
|
|
de1ed66aaa | ||
|
|
caeeee9109 | ||
|
|
3c9368b05f | ||
|
|
e31567727a | ||
|
|
7b761c50d7 | ||
|
|
11306a3ce5 | ||
|
|
9d23d4df1f | ||
|
|
45c35d1d37 | ||
|
|
7b1c7cbcb2 | ||
|
|
01b4431627 | ||
|
|
70b478a4b7 | ||
|
|
6e7d227504 | ||
|
|
962afaf613 | ||
|
|
ad0ba5d3bf | ||
|
|
6c729deb77 | ||
|
|
0e887d8b28 | ||
|
|
8fdaf68707 | ||
|
|
0bbbf70e81 | ||
|
|
1342c306a3 | ||
|
|
8890ae4520 | ||
|
|
72d6fa5454 | ||
|
|
1f700a80bc | ||
|
|
d9a25c88e7 | ||
|
|
e060b80b67 | ||
|
|
45687e665d | ||
|
|
5a3dffbc98 | ||
|
|
9e932f025f | ||
|
|
5ea729d0d0 | ||
|
|
67b6c52031 | ||
|
|
8b9c26c12b | ||
|
|
bede7d3fc9 | ||
|
|
cf2d4b890a | ||
|
|
3aa05efe9c | ||
|
|
ac00b513a8 | ||
|
|
7fb4f6de65 | ||
|
|
26251a2158 | ||
|
|
4a0b1f8f10 | ||
|
|
d6cce4a11b | ||
|
|
2ad79ea3d1 | ||
|
|
82ce761b88 | ||
|
|
d1241a6997 | ||
|
|
eb28720cd2 | ||
|
|
436a36a704 | ||
|
|
c2298b2ae0 | ||
|
|
9bc1431291 | ||
|
|
695a57153a | ||
|
|
b19ce01e2e | ||
|
|
d0c74b73dc | ||
|
|
673fce5054 | ||
|
|
9195f7ed31 | ||
|
|
baf97b205f | ||
|
|
13da03396f | ||
|
|
52846e3bf2 | ||
|
|
164c43e2e5 | ||
|
|
3af93df990 | ||
|
|
6026d27b18 | ||
|
|
ba8786c4fe | ||
|
|
5650349868 | ||
|
|
8bd3c32a65 | ||
|
|
07623acf41 | ||
|
|
446629b9f8 | ||
|
|
21dca42e33 | ||
|
|
7c5c9fc8be | ||
|
|
b2262ad4b8 | ||
|
|
4f7aba1e4b | ||
|
|
2bfbc68df8 | ||
|
|
682ae2ed59 | ||
|
|
a13705c1fe | ||
|
|
e4f4ba46f5 | ||
|
|
1f4b343a2e | ||
|
|
f4e01f42c5 | ||
|
|
7416ea1a54 | ||
|
|
b9593b7b4c | ||
|
|
43d7725522 | ||
|
|
d8d3a392b2 | ||
|
|
5a36e72616 | ||
|
|
e9bfe72914 | ||
|
|
db23f28388 | ||
|
|
46bd9a5324 | ||
|
|
d225b6d454 | ||
|
|
17fb991744 | ||
|
|
1035d413de | ||
|
|
9bbccb72e4 | ||
|
|
4b525256fb | ||
|
|
960059e307 | ||
|
|
0941627527 | ||
|
|
efea8c451b | ||
|
|
d9811f4ff1 | ||
|
|
11e6713f20 | ||
|
|
0d37538778 | ||
|
|
c88f8bb277 | ||
|
|
cd8a8ba310 | ||
|
|
9cb81c5fb8 | ||
|
|
e2d3dc1258 | ||
|
|
3c51397be8 | ||
|
|
84d51bf653 | ||
|
|
70c541b06f | ||
|
|
79a7095739 | ||
|
|
cf7fbf0b83 | ||
|
|
f1bf807b67 | ||
|
|
f02581d20a | ||
|
|
03450fc4f7 | ||
|
|
5e0eaa529f | ||
|
|
56184370a7 | ||
|
|
6fdc672dc4 | ||
|
|
ec82a24910 | ||
|
|
06157a9e5c | ||
|
|
a53022bac0 | ||
|
|
896c775fef | ||
|
|
f907d689e5 | ||
|
|
90a9850034 | ||
|
|
4418d348c5 | ||
|
|
7ce93da521 | ||
|
|
aeb08616b5 | ||
|
|
a10df3a133 | ||
|
|
c4039f5663 | ||
|
|
30df4a257a | ||
|
|
6f0df065ad | ||
|
|
8cfc5567d1 | ||
|
|
32defc6833 | ||
|
|
4485cf33df | ||
|
|
d7638ea764 | ||
|
|
d334a472ce | ||
|
|
19672dba39 | ||
|
|
24358eeb51 | ||
|
|
c1a823cd42 | ||
|
|
849c4982a8 | ||
|
|
032d6a1ae1 | ||
|
|
b012c48e62 | ||
|
|
76aa0f70aa | ||
|
|
1c3c525d2b | ||
|
|
9042b16df4 | ||
|
|
1f9198964b | ||
|
|
698513ea84 | ||
|
|
0cb68d9b5d | ||
|
|
221a0942ab | ||
|
|
c83fcc4602 | ||
|
|
b51abc68a8 | ||
|
|
9040c32f52 | ||
|
|
dc81c7244a | ||
|
|
62debd3df4 | ||
|
|
a048cf0f23 | ||
|
|
50ed79c0b3 | ||
|
|
b6963c7cab | ||
|
|
9f5af15987 | ||
|
|
5119048f33 | ||
|
|
090f45092c | ||
|
|
925e36e33b | ||
|
|
720b64ff90 | ||
|
|
4cd9f11f0b | ||
|
|
1b54504165 | ||
|
|
080e514527 | ||
|
|
392ed8b517 | ||
|
|
546701894d | ||
|
|
b90139aee4 | ||
|
|
5d39b554e0 | ||
|
|
51b9ab3661 | ||
|
|
b58672b8ec | ||
|
|
4148b57819 | ||
|
|
8a9f0ddd24 | ||
|
|
4ccc377f1c | ||
|
|
dc56d18595 | ||
|
|
ff78f68443 | ||
|
|
5b52b070d9 | ||
|
|
8f28becd6c | ||
|
|
14212a744a | ||
|
|
cb0af54ab4 | ||
|
|
b6b737a0cd | ||
|
|
092ec1a8f0 | ||
|
|
9476d8bbcd | ||
|
|
72e4a6ccc7 | ||
|
|
73d2c83d8e | ||
|
|
540b315213 | ||
|
|
9594014358 | ||
|
|
d3e781607d | ||
|
|
e9d6874ff5 | ||
|
|
729b43cd54 | ||
|
|
5278060aaa | ||
|
|
d25a1e8463 | ||
|
|
24e260dc0d | ||
|
|
ea6a010c5e | ||
|
|
07715fd541 | ||
|
|
6b9e0e60c5 | ||
|
|
1040b041a4 | ||
|
|
914dcced2b | ||
|
|
520d2bf0a8 | ||
|
|
886a09553f | ||
|
|
9436fa50b8 | ||
|
|
feae293d17 | ||
|
|
8eba025e02 | ||
|
|
060f5dfd6c | ||
|
|
e3e3bb2731 | ||
|
|
1082dd5aa4 | ||
|
|
aaba37325b | ||
|
|
fe225efde5 | ||
|
|
1726a45738 | ||
|
|
09f3ebec80 | ||
|
|
f8a4534496 | ||
|
|
299833b974 | ||
|
|
317a1cd8ca | ||
|
|
81d7ecde04 | ||
|
|
1377769eff | ||
|
|
1cbde75953 | ||
|
|
72d16e22be | ||
|
|
8fa6721a26 | ||
|
|
aeb2355d75 | ||
|
|
81a3adb483 | ||
|
|
8298a22023 | ||
|
|
c3612ec9a6 | ||
|
|
c05f158663 | ||
|
|
671851f345 | ||
|
|
1611429d83 | ||
|
|
a8593078ad | ||
|
|
6165c25976 | ||
|
|
47598a9d7a | ||
|
|
09c727e91a | ||
|
|
0619557f05 | ||
|
|
aa5a9c6c2d | ||
|
|
e3ad81926e | ||
|
|
37abd6d5b8 | ||
|
|
5a7499c80e | ||
|
|
ce3bb23b8c | ||
|
|
845d5b2351 | ||
|
|
08ee361c9c | ||
|
|
c6e6a4bd7d | ||
|
|
85b571594c | ||
|
|
5088c94db5 | ||
|
|
2dc9e9e04c | ||
|
|
2752c641ed | ||
|
|
4c0b6bff9d | ||
|
|
5acebc3e44 | ||
|
|
1e8c065fdb | ||
|
|
b35775b3e0 | ||
|
|
0693853c0a | ||
|
|
6994d12eb6 | ||
|
|
dc0dda35fc | ||
|
|
085fc2a764 | ||
|
|
7ecae9e3a2 | ||
|
|
61d687882f | ||
|
|
354eed23b9 | ||
|
|
99996613bc | ||
|
|
c6e7b1d68a | ||
|
|
69e9823640 | ||
|
|
6e74d02e95 | ||
|
|
397d3073c6 | ||
|
|
ecba921352 | ||
|
|
bea36fdcb5 | ||
|
|
0379e0ee6d | ||
|
|
787a48a795 | ||
|
|
ce257fcc95 | ||
|
|
becc50d2b8 | ||
|
|
673be6056c | ||
|
|
5c7b19527d | ||
|
|
4304099d3a | ||
|
|
5911968469 | ||
|
|
6afde15a1d | ||
|
|
ab578f499c | ||
|
|
e78c3bc6aa | ||
|
|
6394a8ee76 | ||
|
|
5f4e62824f | ||
|
|
f1966f42de | ||
|
|
704039afc2 | ||
|
|
b1c9b27f17 | ||
|
|
3a1c0a707a | ||
|
|
781c28044a | ||
|
|
76346a435a | ||
|
|
a4ebe3532b | ||
|
|
189c8c5a2a | ||
|
|
c1c50fcdb0 | ||
|
|
aad91c32d1 | ||
|
|
b80a84822e | ||
|
|
3e4f86d5fe | ||
|
|
3cb9fa6926 | ||
|
|
900fe003d4 | ||
|
|
3c923f7a20 | ||
|
|
6d95c85719 | ||
|
|
5a0bdb6358 | ||
|
|
49f8d7ac56 | ||
|
|
fd99d88510 | ||
|
|
29f37bbe43 | ||
|
|
1567dd6163 | ||
|
|
297d0b7466 | ||
|
|
7db378a8c8 | ||
|
|
3f5c73ca26 | ||
|
|
53f7ddcb82 | ||
|
|
1f54a40147 | ||
|
|
4c3cdaf593 | ||
|
|
af00eeaf2a | ||
|
|
ed5629f7cf | ||
|
|
88d1854b0d | ||
|
|
328cb3a4dc | ||
|
|
a1c83ebb10 | ||
|
|
d440a78c7b | ||
|
|
6e643d7cda | ||
|
|
0f705bd755 | ||
|
|
f436e44233 | ||
|
|
29f6c5907c | ||
|
|
a4d5015875 | ||
|
|
e8aa282a3a | ||
|
|
44dc55822d | ||
|
|
473bc16384 | ||
|
|
8984a1baf6 | ||
|
|
8fda96eabf | ||
|
|
5110c5d248 | ||
|
|
d23bdee6ed | ||
|
|
2f2ecbbeb0 | ||
|
|
867fe28c5f | ||
|
|
958cdc627a | ||
|
|
473aa9c429 | ||
|
|
846dd24dde | ||
|
|
c01823024d | ||
|
|
1cba327f24 | ||
|
|
c973edee05 | ||
|
|
6744926708 | ||
|
|
a5f040d69d | ||
|
|
0507f25e86 | ||
|
|
f782f18f04 | ||
|
|
ddb58f148d | ||
|
|
75904cf88c | ||
|
|
522deec88b | ||
|
|
4c07d608c5 | ||
|
|
c3490ac819 | ||
|
|
0ada1f2e46 | ||
|
|
6d7493c6e5 | ||
|
|
3306d8a276 | ||
|
|
d5b607eb72 | ||
|
|
af22c74602 | ||
|
|
1822850835 | ||
|
|
f185b9c30d | ||
|
|
d6c39e05f9 | ||
|
|
d7abef33a6 | ||
|
|
a0f6712c57 | ||
|
|
e81acee86b | ||
|
|
bbc9080cfa | ||
|
|
2095280783 | ||
|
|
d2b2e9a0d9 | ||
|
|
e62adf9131 | ||
|
|
4f22a869b8 | ||
|
|
8cf5868a30 | ||
|
|
f8d2b47006 | ||
|
|
71f0f53cae | ||
|
|
5b1fe105ba | ||
|
|
7f447ac21f | ||
|
|
425c7cd390 | ||
|
|
7f72143ee7 | ||
|
|
e743500d6c | ||
|
|
77e3952849 | ||
|
|
21dab1bf50 | ||
|
|
4e9aa726c6 | ||
|
|
004babb572 | ||
|
|
256c048598 | ||
|
|
59b884f4e4 | ||
|
|
45ff535d31 | ||
|
|
4cd8c53645 | ||
|
|
b856ef4ea6 | ||
|
|
ea3d83962f | ||
|
|
1d79076e65 | ||
|
|
1e6bae6801 | ||
|
|
6cda51ebbe | ||
|
|
e4c4c1b964 | ||
|
|
939c8c6d0e | ||
|
|
33c3963f66 | ||
|
|
88bfaa532d | ||
|
|
66e321ebea | ||
|
|
8d2838e928 | ||
|
|
98d896eb81 | ||
|
|
62bd56e70d | ||
|
|
bbc7e0f648 | ||
|
|
534c8e0bc3 | ||
|
|
1f9897e551 | ||
|
|
eba54c8da3 | ||
|
|
e47ac5b02d | ||
|
|
9d134f8171 | ||
|
|
1ec477b5bc | ||
|
|
022f203a2e | ||
|
|
191f21bf50 | ||
|
|
98c4b37664 | ||
|
|
2f2b40ca53 | ||
|
|
8a8be30657 | ||
|
|
0c0aafb956 | ||
|
|
c0bca5b923 | ||
|
|
55ea356efd | ||
|
|
fbcd357b69 | ||
|
|
41db619e28 | ||
|
|
1de8b11d75 | ||
|
|
b85f082d03 | ||
|
|
c2f08b47aa | ||
|
|
329784c9a7 | ||
|
|
1d357aab0a | ||
|
|
fe6deb559b | ||
|
|
591ef4d1f9 | ||
|
|
6a8a991f42 | ||
|
|
87161cb97a | ||
|
|
a28b667b38 | ||
|
|
62c8b4b9e9 | ||
|
|
bc0d5e2e7e | ||
|
|
a66ea60ae7 | ||
|
|
80f908353f | ||
|
|
a3a8ad87d3 | ||
|
|
ea52a7a9ec | ||
|
|
972042645c | ||
|
|
e01c8d4e13 | ||
|
|
351373aea5 | ||
|
|
287680df87 | ||
|
|
aa96a98722 | ||
|
|
58aa231cd2 | ||
|
|
d0a59e9d6f | ||
|
|
972c278356 | ||
|
|
d3b236107b | ||
|
|
ddd359afe0 | ||
|
|
0278777ff4 | ||
|
|
c8b703778b | ||
|
|
a0d49f8c29 | ||
|
|
93f9a318b0 | ||
|
|
bc6679505d | ||
|
|
5698e1a4fb | ||
|
|
61c39a8919 | ||
|
|
ae2e8b6abd | ||
|
|
e1bce30ee3 | ||
|
|
44da884057 | ||
|
|
7f9f05ae0e | ||
|
|
4638d173b6 | ||
|
|
43bc3cee06 | ||
|
|
2db68559d5 | ||
|
|
122b07b757 | ||
|
|
d6760ca4b9 | ||
|
|
fe036e75a3 | ||
|
|
a574e77f0a | ||
|
|
b4c885067d | ||
|
|
200fb9d9ee | ||
|
|
ec06fdcda6 | ||
|
|
fb31cc7268 | ||
|
|
afdbf2ac0b | ||
|
|
4197230ffd | ||
|
|
952e22367e | ||
|
|
a497660c64 | ||
|
|
bd3f4e08b2 | ||
|
|
c2e5aba0e4 | ||
|
|
729cf2c033 | ||
|
|
2633bd46c3 | ||
|
|
f6430d421e | ||
|
|
1045290320 | ||
|
|
0416bb20b3 | ||
|
|
cb7223dee1 | ||
|
|
59b535b0d8 | ||
|
|
6b9d2c19a7 | ||
|
|
3d7fbefa24 | ||
|
|
24311c2e71 | ||
|
|
93db8cc163 | ||
|
|
bdd833e05b | ||
|
|
64bcb9b4c3 | ||
|
|
6f2cf36ba6 | ||
|
|
4828af7130 | ||
|
|
0d0aa7c9a0 | ||
|
|
f0c962fde0 | ||
|
|
a04197f145 | ||
|
|
530e9b05ef | ||
|
|
5276b5f9f7 | ||
|
|
9a8f5f7186 | ||
|
|
7de2b3567d | ||
|
|
2a53fd6f13 | ||
|
|
1092fd4198 | ||
|
|
dd5619c1f9 | ||
|
|
06cffc101f | ||
|
|
5f17dae777 | ||
|
|
001a8a276f | ||
|
|
16986f0f56 | ||
|
|
36ff2808bd | ||
|
|
b566e10847 | ||
|
|
1b4fbf17a8 | ||
|
|
1475b1a299 | ||
|
|
147c5455ff | ||
|
|
73bfd9b66c | ||
|
|
f5fa061392 | ||
|
|
71b50171de | ||
|
|
a172caba24 | ||
|
|
ab39c3bbdb | ||
|
|
29733cc474 | ||
|
|
00a358cfb6 | ||
|
|
000475884d | ||
|
|
49b2cda0c2 | ||
|
|
fdf229400a | ||
|
|
c79d485d69 | ||
|
|
3f9aa621d1 | ||
|
|
c94c00d933 | ||
|
|
e540855bf9 | ||
|
|
e3d55f4e3d | ||
|
|
988fc92456 | ||
|
|
c02b153ef1 | ||
|
|
70ca4893ba | ||
|
|
4e15d3779c | ||
|
|
f924a18d07 | ||
|
|
bce1ec1c66 | ||
|
|
7c4347ad9b | ||
|
|
820c594c1e | ||
|
|
5c2d319b3a | ||
|
|
ff62cc55c2 | ||
|
|
dee872fec2 | ||
|
|
87b670ca4e | ||
|
|
60c4c2f526 | ||
|
|
6fd03f826c | ||
|
|
365cdb9fef | ||
|
|
4342602202 | ||
|
|
a168c10938 | ||
|
|
09da6f870a | ||
|
|
8a4b334d20 | ||
|
|
4f6916a2df | ||
|
|
14a9c94944 | ||
|
|
6ad0fda364 | ||
|
|
491c124ac1 | ||
|
|
81cb7b4f84 | ||
|
|
90c91c2b16 | ||
|
|
161d2810a3 | ||
|
|
9c0dae8d9a | ||
|
|
6375be4d2c | ||
|
|
64234815cc | ||
|
|
b56d4d1ca3 | ||
|
|
8d31b287f2 | ||
|
|
8e59d905ba | ||
|
|
028661f9f8 | ||
|
|
f6189c6d8a | ||
|
|
ee677ced24 | ||
|
|
5f5c142d03 | ||
|
|
2a7fe455ad | ||
|
|
047469de5b | ||
|
|
7a61a68f00 | ||
|
|
50f71390f8 | ||
|
|
fba7bb68fe | ||
|
|
2f6749bf5e | ||
|
|
9253c6dd7b | ||
|
|
e23ad8239b | ||
|
|
2f9e624c31 | ||
|
|
a336b50e0f | ||
|
|
5bc4a96e77 | ||
|
|
113ba8223c | ||
|
|
a760150d75 | ||
|
|
42a52dc606 | ||
|
|
b0c45c115e | ||
|
|
6a427a04ff |
26
.github/workflows/ci.yml
vendored
Normal file
26
.github/workflows/ci.yml
vendored
Normal file
@@ -0,0 +1,26 @@
|
||||
# This workflow will build a .NET project
|
||||
# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-net
|
||||
|
||||
name: .NET
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ "master" ]
|
||||
pull_request:
|
||||
branches: [ "master" ]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Setup .NET
|
||||
uses: actions/setup-dotnet@v3
|
||||
with:
|
||||
dotnet-version: 7.0.x
|
||||
- name: Build
|
||||
run: dotnet build Radzen.Blazor/Radzen.Blazor.csproj
|
||||
- name: Test
|
||||
run: dotnet test Radzen.Blazor.Tests/Radzen.Blazor.Tests.csproj
|
||||
@@ -19,7 +19,7 @@ You can ask your question here. Please use the [Radzen.Blazor Components](https:
|
||||
|
||||
### Dedicated technical support
|
||||
|
||||
Radzen staff provides technical support with guaranteed response time to Radzen Professional and Enterprise subscribers. The pricing options are available [here](https://www.radzen.com/pricing/).
|
||||
Radzen staff provides technical support with guaranteed response time to Radzen Professional and Enterprise subscribers. The pricing options are available [here](https://www.radzen.com/blazor-studio/pricing/).
|
||||
|
||||
## How Can I Contribute?
|
||||
|
||||
|
||||
15
Dockerfile
15
Dockerfile
@@ -13,18 +13,19 @@ RUN apt-get update && apt-get install unzip wget git -y && wget -q -P /tmp https
|
||||
COPY Radzen.Blazor /app/Radzen.Blazor
|
||||
COPY Radzen.DocFX /app/DocFX
|
||||
COPY RadzenBlazorDemos /app/RadzenBlazorDemos
|
||||
COPY RadzenBlazorDemos.Host /app/RadzenBlazorDemos.Host
|
||||
WORKDIR /app
|
||||
RUN docfx DocFX/docfx.json
|
||||
|
||||
FROM mcr.microsoft.com/dotnet/sdk:6.0-focal
|
||||
FROM mcr.microsoft.com/dotnet/sdk:7.0
|
||||
|
||||
COPY --from=0 /app/RadzenBlazorDemos /app
|
||||
WORKDIR /app
|
||||
COPY --from=0 /app/RadzenBlazorDemos.Host /app/RadzenBlazorDemos.Host
|
||||
COPY --from=0 /app/RadzenBlazorDemos /app/RadzenBlazorDemos
|
||||
|
||||
WORKDIR /app/RadzenBlazorDemos.Host
|
||||
RUN dotnet publish -c Release -o out
|
||||
COPY RadzenBlazorDemos/northwind.db /app/out
|
||||
COPY RadzenBlazorDemos/northwind.sql /app/out
|
||||
|
||||
ENV ASPNETCORE_URLS http://*:5000
|
||||
WORKDIR /app/out
|
||||
WORKDIR /app/RadzenBlazorDemos.Host/out
|
||||
|
||||
ENTRYPOINT ["dotnet", "RadzenBlazorDemos.dll"]
|
||||
ENTRYPOINT ["dotnet", "RadzenBlazorDemos.Host.dll"]
|
||||
|
||||
2
LICENSE
2
LICENSE
@@ -1,6 +1,6 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2018-2022 Radzen Ltd
|
||||
Copyright (c) 2018-2023 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
|
||||
|
||||
49
README.md
49
README.md
@@ -5,7 +5,7 @@
|
||||
</h1>
|
||||
|
||||
<p align="center">
|
||||
A set of <strong>60+ free and open source</strong> native Blazor UI controls.
|
||||
A set of <strong>70+ free and open source</strong> native Blazor UI controls.
|
||||
</p>
|
||||
|
||||
<div align="center">
|
||||
@@ -21,7 +21,7 @@
|
||||
<img alt="License - MIT" src="https://img.shields.io/github/license/radzenhq/radzen-blazor?logo=github&style=for-the-badge" />
|
||||
</a>
|
||||
<a href="https://www.nuget.org/packages/Radzen.Blazor">
|
||||
<img alt="Nuget Downloads" src="https://img.shields.io/nuget/dt/Radzen.Blazor?color=%232694F9&label=nuget%20downloads&logo=nuget&style=for-the-badge" />
|
||||
<img alt="NuGet Downloads" src="https://img.shields.io/nuget/dt/Radzen.Blazor?color=%232694F9&label=nuget%20downloads&logo=nuget&style=for-the-badge" />
|
||||
</a>
|
||||
<img alt="Last Commit" src="https://img.shields.io/github/last-commit/radzenhq/radzen-blazor?logo=github&style=for-the-badge" />
|
||||
<a href="https://github.com/radzenhq/radzen-blazor/graphs/contributors">
|
||||
@@ -39,15 +39,15 @@
|
||||
|
||||
### :sparkles: Free
|
||||
|
||||
Radzen Blazor Components are open source and free for commercial use. You can install them from [nuget](https://www.nuget.org/packages/Radzen.Blazor) or build your own copy from source.
|
||||
Radzen Blazor Components are open source and free for commercial use. You can install them from [NuGet](https://www.nuget.org/packages/Radzen.Blazor) or build your own copy from source.
|
||||
|
||||
Paid support is available as part of the [Radzen Professional subscription](https://www.radzen.com/pricing/).
|
||||
Paid support is available as part of the [Radzen Professional subscription](https://www.radzen.com/blazor-studio/pricing/).
|
||||
|
||||
### :computer: Native
|
||||
|
||||
The components are implemented in C# and take full advantage of the Blazor framework. They do not depend on or wrap existing JavaScript frameworks or libraries.
|
||||
|
||||
Both **server-side** and **client-side** (WASM) Blazor are supported.
|
||||
Blazor Server and Blazor WebAssembly are fully supported.
|
||||
|
||||
### :seedling: Growing
|
||||
|
||||
@@ -55,7 +55,7 @@ We add new components and features on a regular basis.
|
||||
|
||||
Short development cycle. We release as soon as new stuff is available. No more quarterly releases.
|
||||
|
||||
## Support exceeding your expectations
|
||||
## Support exceeding your expectations
|
||||
|
||||
### :speech_balloon: Community Support
|
||||
Everybody is welcome to visit the [Radzen Community forum](https://forum.radzen.com/). Join the growing community and participate in the discussions!
|
||||
@@ -64,10 +64,10 @@ Everybody is welcome to visit the [Radzen Community forum](https://forum.radzen.
|
||||
|
||||
The Radzen team monitors the forum threads, but does not guarantee a response to every question. For guaranteed responses you may consider the dedicated support option.
|
||||
|
||||
Dedicated support for the Radzen Blazor Components is available as part of the [Radzen Professional subscription](https://www.radzen.com/pricing/).
|
||||
Dedicated support for the Radzen Blazor Components is available as part of the [Radzen Professional subscription](https://www.radzen.com/blazor-studio/pricing/).
|
||||
|
||||
Our flagship product [Radzen Studio](https://www.radzen.com/features/) provides tons of productivity features for Blazor developers:
|
||||
- The first in the industry WYSIWYG Blazor design time canvas
|
||||
Our flagship product [Radzen Blazor Studio](https://www.radzen.com/blazor-studio/) provides tons of productivity features for Blazor developers:
|
||||
- An industry-leading WYSIWYG Blazor design time canvas
|
||||
- Scaffolding a complete CRUD applications from a database
|
||||
- Built-in security - authentication and authorization
|
||||
- Visual Studio Code and Professional support
|
||||
@@ -78,9 +78,9 @@ Our flagship product [Radzen Studio](https://www.radzen.com/features/) provides
|
||||
|
||||
### 1. Install
|
||||
|
||||
Radzen Blazor Components are distributed as a [Radzen.Blazor nuget package](https://www.nuget.org/packages/Radzen.Blazor). You can add them to your project in one of the following ways
|
||||
Radzen Blazor Components are distributed as a [Radzen.Blazor NuGet package](https://www.nuget.org/packages/Radzen.Blazor). You can add them to your project in one of the following ways
|
||||
- Install the package from command line by running `dotnet add package Radzen.Blazor`
|
||||
- Add the project from the Visual Nuget Package Manager
|
||||
- Add the project from the Visual NuGet Package Manager
|
||||
- Manually edit the .csproj file and add a project reference
|
||||
|
||||
### 2. Import the namespace
|
||||
@@ -89,26 +89,30 @@ Open the `_Imports.razor` file of your Blazor application and add this line `@us
|
||||
|
||||
### 3. Include a theme
|
||||
|
||||
Open the `_Host.cshtml` file (server-side Blazor) or `wwwroot/index.html` (client-side Blazor) and include a theme CSS file by adding this snippet
|
||||
```html
|
||||
<link rel="stylesheet" href="_content/Radzen.Blazor/css/default.css">
|
||||
```
|
||||
If you either add Bootstrap manually or don't use it at all, include this instead:
|
||||
```html
|
||||
<link rel="stylesheet" href="_content/Radzen.Blazor/css/default-base.css">
|
||||
```
|
||||
Radzen Blazor components come with five free themes: Material, Standard, Default, Dark, Software and Humanistic.
|
||||
|
||||
To use a theme
|
||||
1. Pick a theme. The [online demos](https://blazor.radzen.com/colors) allow you to preview the available options via the theme dropdown located in the header. The Material theme is currently selected by default.
|
||||
1. Include the theme CSS file in your Blazor application. Open `Pages\_Layout.cshtml` (Blazor Server .NET 6), `Pages\_Host.cshtml` (Blazor Server .NET 7) or `wwwroot/index.html` (Blazor WebAssembly) and include a theme CSS file by adding this snippet
|
||||
```html
|
||||
<link rel="stylesheet" href="_content/Radzen.Blazor/css/material-base.css">
|
||||
```
|
||||
|
||||
To include a different theme (i.e. Standard) just change the name of the CSS file:
|
||||
```
|
||||
<link rel="stylesheet" href="_content/Radzen.Blazor/css/standard-base.css">
|
||||
```
|
||||
|
||||
### 4. Include Radzen.Blazor.js
|
||||
|
||||
Open the `_Host.cshtml` file (server-side Blazor) or `wwwroot/index.html` (client-side Blazor) and include this snippet:
|
||||
Open `Pages\_Layout.cshtml` (Blazor Server .NET 6), `Pages\_Host.cshtml` (Blazor Server .NET 7) or `wwwroot/index.html` (Blazor WebAssembly) and include this snippet:
|
||||
|
||||
```html
|
||||
<script src="_content/Radzen.Blazor/Radzen.Blazor.js"></script>
|
||||
```
|
||||
|
||||
### 5. Use a component
|
||||
Use any Radzen Blazor component by typing its tag name in a Blazor page e.g.
|
||||
Use any Radzen Blazor component by typing its tag name in a Blazor page e.g.
|
||||
```html
|
||||
<RadzenButton Text="Hi"></RadzenButton>
|
||||
```
|
||||
@@ -133,3 +137,6 @@ Use any Radzen Blazor component by typing its tag name in a Blazor page e.g.
|
||||
}
|
||||
}
|
||||
```
|
||||
## Run demos locally
|
||||
|
||||
Use Radzen.Server.sln to open and run demos as Blazor server application or Radzen.WebAssembly.sln to open and run demos as Blazor WebAssembly application. Radzen.sln has reference to all projects including tests.
|
||||
|
||||
74
Radzen.Blazor.Tests/AutoCompleteTests.cs
Normal file
74
Radzen.Blazor.Tests/AutoCompleteTests.cs
Normal file
@@ -0,0 +1,74 @@
|
||||
using Xunit;
|
||||
|
||||
namespace Radzen.Blazor.Tests
|
||||
{
|
||||
public class AutoCompleteTests
|
||||
{
|
||||
[Fact]
|
||||
public void AutoComplete_Enum_Converts_To_Attr_Value()
|
||||
{
|
||||
// Options
|
||||
Assert.Equal("off", AutoCompleteType.Off.GetAutoCompleteValue());
|
||||
Assert.Equal("on", AutoCompleteType.On.GetAutoCompleteValue());
|
||||
Assert.Equal("name", AutoCompleteType.Name.GetAutoCompleteValue());
|
||||
Assert.Equal("honorific-prefix", AutoCompleteType.HonorificPrefix.GetAutoCompleteValue());
|
||||
Assert.Equal("given-name", AutoCompleteType.GivenName.GetAutoCompleteValue());
|
||||
Assert.Equal("additional-name", AutoCompleteType.AdditionalName.GetAutoCompleteValue());
|
||||
Assert.Equal("family-name", AutoCompleteType.FamilyName.GetAutoCompleteValue());
|
||||
Assert.Equal("honorific-suffix", AutoCompleteType.HonorificSuffix.GetAutoCompleteValue());
|
||||
Assert.Equal("nickname", AutoCompleteType.Nickname.GetAutoCompleteValue());
|
||||
Assert.Equal("email", AutoCompleteType.Email.GetAutoCompleteValue());
|
||||
Assert.Equal("username", AutoCompleteType.Username.GetAutoCompleteValue());
|
||||
Assert.Equal("new-password", AutoCompleteType.NewPassword.GetAutoCompleteValue());
|
||||
Assert.Equal("current-password", AutoCompleteType.CurrentPassword.GetAutoCompleteValue());
|
||||
Assert.Equal("one-time-code", AutoCompleteType.OneTimeCode.GetAutoCompleteValue());
|
||||
Assert.Equal("organization-title", AutoCompleteType.OrganizationTitle.GetAutoCompleteValue());
|
||||
Assert.Equal("organization", AutoCompleteType.Organization.GetAutoCompleteValue());
|
||||
Assert.Equal("street-address", AutoCompleteType.StreetAddress.GetAutoCompleteValue());
|
||||
Assert.Equal("address-line1", AutoCompleteType.AddressLine1.GetAutoCompleteValue());
|
||||
Assert.Equal("address-line2", AutoCompleteType.AddressLine2.GetAutoCompleteValue());
|
||||
Assert.Equal("address-line3", AutoCompleteType.AddressLine3.GetAutoCompleteValue());
|
||||
Assert.Equal("address-level1", AutoCompleteType.AddressLevel1.GetAutoCompleteValue());
|
||||
Assert.Equal("address-level2", AutoCompleteType.AddressLevel2.GetAutoCompleteValue());
|
||||
Assert.Equal("address-level3", AutoCompleteType.AddressLevel3.GetAutoCompleteValue());
|
||||
Assert.Equal("address-level4", AutoCompleteType.AddressLevel4.GetAutoCompleteValue());
|
||||
Assert.Equal("country", AutoCompleteType.Country.GetAutoCompleteValue());
|
||||
Assert.Equal("country-name", AutoCompleteType.CountryName.GetAutoCompleteValue());
|
||||
Assert.Equal("postal-code", AutoCompleteType.PostalCode.GetAutoCompleteValue());
|
||||
Assert.Equal("cc-name", AutoCompleteType.CcName.GetAutoCompleteValue());
|
||||
Assert.Equal("cc-given-name", AutoCompleteType.CcGivenName.GetAutoCompleteValue());
|
||||
Assert.Equal("cc-additional-name", AutoCompleteType.CcAdditionalName.GetAutoCompleteValue());
|
||||
Assert.Equal("cc-family-name", AutoCompleteType.CcFamilyName.GetAutoCompleteValue());
|
||||
Assert.Equal("cc-number", AutoCompleteType.CcNumber.GetAutoCompleteValue());
|
||||
Assert.Equal("cc-exp", AutoCompleteType.CcExp.GetAutoCompleteValue());
|
||||
Assert.Equal("cc-exp-month", AutoCompleteType.CcExpMonth.GetAutoCompleteValue());
|
||||
Assert.Equal("cc-exp-year", AutoCompleteType.CcExpYear.GetAutoCompleteValue());
|
||||
Assert.Equal("cc-csc", AutoCompleteType.CcCsc.GetAutoCompleteValue());
|
||||
Assert.Equal("cc-type", AutoCompleteType.CcType.GetAutoCompleteValue());
|
||||
Assert.Equal("transaction-currency", AutoCompleteType.TransactionCurrency.GetAutoCompleteValue());
|
||||
Assert.Equal("transaction-amount", AutoCompleteType.TransactionAmount.GetAutoCompleteValue());
|
||||
Assert.Equal("language", AutoCompleteType.Language.GetAutoCompleteValue());
|
||||
Assert.Equal("bday", AutoCompleteType.Bday.GetAutoCompleteValue());
|
||||
Assert.Equal("bday-day", AutoCompleteType.BdayDay.GetAutoCompleteValue());
|
||||
Assert.Equal("bday-month", AutoCompleteType.BdayMonth.GetAutoCompleteValue());
|
||||
Assert.Equal("bday-year", AutoCompleteType.BdayYear.GetAutoCompleteValue());
|
||||
Assert.Equal("sex", AutoCompleteType.Sex.GetAutoCompleteValue());
|
||||
Assert.Equal("tel", AutoCompleteType.Tel.GetAutoCompleteValue());
|
||||
Assert.Equal("tel-country-code", AutoCompleteType.TelCountryCode.GetAutoCompleteValue());
|
||||
Assert.Equal("tel-national", AutoCompleteType.TelNational.GetAutoCompleteValue());
|
||||
Assert.Equal("tel-area-code", AutoCompleteType.TelAreaCode.GetAutoCompleteValue());
|
||||
Assert.Equal("tel-local", AutoCompleteType.TelLocal.GetAutoCompleteValue());
|
||||
Assert.Equal("tel-extension", AutoCompleteType.TelExtension.GetAutoCompleteValue());
|
||||
Assert.Equal("impp", AutoCompleteType.Impp.GetAutoCompleteValue());
|
||||
Assert.Equal("url", AutoCompleteType.Url.GetAutoCompleteValue());
|
||||
Assert.Equal("photo", AutoCompleteType.Photo.GetAutoCompleteValue());
|
||||
// Synonyms
|
||||
Assert.Equal("address-level1", AutoCompleteType.State.GetAutoCompleteValue());
|
||||
Assert.Equal("address-level1", AutoCompleteType.Province.GetAutoCompleteValue());
|
||||
Assert.Equal("postal-code", AutoCompleteType.ZipCode.GetAutoCompleteValue());
|
||||
Assert.Equal("given-name", AutoCompleteType.FirstName.GetAutoCompleteValue());
|
||||
Assert.Equal("additional-name", AutoCompleteType.MiddleName.GetAutoCompleteValue());
|
||||
Assert.Equal("family-name", AutoCompleteType.LastName.GetAutoCompleteValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -134,11 +134,11 @@ namespace Radzen.Blazor.Tests
|
||||
|
||||
component.SetParametersAndRender(parameters => parameters.Add(p => p.ButtonStyle, ButtonStyle.Primary));
|
||||
|
||||
Assert.Contains(@$"btn-primary", component.Markup);
|
||||
Assert.Contains(@$"rz-primary", component.Markup);
|
||||
|
||||
component.SetParametersAndRender(parameters => parameters.Add(p => p.ButtonStyle, ButtonStyle.Secondary));
|
||||
|
||||
Assert.Contains(@$"btn-secondary", component.Markup);
|
||||
Assert.Contains(@$"rz-secondary", component.Markup);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
||||
54
Radzen.Blazor.Tests/ChartTests.cs
Normal file
54
Radzen.Blazor.Tests/ChartTests.cs
Normal file
@@ -0,0 +1,54 @@
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Bunit;
|
||||
using Radzen.Blazor.Rendering;
|
||||
using Xunit;
|
||||
using Xunit.Abstractions;
|
||||
|
||||
namespace Radzen.Blazor.Tests;
|
||||
|
||||
public class ChartTests
|
||||
{
|
||||
private readonly ITestOutputHelper output;
|
||||
public ChartTests(ITestOutputHelper output)
|
||||
{
|
||||
this.output = output;
|
||||
}
|
||||
|
||||
[Fact(Timeout = 30000)]
|
||||
public async Task Chart_Tooltip_Performance()
|
||||
{
|
||||
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});
|
||||
|
||||
var seriesData = Enumerable.Range(0, 5000).Select(i => new Point { X = i, Y = i });
|
||||
var chart = ctx.RenderComponent<RadzenChart>(chartParameters =>
|
||||
chartParameters
|
||||
.AddChildContent<RadzenLineSeries<Point>>(seriesParameters =>
|
||||
seriesParameters
|
||||
.Add(p => p.CategoryProperty, nameof(Point.X))
|
||||
.Add(p => p.ValueProperty, nameof(Point.Y))
|
||||
.Add(p => p.Data, seriesData))
|
||||
.AddChildContent<RadzenCategoryAxis>(axisParameters =>
|
||||
axisParameters
|
||||
.Add(p => p.Step, 100)
|
||||
.Add(p => p.Formatter, x =>
|
||||
{
|
||||
Thread.Sleep(100);
|
||||
return $"{x}";
|
||||
})));
|
||||
|
||||
var stopwatch = Stopwatch.StartNew();
|
||||
foreach (var _ in Enumerable.Range(0, 10))
|
||||
{
|
||||
await chart.InvokeAsync(() => chart.Instance.MouseMove(100, 80));
|
||||
Assert.Contains("<div class=\"rz-chart-tooltip", chart.Markup);
|
||||
await chart.InvokeAsync(() => chart.Instance.MouseMove(0, 0));
|
||||
Assert.DoesNotContain("<div class=\"rz-chart-tooltip", chart.Markup);
|
||||
}
|
||||
output.WriteLine($"Time took: {stopwatch.Elapsed}");
|
||||
}
|
||||
}
|
||||
@@ -160,5 +160,83 @@ namespace Radzen.Blazor.Tests
|
||||
Assert.Contains(@$"rz-state-active", component.Markup);
|
||||
Assert.Contains(@$"rzi-times", component.Markup);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void CheckBox_Renders_ReadonlyParameter()
|
||||
{
|
||||
using var ctx = new TestContext();
|
||||
|
||||
var component = ctx.RenderComponent<RadzenCheckBox<bool>>();
|
||||
|
||||
component.SetParametersAndRender(parameters => parameters.Add<bool>(p => p.ReadOnly, true));
|
||||
|
||||
Assert.Contains(@$"readonly", component.Markup);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void CheckBox_DoesNotRaise_ChangedEvent_ReadonlyParameter()
|
||||
{
|
||||
using var ctx = new TestContext();
|
||||
|
||||
var component = ctx.RenderComponent<RadzenCheckBox<bool>>();
|
||||
|
||||
var raised = false;
|
||||
|
||||
component.SetParametersAndRender(parameters => parameters
|
||||
.Add<bool>(p => p.ReadOnly, true)
|
||||
.Add(p => p.Change, args => { raised = true; })
|
||||
);
|
||||
|
||||
component.Find("div.rz-chkbox-box").Click();
|
||||
|
||||
Assert.False(raised);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void CheckBox_DoesNotRaise_ValueChangedEvent_ReadonlyParameter()
|
||||
{
|
||||
using var ctx = new TestContext();
|
||||
|
||||
var component = ctx.RenderComponent<RadzenCheckBox<bool>>();
|
||||
|
||||
var raised = false;
|
||||
|
||||
component.SetParametersAndRender(parameters => parameters
|
||||
.Add<bool>(p => p.ReadOnly, true)
|
||||
.Add(p => p.ValueChanged, args => { raised = true; })
|
||||
);
|
||||
|
||||
component.Find("div.rz-chkbox-box").Click();
|
||||
|
||||
Assert.False(raised);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void CheckBox_ValueNotChanged_ReadonlyParameter()
|
||||
{
|
||||
using var ctx = new TestContext();
|
||||
|
||||
var component = ctx.RenderComponent<RadzenCheckBox<bool>>();
|
||||
|
||||
var value = true;
|
||||
|
||||
component.SetParametersAndRender(parameters => parameters
|
||||
.Add<bool>(p => p.ReadOnly, true)
|
||||
.Add<bool>(p => p.Value, value)
|
||||
);
|
||||
|
||||
component.Find("div.rz-chkbox-box").Click();
|
||||
|
||||
Assert.Contains(@$"rz-state-active", component.Markup);
|
||||
|
||||
component.SetParametersAndRender(parameters => parameters
|
||||
.Add<bool>(p => p.ReadOnly, !true)
|
||||
.Add<bool>(p => p.Value, value)
|
||||
);
|
||||
|
||||
component.Find("div.rz-chkbox-box").Click();
|
||||
|
||||
Assert.DoesNotContain(@$"rz-state-active", component.Markup);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
16
Radzen.Blazor.Tests/ColorPickerTests.cs
Normal file
16
Radzen.Blazor.Tests/ColorPickerTests.cs
Normal file
@@ -0,0 +1,16 @@
|
||||
using Bunit;
|
||||
using Xunit;
|
||||
|
||||
namespace Radzen.Blazor.Tests
|
||||
{
|
||||
public class ColorPickerTests
|
||||
{
|
||||
[Fact]
|
||||
public void ColorPicker_ShouldAcceptInvalidValues()
|
||||
{
|
||||
using var ctx = new TestContext();
|
||||
|
||||
var component = ctx.RenderComponent<RadzenColorPicker>(ComponentParameter.CreateParameter("Value", "invalid"));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -74,11 +74,11 @@ namespace Radzen.Blazor.Tests
|
||||
});
|
||||
});
|
||||
|
||||
var markup = new Regex(@"\s\s+").Replace(component.Markup, "").Trim();
|
||||
var data = component.FindAll(".rz-cell-data");
|
||||
|
||||
Assert.Contains(@$"<span class=""rz-cell-data"">1</span>", markup);
|
||||
Assert.Contains(@$"<span class=""rz-cell-data"">2</span>", markup);
|
||||
Assert.Contains(@$"<span class=""rz-cell-data"">3</span>", markup);
|
||||
Assert.Equal("1", data[0].TextContent.Trim());
|
||||
Assert.Equal("2", data[1].TextContent.Trim());
|
||||
Assert.Equal("3", data[2].TextContent.Trim());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
@@ -99,9 +99,56 @@ namespace Radzen.Blazor.Tests
|
||||
});
|
||||
});
|
||||
|
||||
var markup = new Regex(@"\s\s+").Replace(component.Markup, "").Trim();
|
||||
var title = component.Find(".rz-column-title");
|
||||
Assert.Equal("MyId", title.TextContent.Trim());
|
||||
}
|
||||
|
||||
Assert.Contains(@$"<span class=""rz-column-title"">MyId</span>", markup);
|
||||
[Fact]
|
||||
public void DataGrid_Renders_TitleAttribute()
|
||||
{
|
||||
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(p => p.ShowColumnTitleAsTooltip, true);
|
||||
parameterBuilder.Add<IEnumerable<dynamic>>(p => p.Data, new[] { new { Id = 1 }, new { Id = 2 }, new { Id = 3 } });
|
||||
parameterBuilder.Add<RenderFragment>(p => p.Columns, builder =>
|
||||
{
|
||||
builder.OpenComponent(0, typeof(RadzenDataGridColumn<dynamic>));
|
||||
builder.AddAttribute(1, "Title", "MyId");
|
||||
builder.CloseComponent();
|
||||
});
|
||||
});
|
||||
|
||||
var title = component.Find(".rz-column-title");
|
||||
Assert.Equal("MyId", title.TextContent.Trim());
|
||||
Assert.Equal("MyId", title.GetAttribute("title"));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void DataGrid_DoesNotRender_TitleAttribute()
|
||||
{
|
||||
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(p => p.ShowColumnTitleAsTooltip, false);
|
||||
parameterBuilder.Add<IEnumerable<dynamic>>(p => p.Data, new[] { new { Id = 1 }, new { Id = 2 }, new { Id = 3 } });
|
||||
parameterBuilder.Add<RenderFragment>(p => p.Columns, builder =>
|
||||
{
|
||||
builder.OpenComponent(0, typeof(RadzenDataGridColumn<dynamic>));
|
||||
builder.AddAttribute(1, "Title", "MyId");
|
||||
builder.CloseComponent();
|
||||
});
|
||||
});
|
||||
|
||||
var title = component.Find(".rz-column-title");
|
||||
Assert.Equal("MyId", title.TextContent.Trim());
|
||||
Assert.Empty(title.GetAttribute("title"));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
@@ -380,6 +427,44 @@ namespace Radzen.Blazor.Tests
|
||||
Assert.Contains(@$"rz-paginator-bottom", component.Markup);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void DataGrid_Renders_PagerDensityDefault()
|
||||
{
|
||||
using var ctx = new TestContext();
|
||||
ctx.JSInterop.Mode = JSRuntimeMode.Loose;
|
||||
ctx.JSInterop.SetupModule("_content/Radzen.Blazor/Radzen.Blazor.js");
|
||||
|
||||
var component = ctx.RenderComponent<RadzenGrid<int>>(parameterBuilder => parameterBuilder.Add<IEnumerable<int>>(p => p.Data, Enumerable.Range(0, 100)));
|
||||
|
||||
component.SetParametersAndRender(parameters =>
|
||||
{
|
||||
parameters.Add<bool>(p => p.AllowPaging, true);
|
||||
parameters.Add<PagerPosition>(p => p.PagerPosition, PagerPosition.Top);
|
||||
parameters.Add<Density>(p => p.Density, Density.Default);
|
||||
});
|
||||
|
||||
Assert.DoesNotContain(@$"rz-density-compact", component.Markup);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void DataGrid_Renders_PagerDensityCompact()
|
||||
{
|
||||
using var ctx = new TestContext();
|
||||
ctx.JSInterop.Mode = JSRuntimeMode.Loose;
|
||||
ctx.JSInterop.SetupModule("_content/Radzen.Blazor/Radzen.Blazor.js");
|
||||
|
||||
var component = ctx.RenderComponent<RadzenGrid<int>>(parameterBuilder => parameterBuilder.Add<IEnumerable<int>>(p => p.Data, Enumerable.Range(0, 100)));
|
||||
|
||||
component.SetParametersAndRender(parameters =>
|
||||
{
|
||||
parameters.Add<bool>(p => p.AllowPaging, true);
|
||||
parameters.Add<PagerPosition>(p => p.PagerPosition, PagerPosition.Top);
|
||||
parameters.Add<Density>(p => p.Density, Density.Compact);
|
||||
});
|
||||
|
||||
Assert.Contains(@$"rz-density-compact", component.Markup);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void DataGrid_Renders_DefaultEmptyText()
|
||||
{
|
||||
|
||||
@@ -64,6 +64,40 @@ namespace Radzen.Blazor.Tests
|
||||
Assert.Contains(@$"rz-paginator-bottom", component.Markup);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void DataList_Renders_PagerDensityDefault()
|
||||
{
|
||||
using var ctx = new TestContext();
|
||||
|
||||
var component = ctx.RenderComponent<RadzenDataList<int>>(parameterBuilder => parameterBuilder.Add<IEnumerable<int>>(p => p.Data, Enumerable.Range(0, 100)));
|
||||
|
||||
component.SetParametersAndRender(parameters =>
|
||||
{
|
||||
parameters.Add<bool>(p => p.AllowPaging, true);
|
||||
parameters.Add<PagerPosition>(p => p.PagerPosition, PagerPosition.Top);
|
||||
parameters.Add<Density>(p => p.Density, Density.Default);
|
||||
});
|
||||
|
||||
Assert.DoesNotContain(@$"rz-density-compact", component.Markup);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void DataList_Renders_PagerDensityCompact()
|
||||
{
|
||||
using var ctx = new TestContext();
|
||||
|
||||
var component = ctx.RenderComponent<RadzenDataList<int>>(parameterBuilder => parameterBuilder.Add<IEnumerable<int>>(p => p.Data, Enumerable.Range(0, 100)));
|
||||
|
||||
component.SetParametersAndRender(parameters =>
|
||||
{
|
||||
parameters.Add<bool>(p => p.AllowPaging, true);
|
||||
parameters.Add<PagerPosition>(p => p.PagerPosition, PagerPosition.Top);
|
||||
parameters.Add<Density>(p => p.Density, Density.Compact);
|
||||
});
|
||||
|
||||
Assert.Contains(@$"rz-density-compact", component.Markup);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void DataList_Renders_WrapItemsParameter()
|
||||
{
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using Bunit;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using Xunit;
|
||||
|
||||
@@ -48,7 +49,7 @@ namespace Radzen.Blazor.Tests
|
||||
|
||||
var component = ctx.RenderComponent<RadzenDatePicker<DateTime>>();
|
||||
|
||||
component.SetParametersAndRender(parameters => {
|
||||
component.SetParametersAndRender(parameters => {
|
||||
parameters.Add<bool>(p => p.ShowTime, true);
|
||||
parameters.Add<bool>(p => p.ShowSeconds, true);
|
||||
});
|
||||
@@ -92,7 +93,7 @@ namespace Radzen.Blazor.Tests
|
||||
|
||||
component.SetParametersAndRender(parameters => {
|
||||
parameters.Add(p => p.DateFormat, format);
|
||||
parameters.Add<object>(p => p.Value, DateTime.Now);
|
||||
parameters.Add<object>(p => p.Value, DateTime.Now);
|
||||
});
|
||||
|
||||
Assert.Contains(@$"value=""{string.Format("{0:" + format + "}", DateTime.Now)}""", component.Markup);
|
||||
@@ -145,7 +146,7 @@ namespace Radzen.Blazor.Tests
|
||||
|
||||
component.SetParametersAndRender(parameters => {
|
||||
parameters.Add<object>(p => p.Value, DateTime.Now);
|
||||
parameters.Add<bool>(p => p.AllowClear, true);
|
||||
parameters.Add<bool>(p => p.AllowClear, true);
|
||||
});
|
||||
|
||||
Assert.Contains(@$"<i class=""rz-dropdown-clear-icon rzi rzi-times""", component.Markup);
|
||||
@@ -319,12 +320,12 @@ namespace Radzen.Blazor.Tests
|
||||
DateTime previousDay = DateTime.Today.AddDays(-1);
|
||||
|
||||
using var ctx = new TestContext();
|
||||
ctx.JSInterop.Mode = JSRuntimeMode.Loose;
|
||||
ctx.JSInterop.Mode = JSRuntimeMode.Loose;
|
||||
|
||||
var component = ctx.RenderComponent<RadzenDatePicker<DateTime>>();
|
||||
|
||||
|
||||
var raised = false;
|
||||
object newValue = null;
|
||||
object newValue = null;
|
||||
|
||||
component.SetParametersAndRender(parameters => {
|
||||
parameters.Add(p => p.ValueChanged, args => { raised = true; newValue = args; })
|
||||
@@ -377,14 +378,79 @@ namespace Radzen.Blazor.Tests
|
||||
Assert.True(raised);
|
||||
Assert.Null(newValue);
|
||||
}
|
||||
|
||||
|
||||
[Fact]
|
||||
public void DatePicker_Parses_Input_Using_DateFormat()
|
||||
{
|
||||
using var ctx = new TestContext();
|
||||
ctx.JSInterop.Mode = JSRuntimeMode.Loose;
|
||||
|
||||
var component = ctx.RenderComponent<RadzenDatePicker<DateTime?>>();
|
||||
|
||||
var raised = false;
|
||||
object newValue = null;
|
||||
|
||||
component.SetParametersAndRender(parameters =>
|
||||
{
|
||||
parameters.Add(p => p.DateFormat, "ddMM");
|
||||
parameters.Add(p => p.ValueChanged, args => { raised = true; newValue = args; });
|
||||
});
|
||||
|
||||
var inputElement = component.Find(".rz-inputtext");
|
||||
|
||||
string input = "3012";
|
||||
ctx.JSInterop.Setup<string>("Radzen.getInputValue", invocation => true).SetResult(input);
|
||||
inputElement.Change(input);
|
||||
|
||||
Assert.True(raised);
|
||||
Assert.Equal(new DateTime(DateTime.Now.Year, 12, 30), newValue);
|
||||
}
|
||||
|
||||
|
||||
[Fact]
|
||||
public void DatePicker_Parses_Input_Using_ParseInput()
|
||||
{
|
||||
using var ctx = new TestContext();
|
||||
ctx.JSInterop.Mode = JSRuntimeMode.Loose;
|
||||
|
||||
var component = ctx.RenderComponent<RadzenDatePicker<DateTime?>>();
|
||||
|
||||
Func<string, DateTime?> customParseInput = (input) => {
|
||||
if (DateTime.TryParseExact(input, "ddMM", null, DateTimeStyles.None, out var result))
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
return null;
|
||||
};
|
||||
|
||||
var raised = false;
|
||||
object newValue = null;
|
||||
|
||||
component.SetParametersAndRender(parameters =>
|
||||
{
|
||||
parameters.Add(p => p.ParseInput, customParseInput);
|
||||
parameters.Add(p => p.ValueChanged, args => { raised = true; newValue = args; });
|
||||
});
|
||||
|
||||
var inputElement = component.Find(".rz-inputtext");
|
||||
|
||||
string input = "3012";
|
||||
ctx.JSInterop.Setup<string>("Radzen.getInputValue", invocation => true).SetResult(input);
|
||||
inputElement.Change(input);
|
||||
|
||||
Assert.True(raised);
|
||||
Assert.Equal(new DateTime(DateTime.Now.Year, 12, 30), newValue);
|
||||
}
|
||||
|
||||
|
||||
[Fact]
|
||||
public void DatePicker_Respects_DateTimeMaxValue()
|
||||
{
|
||||
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>>(parameters =>
|
||||
{
|
||||
parameters.Add(p => p.Value, DateTime.MaxValue);
|
||||
@@ -397,25 +463,6 @@ namespace Radzen.Blazor.Tests
|
||||
Assert.Null(exception);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void DatePicker_Respects_DateTimeMinValue()
|
||||
{
|
||||
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>>(parameters =>
|
||||
{
|
||||
parameters.Add(p => p.Value, DateTime.MinValue);
|
||||
});
|
||||
|
||||
Assert.Contains(DateTime.MinValue.ToString(component.Instance.DateFormat), component.Markup);
|
||||
|
||||
var exception = Record.Exception(() => component.Find(".rz-datepicker-prev-icon")
|
||||
.Click());
|
||||
Assert.Null(exception);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(DateTimeKind.Local)]
|
||||
[InlineData(DateTimeKind.Unspecified)]
|
||||
@@ -464,5 +511,72 @@ namespace Radzen.Blazor.Tests
|
||||
|
||||
Assert.Contains(actionsTemplate, component.Markup);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void DatePicker_Converts_DateTimeOffSet_FromUtc_ToLocal()
|
||||
{
|
||||
using var ctx = new TestContext();
|
||||
ctx.JSInterop.Mode = JSRuntimeMode.Loose;
|
||||
ctx.JSInterop.SetupModule("_content/Radzen.Blazor/Radzen.Blazor.js");
|
||||
|
||||
var valueUtc = DateTimeOffset.UtcNow;
|
||||
var kind = DateTimeKind.Local;
|
||||
|
||||
var component = ctx.RenderComponent<RadzenDatePicker<DateTimeOffset>>(parameters =>
|
||||
{
|
||||
parameters.Add(p => p.Kind, kind);
|
||||
parameters.Add(p => p.Value, valueUtc);
|
||||
});
|
||||
|
||||
Assert.Equal(kind, (component.Instance.Value as DateTime?)?.Kind);
|
||||
Assert.Equal(valueUtc.LocalDateTime.ToString(CultureInfo.InvariantCulture), (component.Instance.Value as DateTime?)?.ToString(CultureInfo.InvariantCulture));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void DatePicker_Converts_DateTimeOffSet_Local_ToUtc()
|
||||
{
|
||||
using var ctx = new TestContext();
|
||||
ctx.JSInterop.Mode = JSRuntimeMode.Loose;
|
||||
ctx.JSInterop.SetupModule("_content/Radzen.Blazor/Radzen.Blazor.js");
|
||||
|
||||
var valueUtc = DateTimeOffset.Now;
|
||||
var kind = DateTimeKind.Utc;
|
||||
|
||||
var component = ctx.RenderComponent<RadzenDatePicker<DateTimeOffset>>(parameters =>
|
||||
{
|
||||
parameters.Add(p => p.Kind, kind);
|
||||
parameters.Add(p => p.Value, valueUtc);
|
||||
});
|
||||
|
||||
Assert.Equal(kind, (component.Instance.Value as DateTime?)?.Kind);
|
||||
Assert.Equal(valueUtc.UtcDateTime.ToString(CultureInfo.InvariantCulture), (component.Instance.Value as DateTime?)?.ToString(CultureInfo.InvariantCulture));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void DatePicker_Displays_Calender_Icon()
|
||||
{
|
||||
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>>();
|
||||
|
||||
Assert.Contains(@$"rzi-calendar", component.Markup);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void DatePicker_Displays_Schedule_Icon()
|
||||
{
|
||||
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>>(parameters =>
|
||||
{
|
||||
parameters.Add(p => p.TimeOnly, true);
|
||||
});
|
||||
|
||||
Assert.Contains(@$"rzi-time", component.Markup);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
144
Radzen.Blazor.Tests/DropDownTests.cs
Normal file
144
Radzen.Blazor.Tests/DropDownTests.cs
Normal file
@@ -0,0 +1,144 @@
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using Bunit;
|
||||
using Xunit;
|
||||
|
||||
namespace Radzen.Blazor.Tests
|
||||
{
|
||||
public class DropDownTests
|
||||
{
|
||||
class DataItem
|
||||
{
|
||||
public string Text { get; set; }
|
||||
public int Id { get; set; }
|
||||
}
|
||||
|
||||
private static IRenderedComponent<RadzenDropDown<T>> DropDown<T>(TestContext ctx, Action<ComponentParameterCollectionBuilder<RadzenDropDown<T>>> configure = null)
|
||||
{
|
||||
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 => {
|
||||
parameters.Add(p => p.Data, data);
|
||||
parameters.Add(p => p.TextProperty, nameof(DataItem.Text));
|
||||
|
||||
if (configure != null)
|
||||
{
|
||||
configure.Invoke(parameters);
|
||||
}
|
||||
else
|
||||
{
|
||||
parameters.Add(p => p.ValueProperty, nameof(DataItem.Id));
|
||||
}
|
||||
});
|
||||
|
||||
return component;
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Dropdown_SelectItem_Method_Should_Not_Throw()
|
||||
{
|
||||
using var ctx = new TestContext();
|
||||
|
||||
ctx.JSInterop.Mode = JSRuntimeMode.Loose;
|
||||
|
||||
var component = DropDown<int>(ctx);
|
||||
|
||||
var items = component.FindAll(".rz-dropdown-item");
|
||||
|
||||
Assert.Equal(2, items.Count);
|
||||
|
||||
//this throws
|
||||
await component.InvokeAsync(async () => await component.Instance.SelectItem(1));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void DropDown_RendersItems()
|
||||
{
|
||||
using var ctx = new TestContext();
|
||||
|
||||
ctx.JSInterop.Mode = JSRuntimeMode.Loose;
|
||||
|
||||
var component = DropDown<int>(ctx);
|
||||
|
||||
var items = component.FindAll(".rz-dropdown-item");
|
||||
|
||||
Assert.Equal(2, items.Count);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void DropDown_AppliesSelectionStyleForIntValue()
|
||||
{
|
||||
using var ctx = new TestContext();
|
||||
|
||||
ctx.JSInterop.Mode = JSRuntimeMode.Loose;
|
||||
|
||||
var component = DropDown<int>(ctx);
|
||||
|
||||
var items = component.FindAll(".rz-dropdown-item");
|
||||
|
||||
items[0].Click();
|
||||
|
||||
component.Render();
|
||||
|
||||
items = component.FindAll(".rz-dropdown-item");
|
||||
|
||||
Assert.Contains("rz-state-highlight", items[0].ClassList);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void DropDown_AppliesSelectionStyleForStringValue()
|
||||
{
|
||||
using var ctx = new TestContext();
|
||||
|
||||
ctx.JSInterop.Mode = JSRuntimeMode.Loose;
|
||||
|
||||
var component = DropDown<string>(ctx, parameters => {
|
||||
parameters.Add(p => p.ValueProperty, nameof(DataItem.Text));
|
||||
});
|
||||
|
||||
var items = component.FindAll(".rz-dropdown-item");
|
||||
|
||||
items[0].Click();
|
||||
|
||||
component.Render();
|
||||
|
||||
items = component.FindAll(".rz-dropdown-item");
|
||||
|
||||
Assert.Contains("rz-state-highlight", items[0].ClassList);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void DropDown_AppliesSelectionStyleWhenMultipleSelectionIsEnabled()
|
||||
{
|
||||
using var ctx = new TestContext();
|
||||
|
||||
ctx.JSInterop.Mode = JSRuntimeMode.Loose;
|
||||
|
||||
var component = DropDown<string>(ctx, parameters => {
|
||||
parameters.Add(p => p.ValueProperty, nameof(DataItem.Text));
|
||||
parameters.Add(p => p.Multiple, true);
|
||||
});
|
||||
|
||||
var items = component.FindAll(".rz-multiselect-item");
|
||||
|
||||
items[0].Click();
|
||||
|
||||
component.Render();
|
||||
|
||||
items = component.FindAll(".rz-multiselect-item");
|
||||
|
||||
items[1].Click();
|
||||
|
||||
component.Render();
|
||||
|
||||
var selectedItems = component.FindAll(".rz-state-highlight");
|
||||
|
||||
Assert.Equal(2, selectedItems.Count);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -17,7 +17,6 @@ namespace Radzen.Blazor.Tests
|
||||
component.Render();
|
||||
|
||||
Assert.Contains(@$"rz-fieldset", component.Markup);
|
||||
Assert.Contains(@$"rz-fieldset-legend", component.Markup);
|
||||
Assert.Contains(@$"rz-fieldset-content-wrapper", component.Markup);
|
||||
Assert.Contains(@$"rz-fieldset-content", component.Markup);
|
||||
}
|
||||
|
||||
@@ -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(@$"<i class=""rzi d-inline-flex justify-content-center align-items-center""", component.Markup);
|
||||
Assert.Contains(@$"class=""rzi""", component.Markup);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
@@ -58,6 +58,18 @@ namespace Radzen.Blazor.Tests
|
||||
Assert.Contains(@$"rzi-primary", component.Markup);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Icon_Renders_IconColor()
|
||||
{
|
||||
using var ctx = new TestContext();
|
||||
|
||||
var component = ctx.RenderComponent<RadzenIcon>();
|
||||
|
||||
component.SetParametersAndRender(parameters => parameters.Add(icon => icon.IconColor, Colors.Primary));
|
||||
|
||||
Assert.Contains(@$"color:", component.Markup);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Icon_NotRenders_IconStyleClass_WhenNull()
|
||||
{
|
||||
@@ -69,5 +81,17 @@ namespace Radzen.Blazor.Tests
|
||||
|
||||
Assert.DoesNotContain(@$"rzi-primary", component.Markup);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Icon_NotRenders_IconColor_WhenNull()
|
||||
{
|
||||
using var ctx = new TestContext();
|
||||
|
||||
var component = ctx.RenderComponent<RadzenIcon>();
|
||||
|
||||
component.SetParametersAndRender(parameters => parameters.Add(icon => icon.IconColor, null));
|
||||
|
||||
Assert.DoesNotContain(@$"color:", component.Markup);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,8 +30,10 @@ namespace Radzen.Blazor.Tests
|
||||
|
||||
component.SetParametersAndRender(parameters => parameters.Add(p => p.Text, text));
|
||||
|
||||
Assert.Contains(@$">{text}</span>", component.Markup);
|
||||
Assert.Contains(@$"class=""rz-link-text""", component.Markup);
|
||||
var textElement = component.Find(".rz-link-text");
|
||||
|
||||
Assert.NotNull(textElement);
|
||||
Assert.Equal(text, textElement.TextContent.Trim());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
||||
@@ -26,7 +26,12 @@ namespace Radzen.Blazor.Tests
|
||||
|
||||
var component = ctx.RenderComponent<RadzenLogin>();
|
||||
|
||||
Assert.Contains(@$"<label class=""col-sm-3 col-form-label"" for=""username"">Username</label>", component.Markup);
|
||||
component.SetParametersAndRender(p => {
|
||||
p.AddUnmatched("id", "login");
|
||||
});
|
||||
|
||||
var label = component.Find($@"label[for=""login-username""]");
|
||||
Assert.NotNull(label);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
@@ -63,7 +68,7 @@ namespace Radzen.Blazor.Tests
|
||||
component.SetParametersAndRender(parameters => {
|
||||
parameters.Add(p => p.Username, "user");
|
||||
parameters.Add(p => p.Password, "pwd");
|
||||
parameters.Add(p => p.Login, args => { clicked = true; });
|
||||
parameters.Add(p => p.Login, args => { clicked = true; });
|
||||
});
|
||||
|
||||
component.Find("button").Click();
|
||||
@@ -114,7 +119,7 @@ namespace Radzen.Blazor.Tests
|
||||
parameters.Add(p => p.AllowResetPassword, true);
|
||||
});
|
||||
|
||||
Assert.Contains(@$"Forgot password</a>", component.Markup);
|
||||
Assert.Contains(@$"Forgot password?</a>", component.Markup);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
@@ -190,7 +195,7 @@ namespace Radzen.Blazor.Tests
|
||||
parameters.Add(p => p.Register, args => { clicked = true; });
|
||||
});
|
||||
|
||||
component.Find(".register > button").Click();
|
||||
component.Find(".rz-secondary").Click();
|
||||
|
||||
Assert.True(clicked);
|
||||
}
|
||||
|
||||
@@ -128,6 +128,34 @@ namespace Radzen.Blazor.Tests
|
||||
Assert.Contains(@$"autocomplete=""on""", component.Markup);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Mask_Renders_TypedAutoCompleteParameter()
|
||||
{
|
||||
using var ctx = new TestContext();
|
||||
|
||||
var component = ctx.RenderComponent<RadzenMask>();
|
||||
|
||||
component.SetParametersAndRender(parameters => parameters.Add<bool>(p => p.AutoComplete, false));
|
||||
component.SetParametersAndRender(parameters => parameters.Add<AutoCompleteType>(p => p.AutoCompleteType, AutoCompleteType.On));
|
||||
|
||||
Assert.Contains(@$"autocomplete=""off""", component.Markup);
|
||||
|
||||
component.SetParametersAndRender(parameters => parameters.Add<bool>(p => p.AutoComplete, true));
|
||||
component.SetParametersAndRender(parameters => parameters.Add<AutoCompleteType>(p => p.AutoCompleteType, AutoCompleteType.Off));
|
||||
|
||||
Assert.Contains(@$"autocomplete=""off""", component.Markup);
|
||||
|
||||
component.SetParametersAndRender(parameters => parameters.Add<bool>(p => p.AutoComplete, true));
|
||||
component.SetParametersAndRender(parameters => parameters.Add<AutoCompleteType>(p => p.AutoCompleteType, AutoCompleteType.AdditionalName));
|
||||
|
||||
Assert.Contains(@$"autocomplete=""{AutoCompleteType.AdditionalName.GetAutoCompleteValue()}""", component.Markup);
|
||||
|
||||
component.SetParametersAndRender(parameters => parameters.Add<bool>(p => p.AutoComplete, true));
|
||||
component.SetParametersAndRender(parameters => parameters.Add<AutoCompleteType>(p => p.AutoCompleteType, AutoCompleteType.Email));
|
||||
|
||||
Assert.Contains(@$"autocomplete=""{AutoCompleteType.Email.GetAutoCompleteValue()}""", component.Markup);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Mask_Renders_MaxLengthParameter()
|
||||
{
|
||||
|
||||
159
Radzen.Blazor.Tests/NumericRangeValidatorTests.cs
Normal file
159
Radzen.Blazor.Tests/NumericRangeValidatorTests.cs
Normal file
@@ -0,0 +1,159 @@
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using Bunit;
|
||||
using Microsoft.AspNetCore.Components.Forms;
|
||||
using Xunit;
|
||||
|
||||
namespace Radzen.Blazor.Tests
|
||||
{
|
||||
public class NumericRangeValidatorTests
|
||||
{
|
||||
class FormComponentTestDouble : IRadzenFormComponent
|
||||
{
|
||||
public bool IsBound => false;
|
||||
|
||||
public bool HasValue => true;
|
||||
|
||||
public string Name { get; set; }
|
||||
|
||||
public FieldIdentifier FieldIdentifier => throw new System.NotImplementedException();
|
||||
|
||||
public object GetValue()
|
||||
{
|
||||
return Value;
|
||||
}
|
||||
|
||||
public ValueTask FocusAsync()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public object Value { get; set; }
|
||||
}
|
||||
|
||||
class RadzenNumericRangeValidatorTestDouble : RadzenNumericRangeValidator
|
||||
{
|
||||
public bool Validate(object value)
|
||||
{
|
||||
return base.Validate(new FormComponentTestDouble { Value = value });
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Throws_Exception_If_Min_And_Max_Are_Null()
|
||||
{
|
||||
var validator = new RadzenNumericRangeValidatorTestDouble();
|
||||
|
||||
Assert.Throws<System.ArgumentException>(() => validator.Validate(1));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Returns_False_If_Value_Is_Null()
|
||||
{
|
||||
using var ctx = new TestContext();
|
||||
var component = ctx.RenderComponent<RadzenNumericRangeValidatorTestDouble>();
|
||||
|
||||
component.SetParametersAndRender(parameters =>
|
||||
{
|
||||
component.SetParametersAndRender(parameters => parameters.Add(p => p.Min, 0).Add(p => p.Max, 10));
|
||||
});
|
||||
|
||||
Assert.False(component.Instance.Validate(null));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Returns_False_If_Value_Overflows()
|
||||
{
|
||||
using var ctx = new TestContext();
|
||||
var component = ctx.RenderComponent<RadzenNumericRangeValidatorTestDouble>();
|
||||
|
||||
component.SetParametersAndRender(parameters =>
|
||||
{
|
||||
component.SetParametersAndRender(parameters => parameters.Add(p => p.Min, 0).Add(p => p.Max, 10));
|
||||
});
|
||||
|
||||
Assert.False(component.Instance.Validate(long.MaxValue));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Returns_True_If_Value_Is_Greater_Than_Min()
|
||||
{
|
||||
using var ctx = new TestContext();
|
||||
var component = ctx.RenderComponent<RadzenNumericRangeValidatorTestDouble>();
|
||||
component.SetParametersAndRender(parameters => parameters.Add(p => p.Min, 0));
|
||||
|
||||
Assert.True(component.Instance.Validate(1));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Returns_True_If_Value_Is_Equal_To_Min()
|
||||
{
|
||||
using var ctx = new TestContext();
|
||||
var component = ctx.RenderComponent<RadzenNumericRangeValidatorTestDouble>();
|
||||
component.SetParametersAndRender(parameters => parameters.Add(p => p.Min, 0));
|
||||
|
||||
Assert.True(component.Instance.Validate(0));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Returns_True_If_Value_Is_Less_Than_Max()
|
||||
{
|
||||
using var ctx = new TestContext();
|
||||
var component = ctx.RenderComponent<RadzenNumericRangeValidatorTestDouble>();
|
||||
component.SetParametersAndRender(parameters => parameters.Add(p => p.Max, 10));
|
||||
|
||||
Assert.True(component.Instance.Validate(9));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Returns_True_If_Value_Is_Equal_To_Max()
|
||||
{
|
||||
using var ctx = new TestContext();
|
||||
var component = ctx.RenderComponent<RadzenNumericRangeValidatorTestDouble>();
|
||||
component.SetParametersAndRender(parameters => parameters.Add(p => p.Max, 10));
|
||||
|
||||
Assert.True(component.Instance.Validate(10));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Returns_True_If_Value_Is_Between_Min_And_Max()
|
||||
{
|
||||
using var ctx = new TestContext();
|
||||
var component = ctx.RenderComponent<RadzenNumericRangeValidatorTestDouble>();
|
||||
component.SetParametersAndRender(parameters => parameters.Add(p => p.Min, 0).Add(p => p.Max, 10));
|
||||
|
||||
Assert.True(component.Instance.Validate(5));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Returns_True_If_Value_Is_Between_Min_And_Max_And_They_Are_Nullable()
|
||||
{
|
||||
int? min = 0;
|
||||
int? max = 10;
|
||||
using var ctx = new TestContext();
|
||||
var component = ctx.RenderComponent<RadzenNumericRangeValidatorTestDouble>();
|
||||
component.SetParametersAndRender(parameters => parameters.Add(p => p.Min, min).Add(p => p.Max, max));
|
||||
Assert.True(component.Instance.Validate(5));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Returns_True_When_Value_Is_Of_DifferentType()
|
||||
{
|
||||
using var ctx = new TestContext();
|
||||
var component = ctx.RenderComponent<RadzenNumericRangeValidatorTestDouble>();
|
||||
component.SetParametersAndRender(parameters => parameters.Add(p => p.Min, 0m).Add(p => p.Max, 10m));
|
||||
|
||||
Assert.True(component.Instance.Validate(5));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Returns_False_If_Cannot_Conert_Value()
|
||||
{
|
||||
using var ctx = new TestContext();
|
||||
var component = ctx.RenderComponent<RadzenNumericRangeValidatorTestDouble>();
|
||||
component.SetParametersAndRender(parameters => parameters.Add(p => p.Min, 0m).Add(p => p.Max, 10m));
|
||||
|
||||
Assert.False(component.Instance.Validate(DateTime.Now));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -193,6 +193,34 @@ namespace Radzen.Blazor.Tests
|
||||
Assert.Contains(@$"autocomplete=""on""", component.Markup);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Numeric_Renders_TypedAutoCompleteParameter()
|
||||
{
|
||||
using var ctx = new TestContext();
|
||||
|
||||
var component = ctx.RenderComponent<RadzenNumeric<double>>();
|
||||
|
||||
component.SetParametersAndRender(parameters => parameters.Add<bool>(p => p.AutoComplete, false));
|
||||
component.SetParametersAndRender(parameters => parameters.Add<AutoCompleteType>(p => p.AutoCompleteType, AutoCompleteType.On));
|
||||
|
||||
Assert.Contains(@$"autocomplete=""off""", component.Markup);
|
||||
|
||||
component.SetParametersAndRender(parameters => parameters.Add<bool>(p => p.AutoComplete, true));
|
||||
component.SetParametersAndRender(parameters => parameters.Add<AutoCompleteType>(p => p.AutoCompleteType, AutoCompleteType.Off));
|
||||
|
||||
Assert.Contains(@$"autocomplete=""off""", component.Markup);
|
||||
|
||||
component.SetParametersAndRender(parameters => parameters.Add<bool>(p => p.AutoComplete, true));
|
||||
component.SetParametersAndRender(parameters => parameters.Add<AutoCompleteType>(p => p.AutoCompleteType, AutoCompleteType.BdayMonth));
|
||||
|
||||
Assert.Contains(@$"autocomplete=""{AutoCompleteType.BdayMonth.GetAutoCompleteValue()}""", component.Markup);
|
||||
|
||||
component.SetParametersAndRender(parameters => parameters.Add<bool>(p => p.AutoComplete, true));
|
||||
component.SetParametersAndRender(parameters => parameters.Add<AutoCompleteType>(p => p.AutoCompleteType, AutoCompleteType.BdayYear));
|
||||
|
||||
Assert.Contains(@$"autocomplete=""{AutoCompleteType.BdayYear.GetAutoCompleteValue()}""", component.Markup);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Numeric_Raises_ChangedEvent()
|
||||
{
|
||||
|
||||
@@ -76,5 +76,38 @@ namespace Radzen.Blazor.Tests
|
||||
Assert.DoesNotContain(@$"rz-paginator-summary", component.Markup);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void RadzenPager_Renders_PagerDensityDefault()
|
||||
{
|
||||
using var ctx = new TestContext();
|
||||
ctx.JSInterop.Mode = JSRuntimeMode.Loose;
|
||||
ctx.JSInterop.SetupModule("_content/Radzen.Blazor/Radzen.Blazor.js");
|
||||
|
||||
var component = ctx.RenderComponent<RadzenPager>(parameters =>
|
||||
{
|
||||
parameters.Add<int>(p => p.PageSize, 20);
|
||||
parameters.Add<int>(p => p.Count, 100);
|
||||
parameters.Add<Density>(p => p.Density, Density.Default);
|
||||
});
|
||||
|
||||
Assert.DoesNotContain(@$"rz-density-compact", component.Markup);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void RadzenPager_Renders_PagerDensityCompact()
|
||||
{
|
||||
using var ctx = new TestContext();
|
||||
ctx.JSInterop.Mode = JSRuntimeMode.Loose;
|
||||
ctx.JSInterop.SetupModule("_content/Radzen.Blazor/Radzen.Blazor.js");
|
||||
|
||||
var component = ctx.RenderComponent<RadzenPager>(parameters =>
|
||||
{
|
||||
parameters.Add<int>(p => p.PageSize, 20);
|
||||
parameters.Add<int>(p => p.Count, 100);
|
||||
parameters.Add<Density>(p => p.Density, Density.Compact);
|
||||
});
|
||||
|
||||
Assert.Contains(@$"rz-density-compact", component.Markup);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -128,6 +128,34 @@ namespace Radzen.Blazor.Tests
|
||||
Assert.Contains(@$"autocomplete=""on""", component.Markup);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Password_Renders_TypedAutoCompleteParameter()
|
||||
{
|
||||
using var ctx = new TestContext();
|
||||
|
||||
var component = ctx.RenderComponent<RadzenPassword>();
|
||||
|
||||
component.SetParametersAndRender(parameters => parameters.Add<bool>(p => p.AutoComplete, false));
|
||||
component.SetParametersAndRender(parameters => parameters.Add<AutoCompleteType>(p => p.AutoCompleteType, AutoCompleteType.On));
|
||||
|
||||
Assert.Contains(@$"autocomplete=""new-password""", component.Markup);
|
||||
|
||||
component.SetParametersAndRender(parameters => parameters.Add<bool>(p => p.AutoComplete, true));
|
||||
component.SetParametersAndRender(parameters => parameters.Add<AutoCompleteType>(p => p.AutoCompleteType, AutoCompleteType.Off));
|
||||
|
||||
Assert.Contains(@$"autocomplete=""off""", component.Markup);
|
||||
|
||||
component.SetParametersAndRender(parameters => parameters.Add<bool>(p => p.AutoComplete, true));
|
||||
component.SetParametersAndRender(parameters => parameters.Add<AutoCompleteType>(p => p.AutoCompleteType, AutoCompleteType.CurrentPassword));
|
||||
|
||||
Assert.Contains(@$"autocomplete=""{AutoCompleteType.CurrentPassword.GetAutoCompleteValue()}""", component.Markup);
|
||||
|
||||
component.SetParametersAndRender(parameters => parameters.Add<bool>(p => p.AutoComplete, true));
|
||||
component.SetParametersAndRender(parameters => parameters.Add<AutoCompleteType>(p => p.AutoCompleteType, AutoCompleteType.NewPassword));
|
||||
|
||||
Assert.Contains(@$"autocomplete=""{AutoCompleteType.NewPassword.GetAutoCompleteValue()}""", component.Markup);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Password_Renders_UnmatchedParameter()
|
||||
{
|
||||
|
||||
@@ -18,7 +18,9 @@ namespace Radzen.Blazor.Tests
|
||||
|
||||
component.SetParametersAndRender(parameters => parameters.Add<double>(p => p.Value, value));
|
||||
|
||||
Assert.Contains(@$"<div class=""rz-progressbar-label"">{value}", component.Markup);
|
||||
|
||||
Assert.Contains(@$"<div class=""rz-progressbar-label"">", component.Markup);
|
||||
Assert.Contains(@$"{value}%", component.Markup);
|
||||
Assert.Contains(@$"aria-valuenow=""{value}""", component.Markup);
|
||||
Assert.Contains(@$"aria-valuemin=""0""", component.Markup);
|
||||
}
|
||||
@@ -50,13 +52,13 @@ namespace Radzen.Blazor.Tests
|
||||
|
||||
component.Render();
|
||||
|
||||
Assert.Contains(@$"%</div>", component.Markup);
|
||||
Assert.Contains(@$"0%", component.Markup);
|
||||
|
||||
var value = "mm";
|
||||
var unit = "mm";
|
||||
|
||||
component.SetParametersAndRender(parameters => parameters.Add(p => p.Unit, value));
|
||||
component.SetParametersAndRender(parameters => parameters.Add(p => p.Unit, unit));
|
||||
|
||||
Assert.Contains(@$"{value}</div>", component.Markup);
|
||||
Assert.Contains(@$"0{unit}", component.Markup);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
@@ -118,5 +120,27 @@ namespace Radzen.Blazor.Tests
|
||||
|
||||
Assert.Contains(@$"style=""width: {Math.Min(value / max * 100, 100).ToInvariantString()}%;""", component.Markup);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ProgressBar_Renders_ProgressBarStyle()
|
||||
{
|
||||
using var ctx = new TestContext();
|
||||
|
||||
var component = ctx.RenderComponent<RadzenProgressBar>();
|
||||
|
||||
component.SetParametersAndRender(parameters=>parameters.Add(p=>p.ProgressBarStyle, ProgressBarStyle.Success));
|
||||
Assert.Contains(@$"rz-progressbar-success", component.Markup);
|
||||
|
||||
component.SetParametersAndRender(parameters => parameters.Add(p => p.ProgressBarStyle, ProgressBarStyle.Info));
|
||||
Assert.Contains(@$"rz-progressbar-info", component.Markup);
|
||||
|
||||
component.SetParametersAndRender(parameters => parameters.Add(p => p.ProgressBarStyle, ProgressBarStyle.Success));
|
||||
component.SetParametersAndRender(parameters => parameters.Add(p => p.Mode, ProgressBarMode.Indeterminate));
|
||||
Assert.Contains(@$"rz-progressbar-success", component.Markup);
|
||||
|
||||
component.SetParametersAndRender(parameters => parameters.Add(p => p.ProgressBarStyle, ProgressBarStyle.Info));
|
||||
component.SetParametersAndRender(parameters => parameters.Add(p => p.Mode, ProgressBarMode.Indeterminate));
|
||||
Assert.Contains(@$"rz-progressbar-info", component.Markup);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
120
Radzen.Blazor.Tests/PropertyAccessTests.cs
Normal file
120
Radzen.Blazor.Tests/PropertyAccessTests.cs
Normal file
@@ -0,0 +1,120 @@
|
||||
using AngleSharp.Css;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Linq.Dynamic.Core;
|
||||
using Xunit;
|
||||
|
||||
namespace Radzen.Blazor.Tests
|
||||
{
|
||||
public class PropertyAccessTests
|
||||
{
|
||||
public partial class TestData
|
||||
{
|
||||
public string PROPERTY { get; set; }
|
||||
public string Property { get; set; }
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Getter_With_DifferentTargetType()
|
||||
{
|
||||
var o = new TestData { Property = "test" };
|
||||
var getter = PropertyAccess.Getter<object, object>(nameof(TestData.Property), typeof(TestData));
|
||||
var value = getter(o);
|
||||
Assert.Equal(o.Property, value);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Getter_With_Members_That_Differ_Only_In_Casing()
|
||||
{
|
||||
var o = new TestData { PROPERTY = nameof(TestData.PROPERTY), Property = nameof(TestData.Property) };
|
||||
var getter = PropertyAccess.Getter<TestData, string>(nameof(TestData.PROPERTY));
|
||||
var value = getter(o);
|
||||
Assert.Equal(nameof(TestData.PROPERTY), value);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Getter_Resolves_Property_On_Simple_Object()
|
||||
{
|
||||
var o = new SimpleObject() { Prop1 = "TestString" };
|
||||
var getter = PropertyAccess.Getter<SimpleObject, string>("Prop1");
|
||||
var value = getter(o);
|
||||
Assert.Equal("TestString", value);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Getter_Resolves_Property_On_Simple_Object_QueryableType()
|
||||
{
|
||||
var _data = new List<SimpleObject>()
|
||||
{
|
||||
new SimpleObject() { Prop1 = "TestString" },
|
||||
};
|
||||
|
||||
Func<object, object> getter = PropertyAccess.Getter<object, object>("Prop1", typeof(SimpleObject));
|
||||
|
||||
var value = getter(_data[0]);
|
||||
Assert.Equal("TestString", value);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Getter_Resolves_Property_On_Nested_Object()
|
||||
{
|
||||
var o = new NestedObject() { Obj = new SimpleObject { Prop1 = "TestString" } };
|
||||
var getter = PropertyAccess.Getter<NestedObject, string>("Obj.Prop1");
|
||||
var value = getter(o);
|
||||
Assert.Equal("TestString", value);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Getter_Resolves_Property_From_Array()
|
||||
{
|
||||
var o = new ArrayObject() { Values = new string[] { "1", "2", "3" } };
|
||||
var getter = PropertyAccess.Getter<ArrayObject, string>("Values[1]");
|
||||
var value = getter(o);
|
||||
Assert.Equal("2", value);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Getter_Resolves_Property_From_Nested_Array()
|
||||
{
|
||||
var o = new NestedArrayObject() { Obj = new ArrayObject() { Values = new string[] { "1", "2", "3" } } };
|
||||
var getter = PropertyAccess.Getter<NestedArrayObject, string>("Obj.Values[2]");
|
||||
var value = getter(o);
|
||||
Assert.Equal("3", value);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Getter_Resolves_Property_From_List()
|
||||
{
|
||||
var o = new ListObject() { Values = new List<string>() { "1", "2", "3" } };
|
||||
var getter = PropertyAccess.Getter<ListObject, string>("Values[1]");
|
||||
var value = getter(o);
|
||||
Assert.Equal("2", value);
|
||||
}
|
||||
|
||||
public class SimpleObject
|
||||
{
|
||||
public string Prop1 { get; set; }
|
||||
}
|
||||
|
||||
public class NestedObject
|
||||
{
|
||||
public SimpleObject Obj { get; set; }
|
||||
}
|
||||
|
||||
public class ArrayObject
|
||||
{
|
||||
public string[] Values { get; set; }
|
||||
}
|
||||
|
||||
public class NestedArrayObject
|
||||
{
|
||||
public ArrayObject Obj { get; set; }
|
||||
}
|
||||
|
||||
public class ListObject
|
||||
{
|
||||
public List<string> Values { get; set; }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net6</TargetFramework>
|
||||
<TargetFramework>net7</TargetFramework>
|
||||
|
||||
<IsPackable>false</IsPackable>
|
||||
</PropertyGroup>
|
||||
|
||||
25
Radzen.Blazor.Tests/Rendering/StepGeneratorTests.cs
Normal file
25
Radzen.Blazor.Tests/Rendering/StepGeneratorTests.cs
Normal file
@@ -0,0 +1,25 @@
|
||||
using System.Collections.Generic;
|
||||
using Radzen.Blazor.Rendering;
|
||||
using Xunit;
|
||||
|
||||
namespace Radzen.Blazor.Tests.Rendering;
|
||||
|
||||
public class StepGeneratorTests
|
||||
{
|
||||
[Fact]
|
||||
public void Renders_Path_Correctly()
|
||||
{
|
||||
var data = new List<Point>
|
||||
{
|
||||
new() { X = 10, Y = 10 },
|
||||
new() { X = 20, Y = 15 },
|
||||
new() { X = 30, Y = 20 },
|
||||
new() { X = 40, Y = 25 },
|
||||
new() { X = 50, Y = 50 }
|
||||
};
|
||||
|
||||
var path = new StepGenerator().Path(data);
|
||||
|
||||
Assert.Equal("10 10 H 20 V 15 H 30 V 20 H 40 V 25 H 50 V 50", path);
|
||||
}
|
||||
}
|
||||
197
Radzen.Blazor.Tests/SpeechToTextButtonTests.cs
Normal file
197
Radzen.Blazor.Tests/SpeechToTextButtonTests.cs
Normal file
@@ -0,0 +1,197 @@
|
||||
using Bunit;
|
||||
using Xunit;
|
||||
|
||||
namespace Radzen.Blazor.Tests
|
||||
{
|
||||
public class SpeechToTextButtonTests
|
||||
{
|
||||
[Fact]
|
||||
public void SpeechToTextButton_Renders_Record_Button_When_Visible()
|
||||
{
|
||||
using var ctx = new TestContext();
|
||||
|
||||
var component = ctx.RenderComponent<RadzenSpeechToTextButton>();
|
||||
|
||||
component.Render();
|
||||
|
||||
var recordButton = component.Find("button.rz-button-icon-only.rz-speech-to-text-button");
|
||||
|
||||
Assert.NotNull(recordButton);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SpeechToTextButton_Does_Not_Renders_Record_Button_When_Visible_False()
|
||||
{
|
||||
using var ctx = new TestContext();
|
||||
|
||||
var component = ctx.RenderComponent<RadzenSpeechToTextButton>();
|
||||
|
||||
component.SetParametersAndRender(parameters =>
|
||||
{
|
||||
parameters.Add(p => p.Visible, false);
|
||||
});
|
||||
|
||||
Assert.Throws<ElementNotFoundException>(() => component.Find("button.rz-button-icon-only.rz-speech-to-text-button"));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SpeechToTextButton_Renders_Additional_Css()
|
||||
{
|
||||
using var ctx = new TestContext();
|
||||
|
||||
var component =
|
||||
ctx.RenderComponent<RadzenSpeechToTextButton>(ComponentParameter.CreateParameter("class", "another-class"));
|
||||
|
||||
var recordButton = component.Find("button.rz-button-icon-only.rz-speech-to-text-button.another-class");
|
||||
|
||||
Assert.NotNull(recordButton);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SpeechToTextButton_Can_Override_Default_Title_And_Aria_Label()
|
||||
{
|
||||
using var ctx = new TestContext();
|
||||
|
||||
var component =
|
||||
ctx.RenderComponent<RadzenSpeechToTextButton>(
|
||||
ComponentParameter.CreateParameter("title", "title override"),
|
||||
ComponentParameter.CreateParameter("aria-label", "aria-label override"));
|
||||
|
||||
var recordButton = component.Find("button.rz-button-icon-only.rz-speech-to-text-button");
|
||||
|
||||
Assert.NotNull(recordButton);
|
||||
Assert.Equal("title override", recordButton.GetAttribute("title"));
|
||||
Assert.Equal("aria-label override", recordButton.GetAttribute("aria-label"));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SpeechToTextButton_Sets_Record_Button_Css_When_Record_Button_Clicked()
|
||||
{
|
||||
using var ctx = new TestContext();
|
||||
|
||||
var component = ctx.RenderComponent<RadzenSpeechToTextButton>();
|
||||
|
||||
ctx.JSInterop.Mode = JSRuntimeMode.Loose;
|
||||
|
||||
component.Render();
|
||||
|
||||
var recordButton = component.Find("button.rz-button-icon-only.rz-speech-to-text-button");
|
||||
|
||||
Assert.NotNull(recordButton);
|
||||
|
||||
recordButton.Click();
|
||||
|
||||
component.Render();
|
||||
|
||||
var blinkingRecordButton = component.Find("button.rz-button-icon-only.rz-speech-to-text-button-recording");
|
||||
|
||||
Assert.NotNull(blinkingRecordButton);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SpeechToTextButton_Sets_StopTitle_When_Record_Button_Clicked()
|
||||
{
|
||||
using var ctx = new TestContext();
|
||||
|
||||
var component = ctx.RenderComponent<RadzenSpeechToTextButton>();
|
||||
|
||||
ctx.JSInterop.Mode = JSRuntimeMode.Loose;
|
||||
|
||||
component.Render();
|
||||
|
||||
var recordButton = component.Find("button.rz-button-icon-only.rz-speech-to-text-button");
|
||||
|
||||
Assert.NotNull(recordButton);
|
||||
|
||||
recordButton.Click();
|
||||
|
||||
component.Render();
|
||||
|
||||
var blinkingRecordButton = component.Find("button.rz-button-icon-only.rz-speech-to-text-button-recording");
|
||||
|
||||
Assert.Equal(component.Instance.StopTitle, blinkingRecordButton.GetAttribute("title"));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SpeechToTextButton_ChangesIconWhen_When_Record_Button_Clicked()
|
||||
{
|
||||
using var ctx = new TestContext();
|
||||
|
||||
var component = ctx.RenderComponent<RadzenSpeechToTextButton>();
|
||||
|
||||
ctx.JSInterop.Mode = JSRuntimeMode.Loose;
|
||||
|
||||
component.Render();
|
||||
|
||||
var recordButton = component.Find("button.rz-button-icon-only.rz-speech-to-text-button");
|
||||
|
||||
Assert.NotNull(recordButton);
|
||||
|
||||
recordButton.Click();
|
||||
|
||||
component.Render();
|
||||
|
||||
var blinkingRecordButton = component.Find("button span");
|
||||
|
||||
Assert.Contains("stop", blinkingRecordButton.TextContent);
|
||||
Assert.DoesNotContain("mic", blinkingRecordButton.TextContent);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SpeechToTextButton_UnSets_Record_Button_Css_When_Record_Button_Clicked_Twice()
|
||||
{
|
||||
using var ctx = new TestContext();
|
||||
|
||||
var component = ctx.RenderComponent<RadzenSpeechToTextButton>();
|
||||
|
||||
ctx.JSInterop.Mode = JSRuntimeMode.Loose;
|
||||
|
||||
component.Render();
|
||||
|
||||
var recordButton = component.Find("button.rz-button-icon-only.rz-speech-to-text-button");
|
||||
|
||||
Assert.NotNull(recordButton);
|
||||
|
||||
recordButton.Click();
|
||||
|
||||
component.Render();
|
||||
|
||||
const string blinkingRecordButtonSelector = "button.rz-button-icon-only.rz-speech-to-text-button-recording";
|
||||
var blinkingRecordButton = component.Find(blinkingRecordButtonSelector);
|
||||
|
||||
Assert.NotNull(blinkingRecordButton);
|
||||
|
||||
blinkingRecordButton.Click();
|
||||
|
||||
component.Render();
|
||||
|
||||
Assert.Throws<ElementNotFoundException>(() => component.Find(blinkingRecordButtonSelector));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SpeechToTextButton_Invokes_OnResult_FromJs()
|
||||
{
|
||||
using var ctx = new TestContext();
|
||||
|
||||
ctx.JSInterop.Mode = JSRuntimeMode.Loose;
|
||||
|
||||
var component = ctx.RenderComponent<RadzenSpeechToTextButton>();
|
||||
|
||||
string resultsFromJs = null;
|
||||
|
||||
component.SetParametersAndRender(parameters => parameters.Add(p => p.Change, r => resultsFromJs = r));
|
||||
|
||||
var recordButton = component.Find("button.rz-button-icon-only.rz-speech-to-text-button");
|
||||
|
||||
Assert.NotNull(recordButton);
|
||||
|
||||
recordButton.Click();
|
||||
|
||||
const string speechResults = "results from js";
|
||||
|
||||
component.InvokeAsync(() => component.Instance.OnResult(speechResults));
|
||||
|
||||
Assert.Equal(speechResults, resultsFromJs);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -127,6 +127,8 @@ namespace Radzen.Blazor.Tests
|
||||
public void SplitButton_Raises_ClickEvent()
|
||||
{
|
||||
using var ctx = new TestContext();
|
||||
ctx.JSInterop.Mode = JSRuntimeMode.Loose;
|
||||
ctx.JSInterop.SetupModule("_content/Radzen.Blazor/Radzen.Blazor.js");
|
||||
|
||||
var component = ctx.RenderComponent<RadzenSplitButton>();
|
||||
|
||||
|
||||
@@ -128,6 +128,34 @@ namespace Radzen.Blazor.Tests
|
||||
Assert.Contains(@$"autocomplete=""on""", component.Markup);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void TextBox_Renders_TypedAutoCompleteParameter()
|
||||
{
|
||||
using var ctx = new TestContext();
|
||||
|
||||
var component = ctx.RenderComponent<RadzenTextBox>();
|
||||
|
||||
component.SetParametersAndRender(parameters => parameters.Add<bool>(p => p.AutoComplete, false));
|
||||
component.SetParametersAndRender(parameters => parameters.Add<AutoCompleteType>(p => p.AutoCompleteType, AutoCompleteType.On));
|
||||
|
||||
Assert.Contains(@$"autocomplete=""off""", component.Markup);
|
||||
|
||||
component.SetParametersAndRender(parameters => parameters.Add<bool>(p => p.AutoComplete, true));
|
||||
component.SetParametersAndRender(parameters => parameters.Add<AutoCompleteType>(p => p.AutoCompleteType, AutoCompleteType.Off));
|
||||
|
||||
Assert.Contains(@$"autocomplete=""off""", component.Markup);
|
||||
|
||||
component.SetParametersAndRender(parameters => parameters.Add<bool>(p => p.AutoComplete, true));
|
||||
component.SetParametersAndRender(parameters => parameters.Add<AutoCompleteType>(p => p.AutoCompleteType, AutoCompleteType.AdditionalName));
|
||||
|
||||
Assert.Contains(@$"autocomplete=""{AutoCompleteType.AdditionalName.GetAutoCompleteValue()}""", component.Markup);
|
||||
|
||||
component.SetParametersAndRender(parameters => parameters.Add<bool>(p => p.AutoComplete, true));
|
||||
component.SetParametersAndRender(parameters => parameters.Add<AutoCompleteType>(p => p.AutoCompleteType, AutoCompleteType.FamilyName));
|
||||
|
||||
Assert.Contains(@$"autocomplete=""{AutoCompleteType.FamilyName.GetAutoCompleteValue()}""", component.Markup);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void TextBox_Renders_MaxLengthParameter()
|
||||
{
|
||||
|
||||
138
Radzen.Blazor/AutoCompleteType.cs
Normal file
138
Radzen.Blazor/AutoCompleteType.cs
Normal file
@@ -0,0 +1,138 @@
|
||||
namespace Radzen.Blazor
|
||||
{
|
||||
/// <summary>
|
||||
/// The <c>AutomCompleteType</c> is a string-associated enum of
|
||||
/// browser-supported autocomplete attribute values.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This class lists the autocomplete attirbute options allowing
|
||||
/// developers to provide the browser with guidance on how to pre-populate
|
||||
/// the form fields. It is a class rather than a simpler enum to associate
|
||||
/// each option with the string the browser expects. For more information
|
||||
/// please review the list of options (https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes/autocomplete)
|
||||
/// and the spec (https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#autofill).
|
||||
/// </remarks>
|
||||
public enum AutoCompleteType
|
||||
{
|
||||
/// <summary>Autocomplete is disabled. </summary>
|
||||
Off,
|
||||
/// <summary>Autocomplete is enabled. The browser chooses what values to suggest. </summary>
|
||||
On,
|
||||
/// <summary>The field expects the value to be a person's full name.</summary>
|
||||
Name,
|
||||
/// <summary>The prefix or title, such as "Mrs.", "Mr.", "Miss", "Ms.", "Dr." etc.</summary>
|
||||
HonorificPrefix,
|
||||
/// <summary>The given (or "first") name.</summary>
|
||||
GivenName,
|
||||
/// <summary>The middle name.</summary>
|
||||
AdditionalName,
|
||||
/// <summary>The family (or "last") name.</summary>
|
||||
FamilyName,
|
||||
/// <summary>The suffix, such as "Jr.", "B.Sc.", "PhD.", "MBASW", etc.</summary>
|
||||
HonorificSuffix,
|
||||
/// <summary>The nickname or handle.</summary>
|
||||
Nickname,
|
||||
/// <summary>The email address.</summary>
|
||||
Email,
|
||||
/// <summary>The username or account name.</summary>
|
||||
Username,
|
||||
/// <summary>A new password. When creating a new account or changing passwords.</summary>
|
||||
NewPassword,
|
||||
/// <summary>A current password. When filling in an existing password.</summary>
|
||||
CurrentPassword,
|
||||
/// <summary>A one-time code used for verifying user identity.</summary>
|
||||
OneTimeCode,
|
||||
/// <summary>A job title, or the title a person has within an organization, such as "Senior Technical Writer", "President", or "Assistant Troop Leader".</summary>
|
||||
OrganizationTitle,
|
||||
/// <summary>A company, business, or organization name.</summary>
|
||||
Organization,
|
||||
/// <summary>A street address. Use multiple address lines when more space is needed.</summary>
|
||||
StreetAddress,
|
||||
/// <summary>The line 1 of a street address. For example, "1234 Main Street".</summary>
|
||||
AddressLine1,
|
||||
/// <summary>The line 2 of a street address. For example, "Apartment 123".</summary>
|
||||
AddressLine2,
|
||||
/// <summary>The line 3 of a street address. For example, "c/o Jane Doe".</summary>
|
||||
AddressLine3,
|
||||
/// <summary>The city or locality.</summary>
|
||||
AddressLevel1,
|
||||
/// <summary>The state, province, prefecture, or region.</summary>
|
||||
AddressLevel2,
|
||||
/// <summary>The zip code or postal code.</summary>
|
||||
AddressLevel3,
|
||||
/// <summary>The country name.</summary>
|
||||
AddressLevel4,
|
||||
/// <summary>The country code.</summary>
|
||||
Country,
|
||||
/// <summary>The country name.</summary>
|
||||
CountryName,
|
||||
/// <summary>The postal code.</summary>
|
||||
PostalCode,
|
||||
/// <summary>The full name as printed on or associated with a payment instrument such as a credit card.</summary>
|
||||
CcName,
|
||||
/// <summary>The given (or "first") name as printed on or associated with a payment instrument such as a credit card.</summary>
|
||||
CcGivenName,
|
||||
/// <summary>The middle name as printed on or associated with a payment instrument such as a credit card.</summary>
|
||||
CcAdditionalName,
|
||||
/// <summary>The family (or "last") name as printed on or associated with a payment instrument such as a credit card.</summary>
|
||||
CcFamilyName,
|
||||
/// <summary>A credit card number or other number identifying a payment method, such as an account number.</summary>
|
||||
CcNumber,
|
||||
/// <summary>A payment method expiration date, typically in the form "MM/YY" or "MM/YYYY".</summary>
|
||||
CcExp,
|
||||
/// <summary>A payment method expiration month, typically in numeric form (MM).</summary>
|
||||
CcExpMonth,
|
||||
/// <summary>A payment method expiration year, typically in numeric form (YYYY).</summary>
|
||||
CcExpYear,
|
||||
/// <summary>The security code for your payment method, such as the CVV code.</summary>
|
||||
CcCsc,
|
||||
/// <summary>The type of payment instrument, such as "Visa", "Master Card", "Checking", or "Savings".</summary>
|
||||
CcType,
|
||||
/// <summary>The currency in which the transaction was completed. Use the ISO 4217 currency codes, such as "USD" for the US dollar.</summary>
|
||||
TransactionCurrency,
|
||||
/// <summary>The amount, in the currency specified by the transaction currency attribute, of the transaction completed.</summary>
|
||||
TransactionAmount,
|
||||
/// <summary>The language in which the transaction was completed. Use the relevant BCP 47 language tag.</summary>
|
||||
Language,
|
||||
/// <summary>A birth date, as a full date.</summary>
|
||||
Bday,
|
||||
/// <summary>The day of the month of a birth date.</summary>
|
||||
BdayDay,
|
||||
/// <summary>The month of the year of a birth date.</summary>
|
||||
BdayMonth,
|
||||
/// <summary>The year of a birth date.</summary>
|
||||
BdayYear,
|
||||
/// <summary>A gender identity (such as "Female", "Fa'afafine", "Hijra", "Male", "Nonbinary"), as freeform text without newlines.</summary>
|
||||
Sex,
|
||||
/// <summary>A full telephone number, including the country code. </summary>
|
||||
Tel,
|
||||
/// <summary>A country code, such as "1" for the United States, Canada, and other areas in North America and parts of the Caribbean.</summary>
|
||||
TelCountryCode,
|
||||
/// <summary>The entire phone number without the country code component, including a country-internal prefix.</summary>
|
||||
TelNational,
|
||||
/// <summary>The area code, with any country-internal prefix applied if appropriate.</summary>
|
||||
TelAreaCode,
|
||||
/// <summary>The phone number without the country or area code.</summary>
|
||||
TelLocal,
|
||||
/// <summary>The extension number, if applicable.</summary>
|
||||
TelExtension,
|
||||
/// <summary>A URL for an instant messaging protocol endpoint, such as "xmpp:username@example.net".</summary>
|
||||
Impp,
|
||||
/// <summary>A URL, such as a home page or company website address as appropriate given the context of the other fields in the form.</summary>
|
||||
Url,
|
||||
/// <summary>The URL of an image representing the person, company, or contact information given in the other fields in the form.</summary>
|
||||
Photo,
|
||||
/// <summary>State.</summary>
|
||||
State,
|
||||
/// <summary>Province.</summary>
|
||||
Province,
|
||||
/// <summary>Zip code.</summary>
|
||||
ZipCode,
|
||||
/// <summary>Firs name.</summary>
|
||||
FirstName,
|
||||
/// <summary>Middle name.</summary>
|
||||
MiddleName,
|
||||
/// <summary>Last name.</summary>
|
||||
LastName,
|
||||
}
|
||||
}
|
||||
@@ -67,7 +67,13 @@ namespace Radzen.Blazor
|
||||
/// <value>The ticks.</value>
|
||||
public RadzenTicks Ticks { get; set; } = new RadzenTicks();
|
||||
|
||||
internal int TickDistance { get; set; } = 100;
|
||||
/// <summary>
|
||||
/// Gets or sets the pixel distance between axis ticks. It is used to calculate the number of visible ticks depending on the available space. Set to 100 by default;
|
||||
/// Setting <see cref="Step" /> will override this value.
|
||||
/// </summary>
|
||||
/// <value>The desired pixel distance between ticks.</value>
|
||||
[Parameter]
|
||||
public int TickDistance { get; set; } = 100;
|
||||
|
||||
/// <summary>
|
||||
/// Specifies the minimum value of the axis.
|
||||
|
||||
@@ -5,6 +5,8 @@ using System.Linq;
|
||||
using System.Linq.Dynamic.Core;
|
||||
using Radzen.Blazor.Rendering;
|
||||
using System.Threading.Tasks;
|
||||
using System.Collections;
|
||||
using Microsoft.AspNetCore.Components.Rendering;
|
||||
|
||||
namespace Radzen.Blazor
|
||||
{
|
||||
@@ -14,22 +16,34 @@ namespace Radzen.Blazor
|
||||
/// <typeparam name="TItem">The type of the series data.</typeparam>
|
||||
public abstract class CartesianSeries<TItem> : RadzenChartComponentBase, IChartSeries, IDisposable
|
||||
{
|
||||
/// <summary>
|
||||
/// Cache for the value returned by <see cref="Category"/> when that value is only dependent on
|
||||
/// <see cref="CategoryProperty"/>.
|
||||
/// </summary>
|
||||
Func<TItem, double> categoryPropertyCache;
|
||||
|
||||
/// <summary>
|
||||
/// Creates a getter function that returns a value from the specified category scale for the specified data item.
|
||||
/// </summary>
|
||||
/// <param name="scale">The scale.</param>
|
||||
protected Func<TItem, double> Category(ScaleBase scale)
|
||||
internal Func<TItem, double> Category(ScaleBase scale)
|
||||
{
|
||||
if (categoryPropertyCache != null)
|
||||
{
|
||||
return categoryPropertyCache;
|
||||
}
|
||||
|
||||
if (IsNumeric(CategoryProperty))
|
||||
{
|
||||
return PropertyAccess.Getter<TItem, double>(CategoryProperty);
|
||||
categoryPropertyCache = PropertyAccess.Getter<TItem, double>(CategoryProperty);
|
||||
return categoryPropertyCache;
|
||||
}
|
||||
|
||||
if (IsDate(CategoryProperty))
|
||||
{
|
||||
var category = PropertyAccess.Getter<TItem, DateTime>(CategoryProperty);
|
||||
|
||||
return (item) => category(item).Ticks;
|
||||
categoryPropertyCache = (item) => category(item).Ticks;
|
||||
return categoryPropertyCache;
|
||||
}
|
||||
|
||||
if (scale is OrdinalScale ordinal)
|
||||
@@ -122,6 +136,18 @@ namespace Radzen.Blazor
|
||||
[Parameter]
|
||||
public RenderFragment<TItem> TooltipTemplate { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the list of overlays.
|
||||
/// </summary>
|
||||
/// <value>The Overlays list.</value>
|
||||
public IList<IChartSeriesOverlay> Overlays { get; } = new List<IChartSeriesOverlay>();
|
||||
|
||||
/// <summary>
|
||||
/// Gets the coordinate system of the series.
|
||||
/// </summary>
|
||||
/// <value>Coordinate system enum value.</value>
|
||||
public virtual CoordinateSystem CoordinateSystem => CoordinateSystem.Cartesian;
|
||||
|
||||
/// <summary>
|
||||
/// The name of the property of <typeparamref name="TItem" /> that provides the X axis (a.k.a. category axis) values.
|
||||
/// </summary>
|
||||
@@ -174,7 +200,7 @@ namespace Radzen.Blazor
|
||||
/// </summary>
|
||||
/// <value>The value.</value>
|
||||
/// <exception cref="ArgumentException">ValueProperty should not be empty</exception>
|
||||
protected Func<TItem, double> Value
|
||||
internal Func<TItem, double> Value
|
||||
{
|
||||
get
|
||||
{
|
||||
@@ -264,7 +290,7 @@ namespace Radzen.Blazor
|
||||
Output = scale.Output
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
var data = GetCategories();
|
||||
|
||||
if (scale is OrdinalScale ordinal)
|
||||
@@ -311,6 +337,23 @@ namespace Radzen.Blazor
|
||||
/// <inheritdoc />
|
||||
public abstract RenderFragment Render(ScaleBase categoryScale, ScaleBase valueScale);
|
||||
|
||||
/// <inheritdoc />
|
||||
public RenderFragment RenderOverlays(ScaleBase categoryScale, ScaleBase valueScale)
|
||||
{
|
||||
return new RenderFragment(builder =>
|
||||
{
|
||||
builder.OpenRegion(0);
|
||||
foreach (var overlay in Overlays)
|
||||
{
|
||||
if (overlay.Visible)
|
||||
{
|
||||
builder.AddContent(1, overlay.Render(categoryScale, valueScale));
|
||||
}
|
||||
}
|
||||
builder.CloseRegion();
|
||||
});
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public abstract string Color { get; }
|
||||
|
||||
@@ -320,6 +363,7 @@ namespace Radzen.Blazor
|
||||
var shouldRefresh = parameters.DidParameterChange(nameof(Data), Data);
|
||||
var visibleChanged = parameters.DidParameterChange(nameof(Visible), Visible);
|
||||
var hiddenChanged = parameters.DidParameterChange(nameof(Hidden), Hidden);
|
||||
var categoryChanged = parameters.DidParameterChange(nameof(CategoryProperty), CategoryProperty);
|
||||
|
||||
await base.SetParametersAsync(parameters);
|
||||
|
||||
@@ -335,6 +379,11 @@ namespace Radzen.Blazor
|
||||
shouldRefresh = true;
|
||||
}
|
||||
|
||||
if (categoryChanged || shouldRefresh)
|
||||
{
|
||||
categoryPropertyCache = null;
|
||||
}
|
||||
|
||||
if (Data != null && Data.Count() != Items.Count)
|
||||
{
|
||||
shouldRefresh = true;
|
||||
@@ -423,7 +472,7 @@ namespace Radzen.Blazor
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public virtual RenderFragment RenderTooltip(object data, double marginLeft, double marginTop)
|
||||
public virtual RenderFragment RenderTooltip(object data, double marginLeft, double marginTop, double chartHeight)
|
||||
{
|
||||
var item = (TItem)data;
|
||||
|
||||
@@ -436,10 +485,7 @@ namespace Radzen.Blazor
|
||||
builder.AddAttribute(1, nameof(ChartTooltip.X), x + marginLeft);
|
||||
builder.AddAttribute(2, nameof(ChartTooltip.Y), y + marginTop);
|
||||
|
||||
if (TooltipTemplate != null)
|
||||
{
|
||||
builder.AddAttribute(3, nameof(ChartTooltip.ChildContent), TooltipTemplate(item));
|
||||
}
|
||||
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));
|
||||
@@ -508,9 +554,81 @@ namespace Radzen.Blazor
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public double GetMedian()
|
||||
{
|
||||
return Data.Select(e => Value(e)).OrderBy(e => e).Skip(Data.Count() / 2).FirstOrDefault();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public double GetMean()
|
||||
{
|
||||
return Data.Select(e => Value(e)).Average();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public double GetMode()
|
||||
{
|
||||
return Data.GroupBy(e => Value(e)).Select(g => new { Value = g.Key, Count = g.Count() }).OrderByDescending(e => e.Count).FirstOrDefault().Value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// https://en.wikipedia.org/wiki/Simple_linear_regression#Fitting_the_regression_line
|
||||
/// </summary>
|
||||
public (double a, double b) GetTrend()
|
||||
{
|
||||
double a, b;
|
||||
|
||||
Func<TItem, double> X;
|
||||
Func<TItem, double> Y;
|
||||
if (Chart.ShouldInvertAxes())
|
||||
{
|
||||
X = e => Chart.CategoryScale.Scale(Value(e));
|
||||
Y = e => Chart.ValueScale.Scale(Category(Chart.ValueScale)(e));
|
||||
}
|
||||
else
|
||||
{
|
||||
X = e => Chart.CategoryScale.Scale(Category(Chart.CategoryScale)(e));
|
||||
Y = e => Chart.ValueScale.Scale(Value(e));
|
||||
}
|
||||
|
||||
var avgX = Data.Select(e => X(e)).Average();
|
||||
var avgY = Data.Select(e => Y(e)).Average();
|
||||
var sumXY = Data.Sum(e => (X(e) - avgX) * (Y(e) - avgY));
|
||||
if (Chart.ShouldInvertAxes())
|
||||
{
|
||||
var sumYSq = Data.Sum(e => (Y(e) - avgY) * (Y(e) - avgY));
|
||||
b = sumXY / sumYSq;
|
||||
a = avgX - b * avgY;
|
||||
}
|
||||
else
|
||||
{
|
||||
var sumXSq = Data.Sum(e => (X(e) - avgX) * (X(e) - avgX));
|
||||
b = sumXY / sumXSq;
|
||||
a = avgY - b * avgX;
|
||||
}
|
||||
|
||||
return (a, b);
|
||||
}
|
||||
|
||||
private async Task OnLegendItemClick()
|
||||
{
|
||||
IsVisible = !IsVisible;
|
||||
|
||||
if (Chart.LegendClick.HasDelegate)
|
||||
{
|
||||
var args = new LegendClickEventArgs
|
||||
{
|
||||
Data = this.Data,
|
||||
Title = GetTitle(),
|
||||
IsVisible = IsVisible,
|
||||
};
|
||||
|
||||
await Chart.LegendClick.InvokeAsync(args);
|
||||
|
||||
IsVisible = args.IsVisible;
|
||||
}
|
||||
|
||||
await Chart.Refresh();
|
||||
}
|
||||
|
||||
@@ -553,7 +671,7 @@ namespace Radzen.Blazor
|
||||
/// Gets the X coordinate of the tooltip of the specified item.
|
||||
/// </summary>
|
||||
/// <param name="item">The item.</param>
|
||||
protected virtual double TooltipX(TItem item)
|
||||
internal virtual double TooltipX(TItem item)
|
||||
{
|
||||
var category = Category(Chart.CategoryScale);
|
||||
return Chart.CategoryScale.Scale(category(item), true);
|
||||
@@ -563,26 +681,45 @@ namespace Radzen.Blazor
|
||||
/// Gets the Y coordinate of the tooltip of the specified item.
|
||||
/// </summary>
|
||||
/// <param name="item">The item.</param>
|
||||
protected virtual double TooltipY(TItem item)
|
||||
internal virtual double TooltipY(TItem item)
|
||||
{
|
||||
return Chart.ValueScale.Scale(Value(item), true);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public virtual object DataAt(double x, double y)
|
||||
public virtual (object, Point) DataAt(double x, double y)
|
||||
{
|
||||
var first = Items.FirstOrDefault();
|
||||
var last = Items.LastOrDefault();
|
||||
if (Items.Any())
|
||||
{
|
||||
var retObject = Items.Select(item =>
|
||||
{
|
||||
var distance = Math.Abs(TooltipX(item) - x);
|
||||
return new { Item = item, Distance = distance };
|
||||
}).Aggregate((a, b) => a.Distance < b.Distance ? a : b).Item;
|
||||
|
||||
var category = Category(Chart.CategoryScale);
|
||||
return (retObject,
|
||||
new Point() { X = TooltipX(retObject), Y = TooltipY(retObject)});
|
||||
}
|
||||
|
||||
var startX = Chart.CategoryScale.Scale(category(first), true);
|
||||
var endX = Chart.CategoryScale.Scale(category(last), true);
|
||||
return (null, null);
|
||||
}
|
||||
|
||||
var count = Math.Max(Items.Count() - 1, 1);
|
||||
var index = Convert.ToInt32((x - startX) / ((endX - startX) / count));
|
||||
/// <inheritdoc />
|
||||
public virtual IEnumerable<ChartDataLabel> GetDataLabels(double offsetX, double offsetY)
|
||||
{
|
||||
var list = new List<ChartDataLabel>();
|
||||
|
||||
return Items.ElementAtOrDefault(index);
|
||||
foreach (var d in Data)
|
||||
{
|
||||
list.Add(new ChartDataLabel
|
||||
{
|
||||
Position = new Point { X = TooltipX(d) + offsetX, Y = TooltipY(d) + offsetY },
|
||||
TextAnchor = "middle",
|
||||
Text = Chart.ValueAxis.Format(Chart.ValueScale, Value(d))
|
||||
});
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -199,5 +199,20 @@ namespace Radzen
|
||||
/// </summary>
|
||||
/// <value>The value.</value>
|
||||
public object Value { get; set; }
|
||||
/// <summary>
|
||||
/// Gets or sets the icon.
|
||||
/// </summary>
|
||||
/// <value>The icon.</value>
|
||||
public string Icon { get; set; }
|
||||
/// <summary>
|
||||
/// Gets or sets the icon color.
|
||||
/// </summary>
|
||||
/// <value>The icon color.</value>
|
||||
public string IconColor { get; set; }
|
||||
/// <summary>
|
||||
/// Gets or sets the image.
|
||||
/// </summary>
|
||||
/// <value>The image.</value>
|
||||
public string Image { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,14 +1,16 @@
|
||||
using System;
|
||||
using Microsoft.AspNetCore.Components;
|
||||
using Microsoft.AspNetCore.Components.Forms;
|
||||
|
||||
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;
|
||||
using Microsoft.AspNetCore.Components;
|
||||
using Microsoft.AspNetCore.Components.Forms;
|
||||
using Radzen.Blazor;
|
||||
using Radzen.Blazor.Rendering;
|
||||
|
||||
namespace Radzen
|
||||
{
|
||||
@@ -96,11 +98,8 @@ namespace Radzen
|
||||
}
|
||||
set
|
||||
{
|
||||
if (_form != value && value != null)
|
||||
{
|
||||
_form = value;
|
||||
_form.AddComponent(this);
|
||||
}
|
||||
_form = value;
|
||||
_form?.AddComponent(this);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -216,6 +215,32 @@ namespace Radzen
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the search text
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
public string SearchText
|
||||
{
|
||||
get
|
||||
{
|
||||
return searchText;
|
||||
}
|
||||
set
|
||||
{
|
||||
if (searchText != value)
|
||||
{
|
||||
searchText = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the search text changed.
|
||||
/// </summary>
|
||||
/// <value>The search text changed.</value>
|
||||
[Parameter]
|
||||
public EventCallback<string> SearchTextChanged { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The search text
|
||||
/// </summary>
|
||||
@@ -291,20 +316,35 @@ namespace Radzen
|
||||
/// <returns>A Task representing the asynchronous operation.</returns>
|
||||
public override async Task SetParametersAsync(ParameterView parameters)
|
||||
{
|
||||
var searchTextChanged = parameters.DidParameterChange(nameof(SearchText), SearchText);
|
||||
if (searchTextChanged)
|
||||
{
|
||||
searchText = parameters.GetValueOrDefault<string>(SearchText);
|
||||
}
|
||||
|
||||
var dataChanged = parameters.DidParameterChange(nameof(Data), Data);
|
||||
|
||||
if (dataChanged)
|
||||
{
|
||||
await OnDataChanged();
|
||||
}
|
||||
|
||||
var disabledChanged = parameters.DidParameterChange(nameof(Disabled), Disabled);
|
||||
|
||||
var result = base.SetParametersAsync(parameters);
|
||||
|
||||
if (EditContext != null && ValueExpression != null && FieldIdentifier.Model != EditContext.Model)
|
||||
{
|
||||
FieldIdentifier = FieldIdentifier.Create(ValueExpression);
|
||||
EditContext.OnValidationStateChanged -= ValidationStateChanged;
|
||||
EditContext.OnValidationStateChanged += ValidationStateChanged;
|
||||
}
|
||||
|
||||
if (disabledChanged)
|
||||
{
|
||||
FormFieldContext?.DisabledChanged(Disabled);
|
||||
}
|
||||
|
||||
await result;
|
||||
}
|
||||
|
||||
@@ -337,7 +377,7 @@ namespace Radzen
|
||||
/// Gets the value.
|
||||
/// </summary>
|
||||
/// <returns>System.Object.</returns>
|
||||
public object GetValue()
|
||||
public virtual object GetValue()
|
||||
{
|
||||
return Value;
|
||||
}
|
||||
@@ -350,6 +390,21 @@ namespace Radzen
|
||||
/// <returns>ClassList.</returns>
|
||||
protected ClassList GetClassList(string className) => ClassList.Create(className)
|
||||
.AddDisabled(Disabled)
|
||||
.Add(FieldIdentifier, EditContext);
|
||||
.Add(FieldIdentifier, EditContext)
|
||||
.Add("rz-state-empty", !HasValue);
|
||||
#if NET5_0_OR_GREATER
|
||||
/// <inheritdoc/>
|
||||
public virtual async ValueTask FocusAsync()
|
||||
{
|
||||
await Element.FocusAsync();
|
||||
}
|
||||
#endif
|
||||
|
||||
/// <summary> Provides support for RadzenFormField integration. </summary>
|
||||
[CascadingParameter]
|
||||
public IFormFieldContext FormFieldContext { get; set; }
|
||||
|
||||
/// <summary> Gets the current placeholder. Returns empty string if this component is inside a RadzenFormField.</summary>
|
||||
protected string CurrentPlaceholder => FormFieldContext != null ? " " : Placeholder;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -76,10 +76,15 @@ namespace Radzen
|
||||
|
||||
private void UriHelper_OnLocationChanged(object sender, Microsoft.AspNetCore.Components.Routing.LocationChangedEventArgs e)
|
||||
{
|
||||
if (dialogs.Count > 0)
|
||||
while (dialogs.Any())
|
||||
{
|
||||
Close();
|
||||
}
|
||||
|
||||
if (_sideDialogTask?.Task.IsCompleted == false)
|
||||
{
|
||||
CloseSide();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -97,6 +102,16 @@ namespace Radzen
|
||||
/// </summary>
|
||||
public event Action<string, Type, Dictionary<string, object>, DialogOptions> OnOpen;
|
||||
|
||||
/// <summary>
|
||||
/// Raises the Close event for the side dialog
|
||||
/// </summary>
|
||||
public event Action<dynamic> OnSideClose;
|
||||
|
||||
/// <summary>
|
||||
/// Raises the Open event for the side dialog
|
||||
/// </summary>
|
||||
public event Action<Type, Dictionary<string, object>, SideDialogOptions> OnSideOpen;
|
||||
|
||||
/// <summary>
|
||||
/// Opens a dialog with the specified arguments.
|
||||
/// </summary>
|
||||
@@ -104,7 +119,7 @@ namespace Radzen
|
||||
/// <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="options">The dialog options.</param>
|
||||
public void Open<T>(string title, Dictionary<string, object> parameters = null, DialogOptions options = null) where T : ComponentBase
|
||||
public virtual void Open<T>(string title, Dictionary<string, object> parameters = null, DialogOptions options = null) where T : ComponentBase
|
||||
{
|
||||
OpenDialog<T>(title, parameters, options);
|
||||
}
|
||||
@@ -121,6 +136,7 @@ namespace Radzen
|
||||
/// The tasks
|
||||
/// </summary>
|
||||
protected List<TaskCompletionSource<dynamic>> tasks = new List<TaskCompletionSource<dynamic>>();
|
||||
private TaskCompletionSource<dynamic> _sideDialogTask;
|
||||
|
||||
/// <summary>
|
||||
/// Opens a dialog with the specified arguments.
|
||||
@@ -130,7 +146,7 @@ namespace Radzen
|
||||
/// <param name="parameters">The dialog parameters. Passed as property values of <typeparamref name="T" />.</param>
|
||||
/// <param name="options">The dialog options.</param>
|
||||
/// <returns>The value passed as argument to <see cref="Close" />.</returns>
|
||||
public Task<dynamic> OpenAsync<T>(string title, Dictionary<string, object> parameters = null, DialogOptions options = null) where T : ComponentBase
|
||||
public virtual Task<dynamic> OpenAsync<T>(string title, Dictionary<string, object> parameters = null, DialogOptions options = null) where T : ComponentBase
|
||||
{
|
||||
var task = new TaskCompletionSource<dynamic>();
|
||||
tasks.Add(task);
|
||||
@@ -140,6 +156,42 @@ namespace Radzen
|
||||
return task.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>
|
||||
/// <returns>A task that completes when the dialog is closed or a new one opened</returns>
|
||||
public Task<dynamic> OpenSideAsync<T>(string title, Dictionary<string, object> parameters = null, SideDialogOptions options = null)
|
||||
where T : ComponentBase
|
||||
{
|
||||
CloseSide();
|
||||
_sideDialogTask = new TaskCompletionSource<dynamic>();
|
||||
if (options == null)
|
||||
{
|
||||
options = new SideDialogOptions();
|
||||
}
|
||||
|
||||
options.Title = title;
|
||||
OnSideOpen?.Invoke(typeof(T), parameters ?? new Dictionary<string, object>(), options);
|
||||
return _sideDialogTask.Task;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Closes the side dialog
|
||||
/// </summary>
|
||||
/// <param name="result">The result of the Dialog</param>
|
||||
public void CloseSide(dynamic result = null)
|
||||
{
|
||||
if (_sideDialogTask?.Task.IsCompleted == false)
|
||||
{
|
||||
_sideDialogTask.TrySetResult(result);
|
||||
OnSideClose?.Invoke(result);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Opens a dialog with the specified content.
|
||||
/// </summary>
|
||||
@@ -147,7 +199,7 @@ namespace Radzen
|
||||
/// <param name="childContent">The content displayed in the dialog.</param>
|
||||
/// <param name="options">The dialog options.</param>
|
||||
/// <returns>The value passed as argument to <see cref="Close" />.</returns>
|
||||
public Task<dynamic> OpenAsync(string title, RenderFragment<DialogService> childContent, DialogOptions options = null)
|
||||
public virtual Task<dynamic> OpenAsync(string title, RenderFragment<DialogService> childContent, DialogOptions options = null)
|
||||
{
|
||||
var task = new TaskCompletionSource<dynamic>();
|
||||
tasks.Add(task);
|
||||
@@ -167,7 +219,7 @@ namespace Radzen
|
||||
/// <param name="title">The text displayed in the title bar of the dialog.</param>
|
||||
/// <param name="childContent">The content displayed in the dialog.</param>
|
||||
/// <param name="options">The dialog options.</param>
|
||||
public void Open(string title, RenderFragment<DialogService> childContent, DialogOptions options = null)
|
||||
public virtual void Open(string title, RenderFragment<DialogService> childContent, DialogOptions options = null)
|
||||
{
|
||||
options = options ?? new DialogOptions();
|
||||
|
||||
@@ -200,6 +252,9 @@ namespace Radzen
|
||||
AutoFocusFirstElement = options != null ? options.AutoFocusFirstElement : true,
|
||||
CloseDialogOnOverlayClick = options != null ? options.CloseDialogOnOverlayClick : false,
|
||||
CloseDialogOnEsc = options != null ? options.CloseDialogOnEsc : true,
|
||||
CssClass = options != null ? options.CssClass : "",
|
||||
WrapperCssClass = options != null ? options.WrapperCssClass : "",
|
||||
CloseTabIndex = options != null ? options.CloseTabIndex : 0,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -208,7 +263,7 @@ namespace Radzen
|
||||
/// </summary>
|
||||
/// <param name="result">The result.</param>
|
||||
[JSInvokable("DialogService.Close")]
|
||||
public void Close(dynamic result = null)
|
||||
public virtual void Close(dynamic result = null)
|
||||
{
|
||||
var dialog = dialogs.LastOrDefault();
|
||||
|
||||
@@ -229,6 +284,9 @@ namespace Radzen
|
||||
/// <inheritdoc />
|
||||
public void Dispose()
|
||||
{
|
||||
reference?.Dispose();
|
||||
reference = null;
|
||||
|
||||
UriHelper.LocationChanged -= UriHelper_OnLocationChanged;
|
||||
}
|
||||
|
||||
@@ -239,11 +297,11 @@ namespace Radzen
|
||||
/// <param name="title">The text displayed in the title bar of the dialog.</param>
|
||||
/// <param name="options">The options.</param>
|
||||
/// <returns><c>true</c> if the user clicked the OK button, <c>false</c> otherwise.</returns>
|
||||
public async Task<bool?> Confirm(string message = "Confirm?", string title = "Confirm", ConfirmOptions options = null)
|
||||
public virtual async Task<bool?> Confirm(string message = "Confirm?", string title = "Confirm", ConfirmOptions options = null)
|
||||
{
|
||||
var dialogOptions = new DialogOptions()
|
||||
{
|
||||
Width = options != null ? !string.IsNullOrEmpty(options.Width) ? options.Width : "355px" : "355px",
|
||||
Width = options != null ? !string.IsNullOrEmpty(options.Width) ? options.Width : "" : "",
|
||||
Height = options != null ? options.Height : null,
|
||||
Left = options != null ? options.Left : null,
|
||||
Top = options != null ? options.Top : null,
|
||||
@@ -257,41 +315,89 @@ namespace Radzen
|
||||
AutoFocusFirstElement = options != null ? options.AutoFocusFirstElement : true,
|
||||
CloseDialogOnOverlayClick = options != null ? options.CloseDialogOnOverlayClick : false,
|
||||
CloseDialogOnEsc = options != null ? options.CloseDialogOnEsc : true,
|
||||
CssClass = options != null ? $"rz-dialog-confirm {options.CssClass}" : "rz-dialog-confirm",
|
||||
WrapperCssClass = options != null ? $"rz-dialog-wrapper {options.WrapperCssClass}" : "rz-dialog-wrapper",
|
||||
CloseTabIndex = options != null ? options.CloseTabIndex : 0,
|
||||
};
|
||||
|
||||
await JSRuntime.InvokeAsync<string>("Radzen.openDialog", dialogOptions, Reference);
|
||||
|
||||
return await OpenAsync(title, ds =>
|
||||
{
|
||||
RenderFragment content = b =>
|
||||
{
|
||||
var i = 0;
|
||||
b.OpenElement(i++, "div");
|
||||
b.OpenElement(i++, "p");
|
||||
b.AddAttribute(i++, "style", "margin-bottom: 20px;");
|
||||
b.AddContent(i++, message);
|
||||
b.AddAttribute(i++, "class", "rz-dialog-confirm-message");
|
||||
b.AddContent(i++, (MarkupString)message);
|
||||
b.CloseElement();
|
||||
|
||||
b.OpenElement(i++, "div");
|
||||
b.AddAttribute(i++, "class", "row");
|
||||
b.OpenElement(i++, "div");
|
||||
b.AddAttribute(i++, "class", "col-md-12");
|
||||
b.AddAttribute(i++, "class", "rz-dialog-confirm-buttons");
|
||||
|
||||
b.OpenComponent<Blazor.RadzenButton>(i++);
|
||||
b.AddAttribute(i++, "Text", options != null ? options.OkButtonText : "Ok");
|
||||
b.AddAttribute(i++, "Style", "margin-bottom: 10px; width: 150px");
|
||||
b.AddAttribute(i++, "Click", EventCallback.Factory.Create<Microsoft.AspNetCore.Components.Web.MouseEventArgs>(this, () => ds.Close(true)));
|
||||
b.CloseComponent();
|
||||
|
||||
b.OpenComponent<Blazor.RadzenButton>(i++);
|
||||
b.AddAttribute(i++, "Text", options != null ? options.CancelButtonText : "Cancel");
|
||||
b.AddAttribute(i++, "ButtonStyle", ButtonStyle.Secondary);
|
||||
b.AddAttribute(i++, "Style", "margin-bottom: 10px; margin-left: 10px; width: 150px");
|
||||
b.AddAttribute(i++, "Click", EventCallback.Factory.Create<Microsoft.AspNetCore.Components.Web.MouseEventArgs>(this, () => ds.Close(false)));
|
||||
b.CloseComponent();
|
||||
|
||||
b.CloseElement();
|
||||
};
|
||||
return content;
|
||||
}, dialogOptions);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Displays a alert dialog.
|
||||
/// </summary>
|
||||
/// <param name="message">The message displayed to the user.</param>
|
||||
/// <param name="title">The text displayed in the title bar of the dialog.</param>
|
||||
/// <param name="options">The options.</param>
|
||||
/// <returns><c>true</c> if the user clicked the OK button, <c>false</c> otherwise.</returns>
|
||||
public virtual async Task<bool?> Alert(string message = "", string title = "Message", AlertOptions options = null)
|
||||
{
|
||||
var dialogOptions = new DialogOptions()
|
||||
{
|
||||
Width = options != null ? !string.IsNullOrEmpty(options.Width) ? options.Width : "" : "",
|
||||
Height = options != null ? options.Height : null,
|
||||
Left = options != null ? options.Left : null,
|
||||
Top = options != null ? options.Top : null,
|
||||
Bottom = options != null ? options.Bottom : null,
|
||||
ChildContent = options != null ? options.ChildContent : null,
|
||||
ShowTitle = options != null ? options.ShowTitle : true,
|
||||
ShowClose = options != null ? options.ShowClose : true,
|
||||
Resizable = options != null ? options.Resizable : false,
|
||||
Draggable = options != null ? options.Draggable : false,
|
||||
Style = options != null ? options.Style : "",
|
||||
AutoFocusFirstElement = options != null ? options.AutoFocusFirstElement : true,
|
||||
CloseDialogOnOverlayClick = options != null ? options.CloseDialogOnOverlayClick : false,
|
||||
CloseDialogOnEsc = options != null ? options.CloseDialogOnEsc : true,
|
||||
CssClass = options != null ? $"rz-dialog-alert {options.CssClass}" : "rz-dialog-alert",
|
||||
WrapperCssClass = options != null ? $"rz-dialog-wrapper {options.WrapperCssClass}" : "rz-dialog-wrapper",
|
||||
CloseTabIndex = options != null ? options.CloseTabIndex : 0,
|
||||
};
|
||||
|
||||
return await OpenAsync(title, ds =>
|
||||
{
|
||||
RenderFragment content = b =>
|
||||
{
|
||||
var i = 0;
|
||||
b.OpenElement(i++, "p");
|
||||
b.AddAttribute(i++, "class", "rz-dialog-alert-message");
|
||||
b.AddContent(i++, (MarkupString)message);
|
||||
b.CloseElement();
|
||||
|
||||
b.OpenElement(i++, "div");
|
||||
b.AddAttribute(i++, "class", "rz-dialog-alert-buttons");
|
||||
|
||||
b.OpenComponent<Blazor.RadzenButton>(i++);
|
||||
b.AddAttribute(i++, "Text", options != null ? options.OkButtonText : "Ok");
|
||||
b.AddAttribute(i++, "Click", EventCallback.Factory.Create<Microsoft.AspNetCore.Components.Web.MouseEventArgs>(this, () => ds.Close(true)));
|
||||
b.CloseComponent();
|
||||
|
||||
b.CloseElement();
|
||||
};
|
||||
return content;
|
||||
@@ -300,9 +406,9 @@ namespace Radzen
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Class DialogOptions.
|
||||
/// Base Class for dialog options
|
||||
/// </summary>
|
||||
public class DialogOptions
|
||||
public abstract class DialogOptionsBase
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether to show the title bar. Set to <c>true</c> by default.
|
||||
@@ -315,7 +421,93 @@ namespace Radzen
|
||||
/// </summary>
|
||||
/// <value><c>true</c> if the close button is shown; otherwise, <c>false</c>.</value>
|
||||
public bool ShowClose { get; set; } = true;
|
||||
/// <summary>
|
||||
/// Gets or sets the width of the dialog.
|
||||
/// </summary>
|
||||
/// <value>The width.</value>
|
||||
public string Width { get; set; }
|
||||
/// <summary>
|
||||
/// Gets or sets the height of the dialog.
|
||||
/// </summary>
|
||||
/// <value>The height.</value>
|
||||
public string Height { get; set; }
|
||||
/// <summary>
|
||||
/// Gets or sets the CSS style of the dialog
|
||||
/// </summary>
|
||||
/// <value>The style.</value>
|
||||
public string Style { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether the dialog should be closed by clicking the overlay.
|
||||
/// </summary>
|
||||
/// <value><c>true</c> if closeable; otherwise, <c>false</c>.</value>
|
||||
public bool CloseDialogOnOverlayClick { get; set; } = false;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets dialog box custom class
|
||||
/// </summary>
|
||||
public string CssClass { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the CSS classes added to the dialog's wrapper element.
|
||||
/// </summary>
|
||||
public string WrapperCssClass { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value the dialog escape tabindex. Set to <c>0</c> by default.
|
||||
/// </summary>
|
||||
public int CloseTabIndex { get; set; } = 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Class SideDialogOptions
|
||||
/// </summary>
|
||||
public class SideDialogOptions : DialogOptionsBase
|
||||
{
|
||||
/// <summary>
|
||||
/// The title displayed on the dialog.
|
||||
/// </summary>
|
||||
public string Title { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The Position on which the dialog will be positioned
|
||||
/// </summary>
|
||||
public DialogPosition Position { get; set; } = DialogPosition.Right;
|
||||
|
||||
/// <summary>
|
||||
/// Whether to show a mask on the background or not
|
||||
/// </summary>
|
||||
public bool ShowMask { get; set; } = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// DialogPosition enum
|
||||
/// </summary>
|
||||
public enum DialogPosition
|
||||
{
|
||||
/// <summary>
|
||||
/// Dialog will be positioned on the right side
|
||||
/// </summary>
|
||||
Right,
|
||||
/// <summary>
|
||||
/// Dialog will be positioned on the left side
|
||||
/// </summary>
|
||||
Left,
|
||||
/// <summary>
|
||||
/// Dialog will be positioned on the top of the page
|
||||
/// </summary>
|
||||
Top,
|
||||
/// <summary>
|
||||
/// Dialog will be positioned at the bottom of the page
|
||||
/// </summary>
|
||||
Bottom
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Class DialogOptions.
|
||||
/// </summary>
|
||||
public class DialogOptions : DialogOptionsBase
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether the dialog is resizable. Set to <c>false</c> by default.
|
||||
/// </summary>
|
||||
@@ -342,21 +534,6 @@ namespace Radzen
|
||||
/// <value>The bottom.</value>
|
||||
public string Bottom { get; set; }
|
||||
/// <summary>
|
||||
/// Gets or sets the width of the dialog.
|
||||
/// </summary>
|
||||
/// <value>The width.</value>
|
||||
public string Width { get; set; }
|
||||
/// <summary>
|
||||
/// Gets or sets the height of the dialog.
|
||||
/// </summary>
|
||||
/// <value>The height.</value>
|
||||
public string Height { get; set; }
|
||||
/// <summary>
|
||||
/// Gets or sets the CSS style of the dialog
|
||||
/// </summary>
|
||||
/// <value>The style.</value>
|
||||
public string Style { get; set; }
|
||||
/// <summary>
|
||||
/// Gets or sets the child content.
|
||||
/// </summary>
|
||||
/// <value>The child content.</value>
|
||||
@@ -365,13 +542,6 @@ namespace Radzen
|
||||
/// Gets or sets a value indicating whether to focus the first focusable HTML element. Set to <c>true</c> by default.
|
||||
/// </summary>
|
||||
public bool AutoFocusFirstElement { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether the dialog should be closed by clicking the overlay.
|
||||
/// </summary>
|
||||
/// <value><c>true</c> if closeable; otherwise, <c>false</c>.</value>
|
||||
public bool CloseDialogOnOverlayClick { get; set; } = false;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether the dialog should be closed on ESC key press.
|
||||
/// </summary>
|
||||
@@ -382,12 +552,19 @@ namespace Radzen
|
||||
/// <summary>
|
||||
/// Class ConfirmOptions.
|
||||
/// </summary>
|
||||
public class ConfirmOptions : DialogOptions
|
||||
public class AlertOptions : DialogOptions
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the text of the OK button.
|
||||
/// </summary>
|
||||
public string OkButtonText { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Class ConfirmOptions.
|
||||
/// </summary>
|
||||
public class ConfirmOptions : AlertOptions
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the text of the Cancel button.
|
||||
/// </summary>
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
using System;
|
||||
using Microsoft.AspNetCore.Components;
|
||||
using Microsoft.AspNetCore.Components.Rendering;
|
||||
using Microsoft.JSInterop;
|
||||
using Radzen.Blazor;
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Linq.Dynamic.Core;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Components;
|
||||
using Microsoft.AspNetCore.Components.Rendering;
|
||||
using Microsoft.JSInterop;
|
||||
|
||||
namespace Radzen
|
||||
{
|
||||
@@ -16,7 +17,13 @@ namespace Radzen
|
||||
/// <typeparam name="T"></typeparam>
|
||||
public class DropDownBase<T> : DataBoundFormComponent<T>
|
||||
{
|
||||
#if NET5
|
||||
#if NET5_0_OR_GREATER
|
||||
/// <summary>
|
||||
/// Gets or sets a value that determines how many additional items will be rendered before and after the visible region. This help to reduce the frequency of rendering during scrolling. However, higher values mean that more elements will be present in the page.
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
public int VirtualizationOverscanCount { get; set; }
|
||||
|
||||
internal Microsoft.AspNetCore.Components.Web.Virtualization.Virtualize<object> virtualize;
|
||||
|
||||
/// <summary>
|
||||
@@ -30,6 +37,8 @@ namespace Radzen
|
||||
}
|
||||
}
|
||||
|
||||
List<object> virtualItems;
|
||||
|
||||
private async ValueTask<Microsoft.AspNetCore.Components.Web.Virtualization.ItemsProviderResult<object>> LoadItems(Microsoft.AspNetCore.Components.Web.Virtualization.ItemsProviderRequest request)
|
||||
{
|
||||
var data = Data != null ? Data.Cast<object>() : Enumerable.Empty<object>();
|
||||
@@ -44,10 +53,12 @@ namespace Radzen
|
||||
|
||||
if (LoadData.HasDelegate)
|
||||
{
|
||||
await LoadData.InvokeAsync(new Radzen.LoadDataArgs() { Skip = request.StartIndex, Top = request.Count, Filter = await JSRuntime.InvokeAsync<string>("Radzen.getInputValue", search) });
|
||||
await LoadData.InvokeAsync(new Radzen.LoadDataArgs() { Skip = request.StartIndex, Top = request.Count, Filter = searchText });
|
||||
}
|
||||
|
||||
return new Microsoft.AspNetCore.Components.Web.Virtualization.ItemsProviderResult<object>(LoadData.HasDelegate ? Data.Cast<object>() : view.Skip(request.StartIndex).Take(top), LoadData.HasDelegate ? Count : totalItemsCount);
|
||||
virtualItems = (LoadData.HasDelegate ? Data : view.Skip(request.StartIndex).Take(top)).Cast<object>().ToList();
|
||||
|
||||
return new Microsoft.AspNetCore.Components.Web.Virtualization.ItemsProviderResult<object>(virtualItems, LoadData.HasDelegate ? Count : totalItemsCount);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -74,13 +85,22 @@ namespace Radzen
|
||||
/// <returns><c>true</c> if virtualization is allowed; otherwise, <c>false</c>.</returns>
|
||||
internal bool IsVirtualizationAllowed()
|
||||
{
|
||||
#if NET5
|
||||
#if NET5_0_OR_GREATER
|
||||
return AllowVirtualization;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
internal int GetVirtualizationOverscanCount()
|
||||
{
|
||||
#if NET5_0_OR_GREATER
|
||||
return VirtualizationOverscanCount;
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Renders the items.
|
||||
/// </summary>
|
||||
@@ -89,7 +109,7 @@ namespace Radzen
|
||||
{
|
||||
return new RenderFragment(builder =>
|
||||
{
|
||||
#if NET5
|
||||
#if NET5_0_OR_GREATER
|
||||
if (AllowVirtualization)
|
||||
{
|
||||
builder.OpenComponent(0, typeof(Microsoft.AspNetCore.Components.Web.Virtualization.Virtualize<object>));
|
||||
@@ -102,6 +122,11 @@ namespace Radzen
|
||||
});
|
||||
}));
|
||||
|
||||
if(VirtualizationOverscanCount != default(int))
|
||||
{
|
||||
builder.AddAttribute(3, "OverscanCount", VirtualizationOverscanCount);
|
||||
}
|
||||
|
||||
builder.AddComponentReferenceCapture(7, c => { virtualize = (Microsoft.AspNetCore.Components.Web.Virtualization.Virtualize<object>)c; });
|
||||
|
||||
builder.CloseComponent();
|
||||
@@ -131,7 +156,14 @@ namespace Radzen
|
||||
{
|
||||
return !string.IsNullOrEmpty($"{internalValue}");
|
||||
}
|
||||
return internalValue != null;
|
||||
else if (typeof(IEnumerable).IsAssignableFrom(typeof(T)))
|
||||
{
|
||||
return internalValue != null && ((IEnumerable)internalValue).Cast<object>().Any();
|
||||
}
|
||||
else
|
||||
{
|
||||
return internalValue != null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -149,7 +181,7 @@ namespace Radzen
|
||||
|
||||
internal object GetKey(object item)
|
||||
{
|
||||
var value = PropertyAccess.GetItemOrValueFromProperty(item, ValueProperty);
|
||||
var value = GetItemOrValueFromProperty(item, ValueProperty);
|
||||
|
||||
if (!keys.Contains(value))
|
||||
{
|
||||
@@ -169,6 +201,13 @@ namespace Radzen
|
||||
[Parameter]
|
||||
public virtual bool AllowFiltering { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether filtering is allowed as you type. Set to <c>true</c> by default.
|
||||
/// </summary>
|
||||
/// <value><c>true</c> if filtering is allowed; otherwise, <c>false</c>.</value>
|
||||
[Parameter]
|
||||
public virtual bool FilterAsYouType { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether the user can clear the value. Set to <c>false</c> by default.
|
||||
/// </summary>
|
||||
@@ -183,6 +222,13 @@ namespace Radzen
|
||||
[Parameter]
|
||||
public bool Multiple { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether the user can select all values in multiple selection. Set to <c>true</c> by default.
|
||||
/// </summary>
|
||||
/// <value><c>true</c> if select all values is allowed; otherwise, <c>false</c>.</value>
|
||||
[Parameter]
|
||||
public bool AllowSelectAll { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the template.
|
||||
/// </summary>
|
||||
@@ -197,6 +243,13 @@ namespace Radzen
|
||||
[Parameter]
|
||||
public string ValueProperty { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the disabled property.
|
||||
/// </summary>
|
||||
/// <value>The disabled property.</value>
|
||||
[Parameter]
|
||||
public string DisabledProperty { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the selected item changed.
|
||||
/// </summary>
|
||||
@@ -207,7 +260,7 @@ namespace Radzen
|
||||
/// <summary>
|
||||
/// The selected items
|
||||
/// </summary>
|
||||
protected List<object> selectedItems = new List<object>();
|
||||
protected IList<object> selectedItems = new List<object>();
|
||||
/// <summary>
|
||||
/// The selected item
|
||||
/// </summary>
|
||||
@@ -223,10 +276,10 @@ namespace Radzen
|
||||
return;
|
||||
}
|
||||
|
||||
if (selectedItems.Count != View.Cast<object>().Count())
|
||||
if (selectedItems.Count != View.Cast<object>().ToList().Where(i => disabledPropertyGetter != null ? disabledPropertyGetter(i) as bool? != true : true).Count())
|
||||
{
|
||||
selectedItems.Clear();
|
||||
selectedItems = View.Cast<object>().ToList();
|
||||
selectedItems = View.Cast<object>().ToList().Where(i => disabledPropertyGetter != null ? disabledPropertyGetter(i) as bool? != true : true).ToList();
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -236,7 +289,7 @@ namespace Radzen
|
||||
if (!string.IsNullOrEmpty(ValueProperty))
|
||||
{
|
||||
System.Reflection.PropertyInfo pi = PropertyAccess.GetElementType(Data.GetType()).GetProperty(ValueProperty);
|
||||
internalValue = selectedItems.Select(i => PropertyAccess.GetItemOrValueFromProperty(i, ValueProperty)).AsQueryable().Cast(pi.PropertyType);
|
||||
internalValue = selectedItems.Select(i => GetItemOrValueFromProperty(i, ValueProperty)).AsQueryable().Cast(pi.PropertyType);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -244,13 +297,47 @@ namespace Radzen
|
||||
internalValue = selectedItems.AsQueryable().Cast(type);
|
||||
}
|
||||
|
||||
await ValueChanged.InvokeAsync((T)internalValue);
|
||||
if (typeof(IList).IsAssignableFrom(typeof(T)))
|
||||
{
|
||||
var list = (IList)Activator.CreateInstance(typeof(T));
|
||||
foreach (var i in (IEnumerable)internalValue)
|
||||
{
|
||||
list.Add(i);
|
||||
}
|
||||
await ValueChanged.InvokeAsync((T)(object)list);
|
||||
}
|
||||
else if (typeof(T).IsGenericType && typeof(ICollection<>).MakeGenericType(typeof(T).GetGenericArguments()[0]).IsAssignableFrom(typeof(T)))
|
||||
{
|
||||
var list = (IList)Activator.CreateInstance(typeof(List<>).MakeGenericType(typeof(T).GetGenericArguments()[0]));
|
||||
foreach (var i in (IEnumerable)internalValue)
|
||||
{
|
||||
list.Add(i);
|
||||
}
|
||||
await ValueChanged.InvokeAsync((T)(object)list);
|
||||
}
|
||||
else
|
||||
{
|
||||
await ValueChanged.InvokeAsync((T)internalValue);
|
||||
}
|
||||
if (FieldIdentifier.FieldName != null) { EditContext?.NotifyFieldChanged(FieldIdentifier); }
|
||||
await Change.InvokeAsync(internalValue);
|
||||
|
||||
StateHasChanged();
|
||||
}
|
||||
|
||||
internal bool IsAllSelected()
|
||||
{
|
||||
if (LoadData.HasDelegate && !string.IsNullOrEmpty(ValueProperty))
|
||||
{
|
||||
return View != null && View.Cast<object>().ToList()
|
||||
.Where(i => disabledPropertyGetter != null ? disabledPropertyGetter(i) as bool? != true : true)
|
||||
.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();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Resets this instance.
|
||||
/// </summary>
|
||||
@@ -269,6 +356,7 @@ namespace Radzen
|
||||
return;
|
||||
|
||||
searchText = null;
|
||||
await SearchTextChanged.InvokeAsync(searchText);
|
||||
await JSRuntime.InvokeAsync<string>("Radzen.setInputValue", search, "");
|
||||
|
||||
internalValue = default(T);
|
||||
@@ -316,13 +404,94 @@ namespace Radzen
|
||||
selectedItems.Clear();
|
||||
}
|
||||
|
||||
OnDataChanged();
|
||||
|
||||
StateHasChanged();
|
||||
InvokeAsync(OnDataChanged);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override void OnParametersSet()
|
||||
{
|
||||
base.OnParametersSet();
|
||||
|
||||
if (_data != null)
|
||||
{
|
||||
var query = _data.AsQueryable();
|
||||
|
||||
var type = query.ElementType;
|
||||
|
||||
if (type == typeof(object) && typeof(EnumerableQuery).IsAssignableFrom(query.GetType()) && query.Any())
|
||||
{
|
||||
type = query.FirstOrDefault().GetType();
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(ValueProperty))
|
||||
{
|
||||
valuePropertyGetter = PropertyAccess.Getter<object, object>(ValueProperty, type);
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(TextProperty))
|
||||
{
|
||||
textPropertyGetter = PropertyAccess.Getter<object, object>(TextProperty, type);
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(DisabledProperty))
|
||||
{
|
||||
disabledPropertyGetter = PropertyAccess.Getter<object, object>(DisabledProperty, type);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal Func<object, object> valuePropertyGetter;
|
||||
internal Func<object, object> textPropertyGetter;
|
||||
internal Func<object, object> disabledPropertyGetter;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the item or value from property.
|
||||
/// </summary>
|
||||
/// <param name="item">The item.</param>
|
||||
/// <param name="property">The property.</param>
|
||||
/// <returns>System.Object.</returns>
|
||||
public object GetItemOrValueFromProperty(object item, string property)
|
||||
{
|
||||
if (item != null)
|
||||
{
|
||||
if (property == TextProperty && textPropertyGetter != null)
|
||||
{
|
||||
return textPropertyGetter(item);
|
||||
}
|
||||
else if (property == ValueProperty && valuePropertyGetter != null)
|
||||
{
|
||||
return valuePropertyGetter(item);
|
||||
}
|
||||
else if (property == DisabledProperty && disabledPropertyGetter != null)
|
||||
{
|
||||
return disabledPropertyGetter(item);
|
||||
}
|
||||
|
||||
var enumValue = item as Enum;
|
||||
if (enumValue != null)
|
||||
{
|
||||
return Radzen.Blazor.EnumExtensions.GetDisplayDescription(enumValue);
|
||||
}
|
||||
}
|
||||
|
||||
return item;
|
||||
}
|
||||
|
||||
#if NET5_0_OR_GREATER
|
||||
/// <inheritdoc/>
|
||||
protected override async Task OnDataChanged()
|
||||
{
|
||||
await base.OnDataChanged();
|
||||
|
||||
if (AllowVirtualization && Virtualize != null && !LoadData.HasDelegate)
|
||||
{
|
||||
await InvokeAsync(Virtualize.RefreshDataAsync);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// Gets the popup identifier.
|
||||
/// </summary>
|
||||
@@ -420,12 +589,33 @@ namespace Radzen
|
||||
/// </summary>
|
||||
/// <param name="args">The <see cref="Microsoft.AspNetCore.Components.Web.KeyboardEventArgs"/> instance containing the event data.</param>
|
||||
/// <param name="isFilter">if set to <c>true</c> [is filter].</param>
|
||||
private async System.Threading.Tasks.Task HandleKeyPress(Microsoft.AspNetCore.Components.Web.KeyboardEventArgs args, bool isFilter = false)
|
||||
protected virtual async System.Threading.Tasks.Task HandleKeyPress(Microsoft.AspNetCore.Components.Web.KeyboardEventArgs args, bool isFilter = false)
|
||||
{
|
||||
if (Disabled)
|
||||
return;
|
||||
|
||||
var items = (LoadData.HasDelegate ? Data != null ? Data : Enumerable.Empty<object>() : (View != null ? View : Enumerable.Empty<object>())).Cast<object>();
|
||||
List<object> items = Enumerable.Empty<object>().ToList();
|
||||
|
||||
if (LoadData.HasDelegate)
|
||||
{
|
||||
if (Data != null)
|
||||
{
|
||||
items = Data.Cast<object>().ToList();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (IsVirtualizationAllowed())
|
||||
{
|
||||
#if NET5_0_OR_GREATER
|
||||
items = virtualItems;
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
items = View.Cast<object>().ToList();
|
||||
}
|
||||
}
|
||||
|
||||
var key = args.Code != null ? args.Code : args.Key;
|
||||
|
||||
@@ -433,11 +623,13 @@ namespace Radzen
|
||||
{
|
||||
try
|
||||
{
|
||||
var newSelectedIndex = await JSRuntime.InvokeAsync<int>("Radzen.focusListItem", search, list, key == "ArrowDown" || key == "ArrowRight", selectedIndex);
|
||||
var currentViewIndex = Multiple ? selectedIndex : items.IndexOf(selectedItem);
|
||||
|
||||
var newSelectedIndex = await JSRuntime.InvokeAsync<int>("Radzen.focusListItem", search, list, key == "ArrowDown" || key == "ArrowRight", currentViewIndex);
|
||||
|
||||
if (!Multiple)
|
||||
{
|
||||
if (newSelectedIndex != selectedIndex && newSelectedIndex >= 0 && newSelectedIndex <= items.Count() - 1)
|
||||
if (newSelectedIndex != currentViewIndex && newSelectedIndex >= 0 && newSelectedIndex <= items.Count() - 1)
|
||||
{
|
||||
selectedIndex = newSelectedIndex;
|
||||
await OnSelectItem(items.ElementAt(selectedIndex), true);
|
||||
@@ -445,7 +637,7 @@ namespace Radzen
|
||||
}
|
||||
else
|
||||
{
|
||||
selectedIndex = await JSRuntime.InvokeAsync<int>("Radzen.focusListItem", search, list, key == "ArrowDown", selectedIndex);
|
||||
selectedIndex = await JSRuntime.InvokeAsync<int>("Radzen.focusListItem", search, list, key == "ArrowDown", currentViewIndex);
|
||||
}
|
||||
}
|
||||
catch (Exception)
|
||||
@@ -453,7 +645,7 @@ namespace Radzen
|
||||
//
|
||||
}
|
||||
}
|
||||
else if (Multiple && key == "Space")
|
||||
else if (Multiple && key == "Enter")
|
||||
{
|
||||
if (selectedIndex >= 0 && selectedIndex <= items.Count() - 1)
|
||||
{
|
||||
@@ -469,7 +661,7 @@ namespace Radzen
|
||||
{
|
||||
await JSRuntime.InvokeVoidAsync("Radzen.closePopup", PopupID);
|
||||
}
|
||||
else if (key == "Delete")
|
||||
else if (key == "Delete" && AllowClear)
|
||||
{
|
||||
if (!Multiple && selectedItem != null)
|
||||
{
|
||||
@@ -482,7 +674,7 @@ namespace Radzen
|
||||
Debounce(DebounceFilter, FilterDelay);
|
||||
}
|
||||
}
|
||||
else if(AllowFiltering && isFilter)
|
||||
else if (AllowFiltering && isFilter && FilterAsYouType)
|
||||
{
|
||||
Debounce(DebounceFilter, FilterDelay);
|
||||
}
|
||||
@@ -504,17 +696,16 @@ namespace Radzen
|
||||
{
|
||||
if (!LoadData.HasDelegate)
|
||||
{
|
||||
searchText = await JSRuntime.InvokeAsync<string>("Radzen.getInputValue", search);
|
||||
_view = null;
|
||||
if (IsVirtualizationAllowed())
|
||||
{
|
||||
#if NET5
|
||||
#if NET5_0_OR_GREATER
|
||||
if (virtualize != null)
|
||||
{
|
||||
await virtualize.RefreshDataAsync();
|
||||
}
|
||||
await InvokeAsync(() => { StateHasChanged(); });
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -525,28 +716,32 @@ namespace Radzen
|
||||
{
|
||||
if (IsVirtualizationAllowed())
|
||||
{
|
||||
#if NET5
|
||||
#if NET5_0_OR_GREATER
|
||||
if (virtualize != null)
|
||||
{
|
||||
await InvokeAsync(virtualize.RefreshDataAsync);
|
||||
}
|
||||
await InvokeAsync(() => { StateHasChanged(); });
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
await LoadData.InvokeAsync(await GetLoadDataArgs());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (Multiple)
|
||||
selectedIndex = -1;
|
||||
|
||||
await JSRuntime.InvokeAsync<string>("Radzen.repositionPopup", Element, PopupID);
|
||||
await SearchTextChanged.InvokeAsync(SearchText);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handles the <see cref="E:KeyPress" /> event.
|
||||
/// </summary>
|
||||
/// <param name="args">The <see cref="Microsoft.AspNetCore.Components.Web.KeyboardEventArgs"/> instance containing the event data.</param>
|
||||
protected async System.Threading.Tasks.Task OnKeyPress(Microsoft.AspNetCore.Components.Web.KeyboardEventArgs args)
|
||||
protected virtual async System.Threading.Tasks.Task OnKeyPress(Microsoft.AspNetCore.Components.Web.KeyboardEventArgs args)
|
||||
{
|
||||
await HandleKeyPress(args);
|
||||
}
|
||||
@@ -576,17 +771,17 @@ namespace Radzen
|
||||
/// <returns>LoadDataArgs.</returns>
|
||||
internal virtual async System.Threading.Tasks.Task<LoadDataArgs> GetLoadDataArgs()
|
||||
{
|
||||
#if NET5
|
||||
#if NET5_0_OR_GREATER
|
||||
if (AllowVirtualization)
|
||||
{
|
||||
return new Radzen.LoadDataArgs() { Skip = 0, Top = PageSize, Filter = await JSRuntime.InvokeAsync<string>("Radzen.getInputValue", search) };
|
||||
return await Task.FromResult(new Radzen.LoadDataArgs() { Skip = 0, Top = PageSize, Filter = searchText });
|
||||
}
|
||||
else
|
||||
{
|
||||
return new Radzen.LoadDataArgs() { Filter = await JSRuntime.InvokeAsync<string>("Radzen.getInputValue", search) };
|
||||
return await Task.FromResult(new Radzen.LoadDataArgs() { Filter = searchText });
|
||||
}
|
||||
#else
|
||||
return new Radzen.LoadDataArgs() { Filter = await JSRuntime.InvokeAsync<string>("Radzen.getInputValue", search) };
|
||||
return await Task.FromResult(new Radzen.LoadDataArgs() { Filter = searchText });
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -622,7 +817,7 @@ namespace Radzen
|
||||
/// <returns>A Task representing the asynchronous operation.</returns>
|
||||
public override async Task SetParametersAsync(ParameterView parameters)
|
||||
{
|
||||
#if NET5
|
||||
#if NET5_0_OR_GREATER
|
||||
var pageSize = parameters.GetValueOrDefault<int>(nameof(PageSize));
|
||||
if(pageSize != default(int))
|
||||
{
|
||||
@@ -666,7 +861,7 @@ namespace Radzen
|
||||
|
||||
if (valueAsEnumerable != null)
|
||||
{
|
||||
if (valueAsEnumerable.OfType<object>().Count() != selectedItems.Count)
|
||||
if (!valueAsEnumerable.Cast<object>().SequenceEqual(selectedItems.Select(i => GetItemOrValueFromProperty(i, ValueProperty))))
|
||||
{
|
||||
selectedItems.Clear();
|
||||
}
|
||||
@@ -691,15 +886,22 @@ namespace Radzen
|
||||
/// </summary>
|
||||
/// <param name="item">The item.</param>
|
||||
/// <returns><c>true</c> if the specified item is selected; otherwise, <c>false</c>.</returns>
|
||||
internal bool isSelected(object item)
|
||||
internal bool IsSelected(object item)
|
||||
{
|
||||
if (Multiple)
|
||||
if (!string.IsNullOrEmpty(ValueProperty))
|
||||
{
|
||||
return selectedItems.IndexOf(item) != -1;
|
||||
return IsItemSelectedByValue(GetItemOrValueFromProperty(item, ValueProperty));
|
||||
}
|
||||
else
|
||||
{
|
||||
return item == selectedItem;
|
||||
if (Multiple)
|
||||
{
|
||||
return selectedItems.IndexOf(item) != -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
return object.Equals(item, selectedItem);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -723,6 +925,13 @@ namespace Radzen
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the item separator for Multiple dropdown.
|
||||
/// </summary>
|
||||
/// <value>Item separator</value>
|
||||
[Parameter]
|
||||
public string Separator { get; set; } = ",";
|
||||
|
||||
/// <summary>
|
||||
/// Gets the items.
|
||||
/// </summary>
|
||||
@@ -768,7 +977,35 @@ namespace Radzen
|
||||
|
||||
query.Add($"{Enum.GetName(typeof(StringFilterOperator), FilterOperator)}(@0)");
|
||||
|
||||
_view = Query.Where(String.Join(".", query), ignoreCase ? searchText.ToLower() : searchText);
|
||||
var search = ignoreCase ? searchText.ToLower() : searchText;
|
||||
|
||||
if (Query.ElementType == typeof(Enum))
|
||||
{
|
||||
_view = Query.Cast<Enum>()
|
||||
.Where((Func<Enum, bool>)(i =>
|
||||
{
|
||||
var value = ignoreCase ? i.GetDisplayDescription().ToLower() : i.GetDisplayDescription();
|
||||
|
||||
if (FilterOperator == StringFilterOperator.Contains)
|
||||
{
|
||||
return value.Contains(search);
|
||||
}
|
||||
else if (FilterOperator == StringFilterOperator.StartsWith)
|
||||
{
|
||||
return value.StartsWith(search);
|
||||
}
|
||||
else if (FilterOperator == StringFilterOperator.EndsWith)
|
||||
{
|
||||
return value.EndsWith(search);
|
||||
}
|
||||
|
||||
return value == search;
|
||||
})).AsQueryable();
|
||||
}
|
||||
else
|
||||
{
|
||||
_view = Query.Where(String.Join(".", query), search);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -828,6 +1065,11 @@ namespace Radzen
|
||||
/// <param name="raiseChange">if set to <c>true</c> [raise change].</param>
|
||||
public async System.Threading.Tasks.Task SelectItem(object item, bool raiseChange = true)
|
||||
{
|
||||
if (disabledPropertyGetter != null && disabledPropertyGetter(item) as bool? == true)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!Multiple)
|
||||
{
|
||||
if (object.Equals(item, selectedItem))
|
||||
@@ -849,24 +1091,23 @@ namespace Radzen
|
||||
}
|
||||
else
|
||||
{
|
||||
if (selectedItems.IndexOf(item) == -1)
|
||||
{
|
||||
selectedItems.Add(item);
|
||||
}
|
||||
else
|
||||
{
|
||||
selectedItems.Remove(item);
|
||||
}
|
||||
UpdateSelectedItems(item);
|
||||
|
||||
if (!string.IsNullOrEmpty(ValueProperty))
|
||||
{
|
||||
System.Reflection.PropertyInfo pi = PropertyAccess.GetElementType(Data.GetType()).GetProperty(ValueProperty);
|
||||
internalValue = selectedItems.Select(i => PropertyAccess.GetItemOrValueFromProperty(i, ValueProperty)).AsQueryable().Cast(pi.PropertyType);
|
||||
internalValue = selectedItems.Select(i => GetItemOrValueFromProperty(i, ValueProperty)).AsQueryable().Cast(pi.PropertyType);
|
||||
}
|
||||
else
|
||||
{
|
||||
var firstElement = Data.Cast<object>().FirstOrDefault();
|
||||
var elementType = firstElement != null ? firstElement.GetType() : null;
|
||||
var query = Data.AsQueryable();
|
||||
var elementType = query.ElementType;
|
||||
|
||||
if (elementType == typeof(object) && typeof(EnumerableQuery).IsAssignableFrom(query.GetType()) && query.Any())
|
||||
{
|
||||
elementType = query.FirstOrDefault().GetType();
|
||||
}
|
||||
|
||||
if (elementType != null)
|
||||
{
|
||||
internalValue = selectedItems.AsQueryable().Cast(elementType);
|
||||
@@ -879,32 +1120,107 @@ namespace Radzen
|
||||
}
|
||||
if (raiseChange)
|
||||
{
|
||||
await ValueChanged.InvokeAsync(object.Equals(internalValue, null) ? default(T) : (T)internalValue);
|
||||
if (ValueChanged.HasDelegate)
|
||||
{
|
||||
if (typeof(IList).IsAssignableFrom(typeof(T)))
|
||||
{
|
||||
if (object.Equals(internalValue, null))
|
||||
{
|
||||
await ValueChanged.InvokeAsync(default(T));
|
||||
}
|
||||
else
|
||||
{
|
||||
var list = (IList)Activator.CreateInstance(typeof(T));
|
||||
foreach (var i in (IEnumerable)internalValue)
|
||||
{
|
||||
list.Add(i);
|
||||
}
|
||||
await ValueChanged.InvokeAsync((T)(object)list);
|
||||
}
|
||||
}
|
||||
else if (typeof(T).IsGenericType && typeof(ICollection<>).MakeGenericType(typeof(T).GetGenericArguments()[0]).IsAssignableFrom(typeof(T)))
|
||||
{
|
||||
if (object.Equals(internalValue, null))
|
||||
{
|
||||
await ValueChanged.InvokeAsync(default(T));
|
||||
}
|
||||
else
|
||||
{
|
||||
var list = (IList)Activator.CreateInstance(typeof(List<>).MakeGenericType(typeof(T).GetGenericArguments()[0]));
|
||||
foreach (var i in (IEnumerable)internalValue)
|
||||
{
|
||||
list.Add(i);
|
||||
}
|
||||
await ValueChanged.InvokeAsync((T)(object)list);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
await ValueChanged.InvokeAsync(object.Equals(internalValue, null) ? default(T) : (T)internalValue);
|
||||
}
|
||||
}
|
||||
|
||||
if (FieldIdentifier.FieldName != null) { EditContext?.NotifyFieldChanged(FieldIdentifier); }
|
||||
|
||||
await Change.InvokeAsync(internalValue);
|
||||
}
|
||||
StateHasChanged();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override object GetValue()
|
||||
{
|
||||
return internalValue;
|
||||
}
|
||||
|
||||
internal void UpdateSelectedItems(object item)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(ValueProperty))
|
||||
{
|
||||
var value = GetItemOrValueFromProperty(item, ValueProperty);
|
||||
|
||||
if (!IsItemSelectedByValue(value))
|
||||
{
|
||||
selectedItems.Add(item);
|
||||
}
|
||||
else
|
||||
{
|
||||
selectedItems = selectedItems.AsQueryable().Where($@"!object.Equals(it.{ValueProperty},@0)", value).ToList();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!selectedItems.Any(i => object.Equals(i, item)))
|
||||
{
|
||||
selectedItems.Add(item);
|
||||
}
|
||||
else
|
||||
{
|
||||
selectedItems = selectedItems.Where(i => !object.Equals(i, item)).ToList();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Selects the item from value.
|
||||
/// </summary>
|
||||
/// <param name="value">The value.</param>
|
||||
protected virtual void SelectItemFromValue(object value)
|
||||
{
|
||||
if (value != null && View != null)
|
||||
var view = LoadData.HasDelegate ? Data : View;
|
||||
if (value != null && view != null)
|
||||
{
|
||||
if (!Multiple)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(ValueProperty))
|
||||
{
|
||||
if (typeof(EnumerableQuery).IsAssignableFrom(View.GetType()))
|
||||
if (typeof(EnumerableQuery).IsAssignableFrom(view.GetType()))
|
||||
{
|
||||
SelectedItem = View.OfType<object>().Where(i => object.Equals(PropertyAccess.GetValue(i, ValueProperty), value)).FirstOrDefault();
|
||||
SelectedItem = view.OfType<object>().Where(i => object.Equals(GetItemOrValueFromProperty(i, ValueProperty), value)).FirstOrDefault();
|
||||
}
|
||||
else
|
||||
{
|
||||
SelectedItem = View.AsQueryable().Where($@"{ValueProperty} == @0", value).FirstOrDefault();
|
||||
SelectedItem = view.AsQueryable().Where($@"{ValueProperty} == @0", value).FirstOrDefault();
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -918,25 +1234,25 @@ namespace Radzen
|
||||
}
|
||||
else
|
||||
{
|
||||
var values = value as dynamic;
|
||||
var values = value as IEnumerable;
|
||||
if (values != null)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(ValueProperty))
|
||||
{
|
||||
foreach (object v in values)
|
||||
foreach (object v in values.ToDynamicList())
|
||||
{
|
||||
dynamic item;
|
||||
|
||||
if (typeof(EnumerableQuery).IsAssignableFrom(View.GetType()))
|
||||
if (typeof(EnumerableQuery).IsAssignableFrom(view.GetType()))
|
||||
{
|
||||
item = View.OfType<object>().Where(i => object.Equals(PropertyAccess.GetValue(i, ValueProperty), v)).FirstOrDefault();
|
||||
item = view.OfType<object>().Where(i => object.Equals(GetItemOrValueFromProperty(i, ValueProperty), v)).FirstOrDefault();
|
||||
}
|
||||
else
|
||||
{
|
||||
item = View.AsQueryable().Where($@"{ValueProperty} == @0", v).FirstOrDefault();
|
||||
item = view.AsQueryable().Where($@"{ValueProperty} == @0", v).FirstOrDefault();
|
||||
}
|
||||
|
||||
if (!object.Equals(item, null) && selectedItems.IndexOf(item) == -1)
|
||||
if (!object.Equals(item, null) && !selectedItems.AsQueryable().Where($@"object.Equals(it.{ValueProperty},@0)", v).Any())
|
||||
{
|
||||
selectedItems.Add(item);
|
||||
}
|
||||
@@ -956,6 +1272,21 @@ namespace Radzen
|
||||
}
|
||||
}
|
||||
|
||||
internal bool IsItemSelectedByValue(object v)
|
||||
{
|
||||
switch (internalValue)
|
||||
{
|
||||
case string s:
|
||||
return object.Equals(s, v);
|
||||
case IEnumerable enumerable:
|
||||
return enumerable.Cast<object>().Contains(v);
|
||||
case null:
|
||||
return false;
|
||||
default:
|
||||
return object.Equals(internalValue, v);
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void Dispose()
|
||||
{
|
||||
|
||||
69
Radzen.Blazor/Extensions.cs
Normal file
69
Radzen.Blazor/Extensions.cs
Normal file
@@ -0,0 +1,69 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Reflection.Emit;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Xml.Linq;
|
||||
|
||||
namespace Radzen.Blazor
|
||||
{
|
||||
/// <summary>
|
||||
/// Class EnumExtensions.
|
||||
/// </summary>
|
||||
public static class EnumExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets enum description.
|
||||
/// </summary>
|
||||
public static string GetDisplayDescription(this Enum enumValue)
|
||||
{
|
||||
var enumValueAsString = enumValue.ToString();
|
||||
var val = enumValue.GetType().GetMember(enumValueAsString).FirstOrDefault();
|
||||
|
||||
return val?.GetCustomAttribute<DisplayAttribute>()?.GetDescription() ?? enumValueAsString;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts Enum to IEnumerable of Value/Text.
|
||||
/// </summary>
|
||||
public static IEnumerable<object> EnumAsKeyValuePair(Type enumType)
|
||||
{
|
||||
return Enum.GetValues(enumType).Cast<Enum>().Distinct().Select(val => new { Value = Convert.ToInt32(val), Text = val.GetDisplayDescription() });
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts the autocomplete type enum value to the expected
|
||||
/// autocomplete attribute value.
|
||||
/// </summary>
|
||||
/// <returns>The autocomplete attribute string value.</returns>
|
||||
public static string GetAutoCompleteValue(this AutoCompleteType typeValue)
|
||||
{
|
||||
// Handle synonyms.
|
||||
switch (typeValue)
|
||||
{
|
||||
case AutoCompleteType.FirstName:
|
||||
return "given-name";
|
||||
case AutoCompleteType.LastName:
|
||||
return "family-name";
|
||||
case AutoCompleteType.MiddleName:
|
||||
return "additional-name";
|
||||
case AutoCompleteType.ZipCode:
|
||||
return "postal-code";
|
||||
case AutoCompleteType.Province:
|
||||
return "address-level1";
|
||||
case AutoCompleteType.State:
|
||||
return "address-level1";
|
||||
}
|
||||
|
||||
// Handle standard values.
|
||||
var value = typeValue.ToString();
|
||||
value = Regex.Replace(value, "([^A-Z])([A-Z])", "$1-$2");
|
||||
return Regex.Replace(value, "([A-Z]+)([A-Z][^A-Z$])", "$1-$2")
|
||||
.Trim().ToLower();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Components;
|
||||
using Microsoft.AspNetCore.Components.Forms;
|
||||
using Microsoft.AspNetCore.Components.Web;
|
||||
using Radzen.Blazor;
|
||||
using Radzen.Blazor.Rendering;
|
||||
|
||||
namespace Radzen
|
||||
@@ -72,11 +73,8 @@ namespace Radzen
|
||||
}
|
||||
set
|
||||
{
|
||||
if (_form != value && value != null)
|
||||
{
|
||||
_form = value;
|
||||
_form.AddComponent(this);
|
||||
}
|
||||
_form = value;
|
||||
_form?.AddComponent(this);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -165,6 +163,8 @@ namespace Radzen
|
||||
/// <returns>Task.</returns>
|
||||
public override Task SetParametersAsync(ParameterView parameters)
|
||||
{
|
||||
var disabledChanged = parameters.DidParameterChange(nameof(Disabled), Disabled);
|
||||
|
||||
var result = base.SetParametersAsync(parameters);
|
||||
|
||||
if (EditContext != null && ValueExpression != null && FieldIdentifier.Model != EditContext.Model)
|
||||
@@ -174,6 +174,11 @@ namespace Radzen
|
||||
EditContext.OnValidationStateChanged += ValidationStateChanged;
|
||||
}
|
||||
|
||||
if (disabledChanged)
|
||||
{
|
||||
FormFieldContext?.DisabledChanged(Disabled);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -233,6 +238,21 @@ namespace Radzen
|
||||
/// <returns>ClassList.</returns>
|
||||
protected ClassList GetClassList(string className) => ClassList.Create(className)
|
||||
.AddDisabled(Disabled)
|
||||
.Add(FieldIdentifier, EditContext);
|
||||
.Add(FieldIdentifier, EditContext)
|
||||
.Add("rz-state-empty", !HasValue);
|
||||
|
||||
/// <summary> Provides support for RadzenFormField integration. </summary>
|
||||
[CascadingParameter]
|
||||
public IFormFieldContext FormFieldContext { get; set; }
|
||||
|
||||
/// <summary> Gets the current placeholder. Returns empty string if this component is inside a RadzenFormField.</summary>
|
||||
protected string CurrentPlaceholder => FormFieldContext != null ? " " : Placeholder;
|
||||
#if NET5_0_OR_GREATER
|
||||
/// <inheritdoc/>
|
||||
public virtual async ValueTask FocusAsync()
|
||||
{
|
||||
await Element.FocusAsync();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Components;
|
||||
using Radzen.Blazor.Rendering;
|
||||
|
||||
namespace Radzen.Blazor
|
||||
{
|
||||
@@ -40,13 +44,21 @@ namespace Radzen.Blazor
|
||||
/// <returns>RenderFragment.</returns>
|
||||
RenderFragment Render(ScaleBase categoryScale, ScaleBase valueScale);
|
||||
/// <summary>
|
||||
/// Renders the series overlays with the specified category and value scales.
|
||||
/// </summary>
|
||||
/// <param name="categoryScale">The category scale.</param>
|
||||
/// <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);
|
||||
RenderFragment RenderTooltip(object data, double marginLeft, double marginTop, double chartHeight);
|
||||
/// <summary>
|
||||
/// Renders the legend item.
|
||||
/// </summary>
|
||||
@@ -85,7 +97,35 @@ namespace Radzen.Blazor
|
||||
/// </summary>
|
||||
/// <param name="x">The x.</param>
|
||||
/// <param name="y">The y.</param>
|
||||
object DataAt(double x, double y);
|
||||
(object, Point) DataAt(double x, double y);
|
||||
/// <summary>
|
||||
/// Returns data chart position
|
||||
/// </summary>
|
||||
IEnumerable<ChartDataLabel> GetDataLabels(double offsetX, double offsetY);
|
||||
/// <summary>
|
||||
/// Returns series median
|
||||
/// </summary>
|
||||
double GetMedian();
|
||||
/// <summary>
|
||||
/// Returns series mean
|
||||
/// </summary>
|
||||
double GetMean();
|
||||
/// <summary>
|
||||
/// Returns series mode
|
||||
/// </summary>
|
||||
double GetMode();
|
||||
/// <summary>
|
||||
/// Returns series trend
|
||||
/// </summary>
|
||||
(double a, double b) GetTrend();
|
||||
/// <summary>
|
||||
/// Series coordinate system
|
||||
/// </summary>
|
||||
CoordinateSystem CoordinateSystem { get; }
|
||||
/// <summary>
|
||||
/// Series overlays
|
||||
/// </summary>
|
||||
IList<IChartSeriesOverlay> Overlays{ get; }
|
||||
/// <summary>
|
||||
/// Gets or sets the title of the series. The title is displayed in tooltips and the legend.
|
||||
/// </summary>
|
||||
|
||||
33
Radzen.Blazor/IChartSeriesOverlay.cs
Normal file
33
Radzen.Blazor/IChartSeriesOverlay.cs
Normal file
@@ -0,0 +1,33 @@
|
||||
using Microsoft.AspNetCore.Components;
|
||||
|
||||
namespace Radzen.Blazor
|
||||
{
|
||||
/// <summary>
|
||||
/// Interface for chart overlays
|
||||
/// </summary>
|
||||
public interface IChartSeriesOverlay
|
||||
{
|
||||
/// <summary>
|
||||
/// Render overlay
|
||||
/// </summary>
|
||||
/// <param name="categoryScale"></param>
|
||||
/// <param name="valueScale"></param>
|
||||
/// <returns>RenderFragment</returns>
|
||||
RenderFragment Render(ScaleBase categoryScale, ScaleBase valueScale);
|
||||
|
||||
/// <summary>
|
||||
/// Gets overlay visibility state
|
||||
/// </summary>
|
||||
bool Visible { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Hit test
|
||||
/// </summary>
|
||||
bool Contains(double mouseX, double mouseY, int tolerance);
|
||||
|
||||
/// <summary>
|
||||
/// Renders tooltip
|
||||
/// </summary>
|
||||
RenderFragment RenderTooltip(double mouseX, double mouseY, double marginLeft, double marginTop);
|
||||
}
|
||||
}
|
||||
20
Radzen.Blazor/IChartStackedBarSeries.cs
Normal file
20
Radzen.Blazor/IChartStackedBarSeries.cs
Normal file
@@ -0,0 +1,20 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Radzen.Blazor
|
||||
{
|
||||
/// <summary>
|
||||
/// Marker interface for <see cref="RadzenStackedBarSeries{TItem}" />.
|
||||
/// </summary>
|
||||
public interface IChartStackedBarSeries : IChartBarSeries
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the value at the specified index.
|
||||
/// </summary>
|
||||
double ValueAt(int index);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the values for category.
|
||||
/// </summary>
|
||||
IEnumerable<double> ValuesForCategory(double category);
|
||||
}
|
||||
}
|
||||
26
Radzen.Blazor/IChartStackedColumnSeries.cs
Normal file
26
Radzen.Blazor/IChartStackedColumnSeries.cs
Normal file
@@ -0,0 +1,26 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Radzen.Blazor
|
||||
{
|
||||
/// <summary>
|
||||
/// Marker interface for <see cref="RadzenStackedColumnSeries{TItem}" />.
|
||||
/// </summary>
|
||||
public interface IChartStackedColumnSeries
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the count.
|
||||
/// </summary>
|
||||
/// <value>The count.</value>
|
||||
int Count { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the values for category.
|
||||
/// </summary>
|
||||
IEnumerable<double> ValuesForCategory(double category);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the value at the specified index.
|
||||
/// </summary>
|
||||
double ValueAt(int index);
|
||||
}
|
||||
}
|
||||
@@ -59,6 +59,20 @@ namespace Radzen.Blazor
|
||||
/// <param name="end">The end.</param>
|
||||
Task SelectSlot(DateTime start, DateTime end);
|
||||
/// <summary>
|
||||
/// Selects the specified slot.
|
||||
/// </summary>
|
||||
/// <param name="start">The start.</param>
|
||||
/// <param name="end">The end.</param>
|
||||
/// <param name="appointments">The appointments for this range.</param>
|
||||
Task<bool> SelectSlot(DateTime start, DateTime end, IEnumerable<AppointmentData> appointments);
|
||||
/// <summary>
|
||||
/// Selects the specified more link.
|
||||
/// </summary>
|
||||
/// <param name="start">The start.</param>
|
||||
/// <param name="end">The end.</param>
|
||||
/// <param name="appointments">The appointments for this range.</param>
|
||||
Task<bool> SelectMore(DateTime start, DateTime end, IEnumerable<AppointmentData> appointments);
|
||||
/// <summary>
|
||||
/// Gets the appointment HTML attributes.
|
||||
/// </summary>
|
||||
/// <param name="item">The appointment.</param>
|
||||
|
||||
22
Radzen.Blazor/Interpolation.cs
Normal file
22
Radzen.Blazor/Interpolation.cs
Normal file
@@ -0,0 +1,22 @@
|
||||
namespace Radzen.Blazor
|
||||
{
|
||||
/// <summary>
|
||||
/// Specifies the interpolation mode of lines between data points. Used by <see cref="RadzenAreaSeries{TItem}"/> and <see cref="RadzenLineSeries{TItem}"/>.
|
||||
/// </summary>
|
||||
public enum Interpolation
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// Points are connected by a straight line.
|
||||
/// </summary>
|
||||
Line,
|
||||
/// <summary>
|
||||
/// Points are connected by a smooth curve.
|
||||
/// </summary>
|
||||
Spline,
|
||||
/// <summary>
|
||||
/// Points are connected by horizontal and vertical lines only.
|
||||
/// </summary>
|
||||
Step
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2018-2022 Radzen Ltd
|
||||
Copyright (c) 2018-2023 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
|
||||
|
||||
@@ -65,7 +65,13 @@ namespace Radzen.Blazor
|
||||
if (start == end)
|
||||
{
|
||||
start = 0;
|
||||
end = end + NiceNumber(end / ticks, false);
|
||||
end += NiceNumber(end / ticks, false);
|
||||
}
|
||||
|
||||
if (Round && end < 0)
|
||||
{
|
||||
end = 0;
|
||||
start += NiceNumber(start / ticks, false);
|
||||
}
|
||||
|
||||
var range = end - start;
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
using System;
|
||||
using Microsoft.AspNetCore.Components;
|
||||
using Radzen.Blazor;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Text;
|
||||
@@ -35,7 +37,11 @@ namespace Radzen
|
||||
Severity = message.Severity,
|
||||
Summary = message.Summary,
|
||||
Detail = message.Detail,
|
||||
Style = message.Style
|
||||
Style = message.Style,
|
||||
Click = message.Click,
|
||||
Close = message.Close,
|
||||
CloseOnClick = message.CloseOnClick,
|
||||
Payload = message.Payload
|
||||
};
|
||||
|
||||
if (!Messages.Contains(newMessage))
|
||||
@@ -51,14 +57,22 @@ namespace Radzen
|
||||
/// <param name="summary">The summary.</param>
|
||||
/// <param name="detail">The detail.</param>
|
||||
/// <param name="duration">The duration.</param>
|
||||
public void Notify(NotificationSeverity severity = NotificationSeverity.Info, string summary = "", string detail = "", double duration = 3000)
|
||||
/// <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>
|
||||
public void Notify(NotificationSeverity severity = NotificationSeverity.Info, string summary = "", string detail = "", double duration = 3000, Action<NotificationMessage> click = null, bool closeOnClick = false, object payload = null, Action<NotificationMessage> close = null)
|
||||
{
|
||||
var newMessage = new NotificationMessage()
|
||||
{
|
||||
Duration = duration,
|
||||
Severity = severity,
|
||||
Summary = summary,
|
||||
Detail = detail
|
||||
Detail = detail,
|
||||
Click = click,
|
||||
Close = close,
|
||||
CloseOnClick = closeOnClick,
|
||||
Payload = payload
|
||||
};
|
||||
|
||||
if (!Messages.Contains(newMessage))
|
||||
@@ -98,5 +112,24 @@ namespace Radzen
|
||||
/// </summary>
|
||||
/// <value>The style.</value>
|
||||
public string Style { get; set; }
|
||||
}
|
||||
/// <summary>
|
||||
/// 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; }
|
||||
/// <summary>
|
||||
/// Get or set the event for when the notification is closed
|
||||
/// </summary>
|
||||
public Action<NotificationMessage> Close { get; set; }
|
||||
/// <summary>
|
||||
/// Gets or sets click on close action.
|
||||
/// </summary>
|
||||
/// <value>If true, then the notification will be closed when clicked on.</value>
|
||||
public bool CloseOnClick { get; set; }
|
||||
/// <summary>
|
||||
/// Gets or sets notification payload.
|
||||
/// </summary>
|
||||
/// <value>Used to store a custom payload that can be retreived later in the click event handler.</value>
|
||||
public object Payload { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ using System.Collections.Generic;
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
using System.Web;
|
||||
using System.Globalization;
|
||||
|
||||
namespace Radzen
|
||||
{
|
||||
@@ -211,7 +212,7 @@ namespace Radzen
|
||||
/// <param name="options">The options.</param>
|
||||
public override void Write(Utf8JsonWriter writer, DateTime value, JsonSerializerOptions options)
|
||||
{
|
||||
writer.WriteStringValue(value.ToString("yyyy-MM-ddTHH:mm:ss.fffZ"));
|
||||
writer.WriteStringValue(value.ToString("yyyy-MM-ddTHH:mm:ss.fffZ", CultureInfo.InvariantCulture));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Specialized;
|
||||
using System.Linq;
|
||||
using System.Linq.Dynamic.Core;
|
||||
using System.Threading.Tasks;
|
||||
@@ -35,6 +36,12 @@ namespace Radzen
|
||||
[Parameter]
|
||||
public HorizontalAlign PagerHorizontalAlign { get; set; } = HorizontalAlign.Justify;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating pager density.
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
public Density Density { get; set; } = Density.Default;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether paging is allowed. Set to <c>false</c> by default.
|
||||
/// </summary>
|
||||
@@ -56,10 +63,24 @@ namespace Radzen
|
||||
}
|
||||
set
|
||||
{
|
||||
_PageSize = value;
|
||||
if (_PageSize != value)
|
||||
{
|
||||
_PageSize = value;
|
||||
InvokeAsync(() => OnPageSizeChanged(value));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal int GetPageSize()
|
||||
{
|
||||
return _PageSize;
|
||||
}
|
||||
|
||||
internal void SetPageSize(int value)
|
||||
{
|
||||
_PageSize = value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the page numbers count.
|
||||
/// </summary>
|
||||
@@ -86,6 +107,13 @@ namespace Radzen
|
||||
[Parameter]
|
||||
public RenderFragment<T> Template { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the loading template.
|
||||
/// </summary>
|
||||
/// <value>The loading template.</value>
|
||||
[Parameter]
|
||||
public RenderFragment LoadingTemplate { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The data
|
||||
/// </summary>
|
||||
@@ -107,12 +135,37 @@ namespace Radzen
|
||||
if (_data != value)
|
||||
{
|
||||
_data = value;
|
||||
|
||||
if (_data != null && _data is INotifyCollectionChanged)
|
||||
{
|
||||
((INotifyCollectionChanged)_data).CollectionChanged += OnCollectionChanged;
|
||||
}
|
||||
|
||||
OnDataChanged();
|
||||
StateHasChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called when INotifyCollectionChanged CollectionChanged is raised.
|
||||
/// </summary>
|
||||
protected virtual void OnCollectionChanged(object sender, NotifyCollectionChangedEventArgs args)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void Dispose()
|
||||
{
|
||||
base.Dispose();
|
||||
|
||||
if (_data != null && _data is INotifyCollectionChanged)
|
||||
{
|
||||
((INotifyCollectionChanged)_data).CollectionChanged -= OnCollectionChanged;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the page size options.
|
||||
/// </summary>
|
||||
@@ -142,9 +195,66 @@ namespace Radzen
|
||||
public string PagingSummaryFormat { get; set; } = "Page {0} of {1} ({2} items)";
|
||||
|
||||
/// <summary>
|
||||
/// The view
|
||||
/// Gets or sets the pager's first page button's title attribute.
|
||||
/// </summary>
|
||||
protected IQueryable<T> _view = null;
|
||||
[Parameter]
|
||||
public string FirstPageTitle { get; set; } = "First page.";
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the pager's first page button's aria-label attribute.
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
public string FirstPageAriaLabel { get; set; } = "Go to first page.";
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the pager's previous page button's title attribute.
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
public string PrevPageTitle { get; set; } = "Previous page";
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the pager's previous page button's aria-label attribute.
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
public string PrevPageAriaLabel { get; set; } = "Go to previous page.";
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the pager's last page button's title attribute.
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
public string LastPageTitle { get; set; } = "Last page";
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the pager's last page button's aria-label attribute.
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
public string LastPageAriaLabel { get; set; } = "Go to last page.";
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the pager's next page button's title attribute.
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
public string NextPageTitle { get; set; } = "Next page";
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the pager's next page button's aria-label attribute.
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
public string NextPageAriaLabel { get; set; } = "Go to next page.";
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the pager's numeric page number buttons' title attributes.
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
public string PageTitleFormat { get; set; } = "Page {0}";
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the pager's numeric page number buttons' aria-label attributes.
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
public string PageAriaLabelFormat { get; set; } = "Go to page {0}.";
|
||||
|
||||
internal IQueryable<T> _view = null;
|
||||
/// <summary>
|
||||
/// Gets the paged view.
|
||||
/// </summary>
|
||||
@@ -259,7 +369,10 @@ namespace Radzen
|
||||
{
|
||||
this.firstRender = firstRender;
|
||||
|
||||
await ReloadOnFirstRender();
|
||||
if (firstRender)
|
||||
{
|
||||
await ReloadOnFirstRender();
|
||||
}
|
||||
|
||||
await base.OnAfterRenderAsync(firstRender);
|
||||
}
|
||||
@@ -308,16 +421,19 @@ namespace Radzen
|
||||
await InvokeAsync(Reload);
|
||||
}
|
||||
|
||||
int? pageSize;
|
||||
internal int? pageSize;
|
||||
|
||||
/// <summary>
|
||||
/// Called when [page size changed].
|
||||
/// </summary>
|
||||
/// <param name="value">The value.</param>
|
||||
protected async Task OnPageSizeChanged(int value)
|
||||
protected virtual async Task OnPageSizeChanged(int value)
|
||||
{
|
||||
pageSize = value;
|
||||
await InvokeAsync(Reload);
|
||||
if (pageSize != value && !this.firstRender)
|
||||
{
|
||||
pageSize = value;
|
||||
await InvokeAsync(Reload);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -342,16 +458,17 @@ namespace Radzen
|
||||
/// Goes to page.
|
||||
/// </summary>
|
||||
/// <param name="page">The page.</param>
|
||||
public async Task GoToPage(int page)
|
||||
/// <param name="forceReload">if set to <c>true</c> [force reload].</param>
|
||||
public async Task GoToPage(int page, bool forceReload = false)
|
||||
{
|
||||
if (topPager != null)
|
||||
{
|
||||
await topPager.GoToPage(page);
|
||||
await topPager.GoToPage(page, forceReload);
|
||||
}
|
||||
|
||||
if (bottomPager != null)
|
||||
{
|
||||
await bottomPager.GoToPage(page);
|
||||
await bottomPager.GoToPage(page, forceReload);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -361,14 +478,21 @@ namespace Radzen
|
||||
/// <param name="forceReload">if set to <c>true</c> [force reload].</param>
|
||||
public async Task FirstPage(bool forceReload = false)
|
||||
{
|
||||
var shouldReload = forceReload && CurrentPage == 0;
|
||||
|
||||
if (topPager != null)
|
||||
{
|
||||
await topPager.FirstPage(forceReload);
|
||||
await topPager.FirstPage();
|
||||
}
|
||||
|
||||
if (bottomPager != null)
|
||||
{
|
||||
await bottomPager.FirstPage(forceReload);
|
||||
await bottomPager.FirstPage();
|
||||
}
|
||||
|
||||
if (shouldReload)
|
||||
{
|
||||
await InvokeAsync(Reload);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Linq.Dynamic.Core;
|
||||
|
||||
@@ -44,8 +45,13 @@ namespace Radzen
|
||||
{FilterOperator.EndsWith, "EndsWith"},
|
||||
{FilterOperator.Contains, "Contains"},
|
||||
{FilterOperator.DoesNotContain, "DoesNotContain"},
|
||||
{FilterOperator.In, "In"},
|
||||
{FilterOperator.NotIn, "NotIn"},
|
||||
{FilterOperator.IsNull, "=="},
|
||||
{FilterOperator.IsNotNull, "!="}
|
||||
{FilterOperator.IsEmpty, "=="},
|
||||
{FilterOperator.IsNotNull, "!="},
|
||||
{FilterOperator.IsNotEmpty, "!="},
|
||||
{FilterOperator.Custom, ""}
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
@@ -64,7 +70,12 @@ namespace Radzen
|
||||
{FilterOperator.Contains, "contains"},
|
||||
{FilterOperator.DoesNotContain, "DoesNotContain"},
|
||||
{FilterOperator.IsNull, "eq"},
|
||||
{FilterOperator.IsNotNull, "ne"}
|
||||
{FilterOperator.IsEmpty, "eq"},
|
||||
{FilterOperator.IsNotNull, "ne"},
|
||||
{FilterOperator.IsNotEmpty, "ne"},
|
||||
{FilterOperator.In, "in"},
|
||||
{FilterOperator.NotIn, "in"},
|
||||
{FilterOperator.Custom, ""}
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
@@ -140,8 +151,10 @@ namespace Radzen
|
||||
public static string ToFilterString<T>(this IEnumerable<RadzenDataGridColumn<T>> columns)
|
||||
{
|
||||
Func<RadzenDataGridColumn<T>, bool> canFilter = (c) => c.Filterable && c.FilterPropertyType != null &&
|
||||
(!(c.GetFilterValue() == null || c.GetFilterValue() as string == string.Empty) || c.GetFilterOperator() == FilterOperator.IsNotNull || c.GetFilterOperator() == FilterOperator.IsNull)
|
||||
&& c.GetFilterProperty() != null;
|
||||
(!(c.GetFilterValue() == null || c.GetFilterValue() as string == string.Empty) || c.GetFilterOperator() == FilterOperator.IsNotNull
|
||||
|| c.GetFilterOperator() == FilterOperator.IsNull || c.GetFilterOperator() == FilterOperator.IsEmpty
|
||||
|| c.GetFilterOperator() == FilterOperator.IsNotEmpty)
|
||||
&& c.GetFilterProperty() != null;
|
||||
|
||||
if (columns.Where(canFilter).Any())
|
||||
{
|
||||
@@ -161,11 +174,11 @@ namespace Radzen
|
||||
{
|
||||
if (v != null)
|
||||
{
|
||||
value = v is DateTime ? ((DateTime)v).ToString("yyyy-MM-ddTHH:mm:ss.fffZ") : v is DateTimeOffset ? ((DateTimeOffset)v).UtcDateTime.ToString("yyyy-MM-ddTHH:mm:ss.fffZ") : "";
|
||||
value = v is DateTime ? ((DateTime)v).ToString("yyyy-MM-ddTHH:mm:ss.fffZ", CultureInfo.InvariantCulture) : v is DateTimeOffset ? ((DateTimeOffset)v).UtcDateTime.ToString("yyyy-MM-ddTHH:mm:ss.fffZ", CultureInfo.InvariantCulture) : "";
|
||||
}
|
||||
if (sv != null)
|
||||
{
|
||||
secondValue = sv is DateTime ? ((DateTime)sv).ToString("yyyy-MM-ddTHH:mm:ss.fffZ") : sv is DateTimeOffset ? ((DateTimeOffset)sv).UtcDateTime.ToString("yyyy-MM-ddTHH:mm:ss.fffZ") : "";
|
||||
secondValue = sv is DateTime ? ((DateTime)sv).ToString("yyyy-MM-ddTHH:mm:ss.fffZ", CultureInfo.InvariantCulture) : sv is DateTimeOffset ? ((DateTimeOffset)sv).UtcDateTime.ToString("yyyy-MM-ddTHH:mm:ss.fffZ", CultureInfo.InvariantCulture) : "";
|
||||
}
|
||||
}
|
||||
else if (PropertyAccess.IsEnum(column.FilterPropertyType) || PropertyAccess.IsNullableEnum(column.FilterPropertyType))
|
||||
@@ -179,12 +192,12 @@ namespace Radzen
|
||||
secondValue = ((int)sv).ToString();
|
||||
}
|
||||
}
|
||||
else if (typeof(IEnumerable).IsAssignableFrom(column.FilterPropertyType) && column.FilterPropertyType != typeof(string))
|
||||
else if (IsEnumerable(column.FilterPropertyType) && column.FilterPropertyType != typeof(string))
|
||||
{
|
||||
var enumerableValue = ((IEnumerable)(v != null ? v : Enumerable.Empty<object>())).AsQueryable();
|
||||
var enumerableSecondValue = ((IEnumerable)(sv != null ? sv : Enumerable.Empty<object>())).AsQueryable();
|
||||
|
||||
var enumerableValueAsString = "new []{" + String.Join(",",
|
||||
var enumerableValueAsString = "new []{" + String.Join(",",
|
||||
(enumerableValue.ElementType == typeof(string) ? enumerableValue.Cast<string>().Select(i => $@"""{i}""").Cast<object>() : enumerableValue.Cast<object>())) + "}";
|
||||
|
||||
var enumerableSecondValueAsString = "new []{" + String.Join(",",
|
||||
@@ -228,11 +241,14 @@ namespace Radzen
|
||||
}
|
||||
else
|
||||
{
|
||||
value = (string)Convert.ChangeType(column.GetFilterValue(), typeof(string));
|
||||
secondValue = (string)Convert.ChangeType(column.GetSecondFilterValue(), typeof(string));
|
||||
value = (string)Convert.ChangeType(column.GetFilterValue(), typeof(string), CultureInfo.InvariantCulture);
|
||||
secondValue = (string)Convert.ChangeType(column.GetSecondFilterValue(), typeof(string), CultureInfo.InvariantCulture);
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(value) || column.GetFilterOperator() == FilterOperator.IsNotNull || column.GetFilterOperator() == FilterOperator.IsNull)
|
||||
if (!string.IsNullOrEmpty(value) || column.GetFilterOperator() == FilterOperator.IsNotNull
|
||||
|| column.GetFilterOperator() == FilterOperator.IsNull
|
||||
|| column.GetFilterOperator() == FilterOperator.IsEmpty
|
||||
|| column.GetFilterOperator() == FilterOperator.IsNotEmpty)
|
||||
{
|
||||
var linqOperator = LinqFilterOperators[column.GetFilterOperator()];
|
||||
if (linqOperator == null)
|
||||
@@ -288,8 +304,9 @@ namespace Radzen
|
||||
linqOperator = "==";
|
||||
}
|
||||
|
||||
var value = !second ? (string)Convert.ChangeType(column.FilterValue, typeof(string)) :
|
||||
var value = !second ? (string)Convert.ChangeType(column.FilterValue, typeof(string)) :
|
||||
(string)Convert.ChangeType(column.SecondFilterValue, typeof(string));
|
||||
value = value?.Replace("\"", "\\\"");
|
||||
|
||||
var columnType = column.Type;
|
||||
var columnFormat = column.Format;
|
||||
@@ -300,11 +317,11 @@ namespace Radzen
|
||||
|
||||
if (columnFormat == "date-time" || columnFormat == "date")
|
||||
{
|
||||
var dateTimeValue = DateTime.Parse(value, null, System.Globalization.DateTimeStyles.RoundtripKind);
|
||||
var dateTimeValue = DateTime.Parse(value, CultureInfo.InvariantCulture, System.Globalization.DateTimeStyles.RoundtripKind);
|
||||
var finalDate = dateTimeValue.TimeOfDay == TimeSpan.Zero ? dateTimeValue.Date : dateTimeValue;
|
||||
var dateFormat = dateTimeValue.TimeOfDay == TimeSpan.Zero ? "yyyy-MM-dd" : "yyyy-MM-ddTHH:mm:ssZ";
|
||||
var dateFormat = dateTimeValue.TimeOfDay == TimeSpan.Zero ? "yyyy-MM-dd" : "yyyy-MM-ddTHH:mm:ss.fffZ";
|
||||
|
||||
return $@"{property} {linqOperator} DateTime(""{finalDate.ToString(dateFormat)}"")";
|
||||
return $@"{property} {linqOperator} DateTime(""{finalDate.ToString(dateFormat, CultureInfo.InvariantCulture)}"")";
|
||||
}
|
||||
else if (columnFormat == "time")
|
||||
{
|
||||
@@ -370,6 +387,11 @@ namespace Radzen
|
||||
|
||||
var columnFilterOperator = !second ? column.GetFilterOperator() : column.GetSecondFilterOperator();
|
||||
|
||||
if (columnFilterOperator == FilterOperator.Custom)
|
||||
{
|
||||
return "";
|
||||
}
|
||||
|
||||
var linqOperator = LinqFilterOperators[columnFilterOperator];
|
||||
if (linqOperator == null)
|
||||
{
|
||||
@@ -379,7 +401,8 @@ namespace Radzen
|
||||
if (column.FilterPropertyType == typeof(string))
|
||||
{
|
||||
string filterCaseSensitivityOperator = column.Grid.FilterCaseSensitivity == FilterCaseSensitivity.CaseInsensitive ? ".ToLower()" : "";
|
||||
|
||||
value = value?.Replace("\"", "\\\"");
|
||||
|
||||
if (!string.IsNullOrEmpty(value) && columnFilterOperator == FilterOperator.Contains)
|
||||
{
|
||||
return $@"({property} == null ? """" : {property}){filterCaseSensitivityOperator}.Contains(""{value}""{filterCaseSensitivityOperator})";
|
||||
@@ -408,6 +431,14 @@ namespace Radzen
|
||||
{
|
||||
return $@"np({property}) == null";
|
||||
}
|
||||
else if (columnFilterOperator == FilterOperator.IsEmpty)
|
||||
{
|
||||
return $@"np({property}) == """"";
|
||||
}
|
||||
else if (columnFilterOperator == FilterOperator.IsNotEmpty)
|
||||
{
|
||||
return $@"np({property}) != """"";
|
||||
}
|
||||
else if (columnFilterOperator == FilterOperator.IsNotNull)
|
||||
{
|
||||
return $@"np({property}) != null";
|
||||
@@ -415,32 +446,40 @@ namespace Radzen
|
||||
}
|
||||
else if (PropertyAccess.IsNumeric(column.FilterPropertyType))
|
||||
{
|
||||
if (column.GetFilterOperator() == FilterOperator.IsNull || column.GetFilterOperator() == FilterOperator.IsNotNull)
|
||||
if (columnFilterOperator == FilterOperator.IsNull || columnFilterOperator == FilterOperator.IsNotNull)
|
||||
{
|
||||
return $"{property} {linqOperator} null";
|
||||
}
|
||||
else if (columnFilterOperator == FilterOperator.IsEmpty || columnFilterOperator == FilterOperator.IsNotEmpty)
|
||||
{
|
||||
return $@"{property} {linqOperator} """"";
|
||||
}
|
||||
else
|
||||
{
|
||||
return $"{property} {linqOperator} {value}";
|
||||
}
|
||||
}
|
||||
else if (column.FilterPropertyType == typeof(DateTime) ||
|
||||
else if (column.FilterPropertyType == typeof(DateTime) ||
|
||||
column.FilterPropertyType == typeof(DateTime?) ||
|
||||
column.FilterPropertyType == typeof(DateTimeOffset) ||
|
||||
column.FilterPropertyType == typeof(DateTimeOffset) ||
|
||||
column.FilterPropertyType == typeof(DateTimeOffset?))
|
||||
{
|
||||
if (column.GetFilterOperator() == FilterOperator.IsNull || column.GetFilterOperator() == FilterOperator.IsNotNull)
|
||||
if (columnFilterOperator == FilterOperator.IsNull || columnFilterOperator == FilterOperator.IsNotNull)
|
||||
{
|
||||
return $"{property} {linqOperator} null";
|
||||
}
|
||||
else if (columnFilterOperator == FilterOperator.IsEmpty || columnFilterOperator == FilterOperator.IsNotEmpty)
|
||||
{
|
||||
return $@"{property} {linqOperator} """"";
|
||||
}
|
||||
else
|
||||
{
|
||||
var dateTimeValue = DateTime.Parse(value, null, System.Globalization.DateTimeStyles.RoundtripKind);
|
||||
var dateTimeValue = DateTime.Parse(value, CultureInfo.InvariantCulture, System.Globalization.DateTimeStyles.RoundtripKind);
|
||||
var finalDate = dateTimeValue.TimeOfDay == TimeSpan.Zero ? dateTimeValue.Date : dateTimeValue;
|
||||
var dateFormat = dateTimeValue.TimeOfDay == TimeSpan.Zero ? "yyyy-MM-dd" : "yyyy-MM-ddTHH:mm:ssZ";
|
||||
var dateFormat = dateTimeValue.TimeOfDay == TimeSpan.Zero ? "yyyy-MM-dd" : "yyyy-MM-ddTHH:mm:ss.fffZ";
|
||||
var dateFunction = column.FilterPropertyType == typeof(DateTimeOffset) || column.FilterPropertyType == typeof(DateTimeOffset?) ? "DateTimeOffset" : "DateTime";
|
||||
|
||||
return $@"{property} {linqOperator} {dateFunction}(""{finalDate.ToString(dateFormat)}"")";
|
||||
return $@"{property} {linqOperator} {dateFunction}(""{finalDate.ToString(dateFormat, CultureInfo.InvariantCulture)}"")";
|
||||
}
|
||||
}
|
||||
else if (column.FilterPropertyType == typeof(bool) || column.FilterPropertyType == typeof(bool?))
|
||||
@@ -449,10 +488,14 @@ namespace Radzen
|
||||
}
|
||||
else if (column.FilterPropertyType == typeof(Guid) || column.FilterPropertyType == typeof(Guid?))
|
||||
{
|
||||
if (column.GetFilterOperator() == FilterOperator.IsNull || column.GetFilterOperator() == FilterOperator.IsNotNull)
|
||||
if (columnFilterOperator == FilterOperator.IsNull || columnFilterOperator == FilterOperator.IsNotNull)
|
||||
{
|
||||
return $"{property} {linqOperator} null";
|
||||
}
|
||||
else if (columnFilterOperator == FilterOperator.IsEmpty || columnFilterOperator == FilterOperator.IsNotEmpty)
|
||||
{
|
||||
return $@"{property} {linqOperator} """"";
|
||||
}
|
||||
else
|
||||
{
|
||||
return $@"{property} {linqOperator} Guid(""{value}"")";
|
||||
@@ -490,7 +533,7 @@ namespace Radzen
|
||||
{
|
||||
if (columnFormat == "date-time" || columnFormat == "date")
|
||||
{
|
||||
return $"{property} {columnFilterOperator} {DateTime.Parse(value, null, System.Globalization.DateTimeStyles.RoundtripKind).ToString("yyyy-MM-ddTHH:mm:ss.fffZ")}";
|
||||
return $"{property} {columnFilterOperator} {DateTime.Parse(value, CultureInfo.InvariantCulture, System.Globalization.DateTimeStyles.RoundtripKind).ToString("yyyy-MM-ddTHH:mm:ss.fffZ", CultureInfo.InvariantCulture)}";
|
||||
}
|
||||
else if (columnFormat == "time")
|
||||
{
|
||||
@@ -502,8 +545,8 @@ namespace Radzen
|
||||
}
|
||||
else if (!string.IsNullOrEmpty(value) && columnFilterOperator == "contains")
|
||||
{
|
||||
return column.Grid.FilterCaseSensitivity == FilterCaseSensitivity.CaseInsensitive ?
|
||||
$"contains({property}, tolower('{value}'))" :
|
||||
return column.Grid.FilterCaseSensitivity == FilterCaseSensitivity.CaseInsensitive ?
|
||||
$"contains({property}, tolower('{value}'))" :
|
||||
$"contains({property}, '{value}')";
|
||||
}
|
||||
else if (!string.IsNullOrEmpty(value) && columnFilterOperator == "DoesNotContain")
|
||||
@@ -514,14 +557,14 @@ namespace Radzen
|
||||
}
|
||||
else if (!string.IsNullOrEmpty(value) && columnFilterOperator == "startswith")
|
||||
{
|
||||
return column.Grid.FilterCaseSensitivity == FilterCaseSensitivity.CaseInsensitive ?
|
||||
return column.Grid.FilterCaseSensitivity == FilterCaseSensitivity.CaseInsensitive ?
|
||||
$"startswith({property}, tolower('{value}'))" :
|
||||
$"startswith({property}, '{value}')";
|
||||
}
|
||||
else if (!string.IsNullOrEmpty(value) && columnFilterOperator == "endswith")
|
||||
{
|
||||
return column.Grid.FilterCaseSensitivity == FilterCaseSensitivity.CaseInsensitive ?
|
||||
$"endswith({property}, tolower('{value}'))" :
|
||||
$"endswith({property}, tolower('{value}'))" :
|
||||
$"endswith({property}, '{value}')";
|
||||
}
|
||||
else if (!string.IsNullOrEmpty(value) && columnFilterOperator == "eq")
|
||||
@@ -554,25 +597,29 @@ namespace Radzen
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="column">The column.</param>
|
||||
/// <param name="second">if set to <c>true</c> [second].</param>
|
||||
/// <param name="filterValue">The specific value to filter by</param>
|
||||
/// <param name="columnFilterOperator">The operator used to compare to <paramref name="filterValue"/></param>
|
||||
/// <returns>System.String.</returns>
|
||||
private static string GetColumnODataFilter<T>(RadzenDataGridColumn<T> column, bool second = false)
|
||||
internal static string GetColumnODataFilter<T>(RadzenDataGridColumn<T> column, object filterValue, FilterOperator columnFilterOperator)
|
||||
{
|
||||
var property = column.GetFilterProperty().Replace('.', '/');
|
||||
|
||||
var columnFilterOperator = !second ? column.GetFilterOperator() : column.GetSecondFilterOperator();
|
||||
var odataFilterOperator = ODataFilterOperators[columnFilterOperator];
|
||||
|
||||
var value = typeof(IEnumerable).IsAssignableFrom(column.FilterPropertyType) && column.FilterPropertyType != typeof(string) ? null :
|
||||
!second ? (string)Convert.ChangeType(column.GetFilterValue(), typeof(string)) :
|
||||
(string)Convert.ChangeType(column.GetSecondFilterValue(), typeof(string));
|
||||
var value = IsEnumerable(column.FilterPropertyType) && column.FilterPropertyType != typeof(string)
|
||||
? null
|
||||
: (string)Convert.ChangeType(filterValue, typeof(string), CultureInfo.InvariantCulture);
|
||||
|
||||
if (column.Grid.FilterCaseSensitivity == FilterCaseSensitivity.CaseInsensitive && column.FilterPropertyType == typeof(string))
|
||||
{
|
||||
property = $"tolower({property})";
|
||||
}
|
||||
|
||||
if (column.FilterPropertyType == typeof(string))
|
||||
if (PropertyAccess.IsEnum(column.FilterPropertyType) || PropertyAccess.IsNullableEnum(column.FilterPropertyType))
|
||||
{
|
||||
return $"{property} {odataFilterOperator} '{value}'";
|
||||
}
|
||||
else if (column.FilterPropertyType == typeof(string))
|
||||
{
|
||||
if (!string.IsNullOrEmpty(value) && columnFilterOperator == FilterOperator.Contains)
|
||||
{
|
||||
@@ -614,16 +661,22 @@ namespace Radzen
|
||||
{
|
||||
return $"{property} {odataFilterOperator} null";
|
||||
}
|
||||
else if (columnFilterOperator == FilterOperator.IsEmpty || columnFilterOperator == FilterOperator.IsNotEmpty)
|
||||
{
|
||||
return $"{property} {odataFilterOperator} ''";
|
||||
}
|
||||
}
|
||||
else if (typeof(IEnumerable).IsAssignableFrom(column.FilterPropertyType) && column.FilterPropertyType != typeof(string))
|
||||
else if (IsEnumerable(column.FilterPropertyType) && column.FilterPropertyType != typeof(string))
|
||||
{
|
||||
var v = !second ? column.GetFilterValue() : column.GetSecondFilterValue();
|
||||
|
||||
var enumerableValue = ((IEnumerable)(v != null ? v : Enumerable.Empty<object>())).AsQueryable();
|
||||
var enumerableValue = ((IEnumerable)(filterValue != null ? filterValue : Enumerable.Empty<object>())).AsQueryable();
|
||||
|
||||
var enumerableValueAsString = "(" + String.Join(",",
|
||||
(enumerableValue.ElementType == typeof(string) ? enumerableValue.Cast<string>().Select(i => $@"'{i}'").Cast<object>() : enumerableValue.Cast<object>())) + ")";
|
||||
|
||||
var enumerableValueAsStringOrForAny = String.Join(" or ",
|
||||
(enumerableValue.ElementType == typeof(string) ? enumerableValue.Cast<string>()
|
||||
.Select(i => $@"i/{property} eq '{i}'").Cast<object>() : enumerableValue.Cast<object>().Select(i => $@"i/{property} eq {i}").Cast<object>()));
|
||||
|
||||
if (enumerableValue.Any() && columnFilterOperator == FilterOperator.Contains)
|
||||
{
|
||||
return $"{property} in {enumerableValueAsString}";
|
||||
@@ -632,6 +685,14 @@ namespace Radzen
|
||||
{
|
||||
return $"not({property} in {enumerableValueAsString})";
|
||||
}
|
||||
else if (enumerableValue.Any() && columnFilterOperator == FilterOperator.In)
|
||||
{
|
||||
return $"{column.Property}/any(i:{enumerableValueAsStringOrForAny})";
|
||||
}
|
||||
else if (enumerableValue.Any() && columnFilterOperator == FilterOperator.NotIn)
|
||||
{
|
||||
return $"not({column.Property}/any(i: {enumerableValueAsStringOrForAny}))";
|
||||
}
|
||||
}
|
||||
else if (PropertyAccess.IsNumeric(column.FilterPropertyType))
|
||||
{
|
||||
@@ -643,6 +704,10 @@ namespace Radzen
|
||||
{
|
||||
return $"{property} {odataFilterOperator} null";
|
||||
}
|
||||
else if (columnFilterOperator == FilterOperator.IsEmpty || columnFilterOperator == FilterOperator.IsNotEmpty)
|
||||
{
|
||||
return $"{property} {odataFilterOperator} ''";
|
||||
}
|
||||
else
|
||||
{
|
||||
return $"{property} eq {value.ToLower()}";
|
||||
@@ -657,9 +722,13 @@ namespace Radzen
|
||||
{
|
||||
return $"{property} {odataFilterOperator} null";
|
||||
}
|
||||
else if (columnFilterOperator == FilterOperator.IsEmpty || columnFilterOperator == FilterOperator.IsNotEmpty)
|
||||
{
|
||||
return $"{property} {odataFilterOperator} ''";
|
||||
}
|
||||
else
|
||||
{
|
||||
return $"{property} {odataFilterOperator} {DateTime.Parse(value, null, System.Globalization.DateTimeStyles.RoundtripKind).ToString("yyyy-MM-ddTHH:mm:ss.fffZ")}";
|
||||
return $"{property} {odataFilterOperator} {DateTime.Parse(value, CultureInfo.InvariantCulture, System.Globalization.DateTimeStyles.RoundtripKind).ToString("yyyy-MM-ddTHH:mm:ss.fffZ", CultureInfo.InvariantCulture)}";
|
||||
}
|
||||
}
|
||||
else if (column.FilterPropertyType == typeof(Guid) || column.FilterPropertyType == typeof(Guid?))
|
||||
@@ -733,8 +802,10 @@ namespace Radzen
|
||||
public static string ToODataFilterString<T>(this IEnumerable<RadzenDataGridColumn<T>> columns)
|
||||
{
|
||||
Func<RadzenDataGridColumn<T>, bool> canFilter = (c) => c.Filterable && c.FilterPropertyType != null &&
|
||||
(!(c.GetFilterValue() == null || c.GetFilterValue() as string == string.Empty) || c.GetFilterOperator() == FilterOperator.IsNotNull || c.GetFilterOperator() == FilterOperator.IsNull)
|
||||
&& c.GetFilterProperty() != null;
|
||||
(!(c.GetFilterValue() == null || c.GetFilterValue() as string == string.Empty)
|
||||
|| c.GetFilterOperator() == FilterOperator.IsNotNull || c.GetFilterOperator() == FilterOperator.IsNull
|
||||
|| c.GetFilterOperator() == FilterOperator.IsEmpty || c.GetFilterOperator() == FilterOperator.IsNotEmpty)
|
||||
&& c.GetFilterProperty() != null;
|
||||
|
||||
if (columns.Where(canFilter).Any())
|
||||
{
|
||||
@@ -749,7 +820,8 @@ namespace Radzen
|
||||
var value = column.GetFilterValue();
|
||||
var secondValue = column.GetSecondFilterValue();
|
||||
|
||||
if (value != null || column.GetFilterOperator() == FilterOperator.IsNotNull || column.GetFilterOperator() == FilterOperator.IsNull)
|
||||
if (value != null || column.GetFilterOperator() == FilterOperator.IsNotNull || column.GetFilterOperator() == FilterOperator.IsNull
|
||||
|| column.GetFilterOperator() == FilterOperator.IsEmpty || column.GetFilterOperator() == FilterOperator.IsNotEmpty)
|
||||
{
|
||||
var linqOperator = ODataFilterOperators[column.GetFilterOperator()];
|
||||
if (linqOperator == null)
|
||||
@@ -761,11 +833,11 @@ namespace Radzen
|
||||
|
||||
if (secondValue == null)
|
||||
{
|
||||
whereList.Add(GetColumnODataFilter(column));
|
||||
whereList.Add(column.GetColumnODataFilter());
|
||||
}
|
||||
else
|
||||
{
|
||||
whereList.Add($"({GetColumnODataFilter(column)} {booleanOperator} {GetColumnODataFilter(column, true)})");
|
||||
{
|
||||
whereList.Add($"({column.GetColumnODataFilter()} {booleanOperator} {column.GetColumnODataFilter(second: true)})");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -834,7 +906,7 @@ namespace Radzen
|
||||
index++;
|
||||
}
|
||||
}
|
||||
else
|
||||
else
|
||||
{
|
||||
var firstFilter = comparison == "StartsWith" || comparison == "EndsWith" || comparison == "Contains" ?
|
||||
$@"{property}{filterCaseSensitivityOperator}.{comparison}(@{index}{filterCaseSensitivityOperator})" :
|
||||
@@ -859,6 +931,14 @@ namespace Radzen
|
||||
return source;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets if type is IEnumerable.
|
||||
/// </summary>
|
||||
public static bool IsEnumerable(Type type)
|
||||
{
|
||||
return typeof(IEnumerable).IsAssignableFrom(type) || typeof(IEnumerable<>).IsAssignableFrom(type);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Wheres the specified columns.
|
||||
/// </summary>
|
||||
@@ -869,8 +949,10 @@ namespace Radzen
|
||||
public static IQueryable<T> Where<T>(this IQueryable<T> source, IEnumerable<RadzenDataGridColumn<T>> columns)
|
||||
{
|
||||
Func<RadzenDataGridColumn<T>, bool> canFilter = (c) => c.Filterable && c.FilterPropertyType != null &&
|
||||
(!(c.GetFilterValue() == null || c.GetFilterValue() as string == string.Empty) || c.GetFilterOperator() == FilterOperator.IsNotNull || c.GetFilterOperator() == FilterOperator.IsNull)
|
||||
&& c.GetFilterProperty() != null;
|
||||
(!(c.GetFilterValue() == null || c.GetFilterValue() as string == string.Empty)
|
||||
|| c.GetFilterOperator() == FilterOperator.IsNotNull || c.GetFilterOperator() == FilterOperator.IsNull
|
||||
|| c.GetFilterOperator() == FilterOperator.IsEmpty || c.GetFilterOperator() == FilterOperator.IsNotEmpty)
|
||||
&& c.GetFilterProperty() != null;
|
||||
|
||||
if (columns.Where(canFilter).Any())
|
||||
{
|
||||
@@ -888,14 +970,18 @@ namespace Radzen
|
||||
property = $"({property})";
|
||||
}
|
||||
|
||||
if (column.FilterPropertyType == typeof(string) && !(column.GetFilterOperator() == FilterOperator.IsNotNull || column.GetFilterOperator() == FilterOperator.IsNull))
|
||||
if (column.FilterPropertyType == typeof(string) &&
|
||||
!(column.GetFilterOperator() == FilterOperator.IsNotNull || column.GetFilterOperator() == FilterOperator.IsNull
|
||||
|| column.GetFilterOperator() == FilterOperator.IsEmpty || column.GetFilterOperator() == FilterOperator.IsNotEmpty))
|
||||
{
|
||||
property = $@"({property} == null ? """" : {property})";
|
||||
}
|
||||
|
||||
string filterCaseSensitivityOperator = column.FilterPropertyType == typeof(string)
|
||||
&& column.GetFilterOperator() != FilterOperator.IsNotNull && column.GetFilterOperator() != FilterOperator.IsNull &&
|
||||
column.Grid.FilterCaseSensitivity == FilterCaseSensitivity.CaseInsensitive ? ".ToLower()" : "";
|
||||
string filterCaseSensitivityOperator = column.FilterPropertyType == typeof(string)
|
||||
&& column.GetFilterOperator() != FilterOperator.IsNotNull && column.GetFilterOperator() != FilterOperator.IsNull
|
||||
&& column.GetFilterOperator() != FilterOperator.IsEmpty && column.GetFilterOperator() != FilterOperator.IsNotEmpty
|
||||
&& column.Grid.FilterCaseSensitivity == FilterCaseSensitivity.CaseInsensitive ? ".ToLower()" : "";
|
||||
|
||||
|
||||
var comparison = LinqFilterOperators[column.GetFilterOperator()];
|
||||
|
||||
@@ -905,7 +991,7 @@ namespace Radzen
|
||||
{
|
||||
if (comparison == "StartsWith" || comparison == "EndsWith" || comparison == "Contains")
|
||||
{
|
||||
if (typeof(IEnumerable).IsAssignableFrom(column.FilterPropertyType) && column.FilterPropertyType != typeof(string) && comparison == "Contains")
|
||||
if (IsEnumerable(column.FilterPropertyType) && column.FilterPropertyType != typeof(string) && comparison == "Contains")
|
||||
{
|
||||
whereList.Add($@"(@{index}).Contains({property})", new object[] { column.GetFilterValue() });
|
||||
}
|
||||
@@ -913,12 +999,12 @@ namespace Radzen
|
||||
{
|
||||
whereList.Add($@"{property}{filterCaseSensitivityOperator}.{comparison}(@{index}{filterCaseSensitivityOperator})", new object[] { column.GetFilterValue() });
|
||||
}
|
||||
|
||||
|
||||
index++;
|
||||
}
|
||||
else if (comparison == "DoesNotContain")
|
||||
{
|
||||
if (typeof(IEnumerable).IsAssignableFrom(column.FilterPropertyType) && column.FilterPropertyType != typeof(string) && comparison == "DoesNotContain")
|
||||
if (IsEnumerable(column.FilterPropertyType) && column.FilterPropertyType != typeof(string) && comparison == "DoesNotContain")
|
||||
{
|
||||
whereList.Add($@"!(@{index}).Contains({property})", new object[] { column.GetFilterValue() });
|
||||
}
|
||||
@@ -926,10 +1012,25 @@ namespace Radzen
|
||||
{
|
||||
whereList.Add($@"!{property}{filterCaseSensitivityOperator}.Contains(@{index}{filterCaseSensitivityOperator})", new object[] { column.GetFilterValue() });
|
||||
}
|
||||
|
||||
|
||||
index++;
|
||||
}
|
||||
else
|
||||
else if (comparison == "In" || comparison == "NotIn")
|
||||
{
|
||||
if (IsEnumerable(column.FilterPropertyType) && column.FilterPropertyType != typeof(string) &&
|
||||
IsEnumerable(column.PropertyType) && column.PropertyType != typeof(string))
|
||||
{
|
||||
whereList.Add($@"{(comparison == "NotIn" ? "!" : "")}{property}.Any(i => i in @{index})", new object[] { column.GetFilterValue() });
|
||||
index++;
|
||||
}
|
||||
else if (IsEnumerable(column.FilterPropertyType) && column.FilterPropertyType != typeof(string) &&
|
||||
column.Property != column.FilterProperty && !string.IsNullOrEmpty(column.FilterProperty))
|
||||
{
|
||||
whereList.Add($@"{(comparison == "NotIn" ? "!" : "")}{column.Property}.Any(i => i.{column.FilterProperty} in @{index})", new object[] { column.GetFilterValue() });
|
||||
index++;
|
||||
}
|
||||
}
|
||||
else if (!(IsEnumerable(column.FilterPropertyType) && column.FilterPropertyType != typeof(string)))
|
||||
{
|
||||
whereList.Add($@"{property}{filterCaseSensitivityOperator} {comparison} @{index}{filterCaseSensitivityOperator}", new object[] { column.GetFilterValue() });
|
||||
index++;
|
||||
@@ -939,8 +1040,8 @@ namespace Radzen
|
||||
{
|
||||
var secondComparison = LinqFilterOperators[column.GetSecondFilterOperator()];
|
||||
|
||||
if (typeof(IEnumerable).IsAssignableFrom(column.FilterPropertyType) && column.FilterPropertyType != typeof(string) &&
|
||||
(comparison == "Contains" || comparison == "DoesNotContain") &&
|
||||
if (IsEnumerable(column.FilterPropertyType) && column.FilterPropertyType != typeof(string) &&
|
||||
(comparison == "Contains" || comparison == "DoesNotContain") &&
|
||||
(secondComparison == "Contains" || secondComparison == "DoesNotContain"))
|
||||
{
|
||||
var firstFilter = $@"{(comparison == "DoesNotContain" ? "!" : "")}(@{index}).Contains({property})";
|
||||
@@ -970,12 +1071,294 @@ namespace Radzen
|
||||
}
|
||||
}
|
||||
|
||||
return source.Where(string.Join($" {gridBooleanOperator} ", whereList.Keys), whereList.Values.SelectMany(i => i.ToArray()).ToArray());
|
||||
return whereList.Keys.Any() ?
|
||||
source.Where(string.Join($" {gridBooleanOperator} ", whereList.Keys), whereList.Values.SelectMany(i => i.ToArray()).ToArray())
|
||||
: source;
|
||||
}
|
||||
|
||||
return source;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Wheres the specified filters.
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="source">The source.</param>
|
||||
/// <param name="dataFilter">The DataFilter.</param>
|
||||
/// <returns>IQueryable<T>.</returns>
|
||||
public static IQueryable<T> Where<T>(this IQueryable<T> source, RadzenDataFilter<T> dataFilter)
|
||||
{
|
||||
Func<CompositeFilterDescriptor, bool> canFilter = (c) => dataFilter.properties.Where(col => col.Property == c.Property).FirstOrDefault()?.FilterPropertyType != null &&
|
||||
(!(c.FilterValue == null || c.FilterValue as string == string.Empty)
|
||||
|| c.FilterOperator == FilterOperator.IsNotNull || c.FilterOperator == FilterOperator.IsNull
|
||||
|| c.FilterOperator == FilterOperator.IsEmpty || c.FilterOperator == FilterOperator.IsNotEmpty)
|
||||
&& c.Property != null;
|
||||
|
||||
if (dataFilter.Filters.Concat(dataFilter.Filters.SelectManyRecursive(i => i.Filters ?? Enumerable.Empty<CompositeFilterDescriptor>())).Where(canFilter).Any())
|
||||
{
|
||||
var index = 0;
|
||||
var filterExpressions = new List<string>();
|
||||
var filterValues = new List<object[]>();
|
||||
|
||||
foreach (var filter in dataFilter.Filters)
|
||||
{
|
||||
AddWhereExpression(canFilter, filter, ref filterExpressions, ref filterValues, ref index, dataFilter);
|
||||
}
|
||||
|
||||
return filterExpressions.Any() ?
|
||||
source.Where(string.Join($" {dataFilter.LogicalFilterOperator.ToString().ToLower()} ", filterExpressions), filterValues.SelectMany(i => i.ToArray()).ToArray())
|
||||
: source;
|
||||
}
|
||||
|
||||
return source;
|
||||
}
|
||||
|
||||
private static void AddWhereExpression<T>(Func<CompositeFilterDescriptor, bool> canFilter, CompositeFilterDescriptor filter, ref List<string> filterExpressions, ref List<object[]> filterValues, ref int index, RadzenDataFilter<T> dataFilter)
|
||||
{
|
||||
if (filter.Filters != null)
|
||||
{
|
||||
var innerFilterExpressions = new List<string>();
|
||||
|
||||
foreach (var f in filter.Filters)
|
||||
{
|
||||
AddWhereExpression(canFilter, f, ref innerFilterExpressions, ref filterValues, ref index, dataFilter);
|
||||
}
|
||||
|
||||
if (innerFilterExpressions.Any())
|
||||
{
|
||||
filterExpressions.Add("(" + string.Join($" {filter.LogicalFilterOperator.ToString().ToLower()} ", innerFilterExpressions) + ")");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (filter.Property == null || (filter.FilterValue == null &&
|
||||
filter.FilterOperator != FilterOperator.IsNull && filter.FilterOperator != FilterOperator.IsNotNull))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var property = PropertyAccess.GetProperty(filter.Property);
|
||||
|
||||
if (property.IndexOf(".") != -1)
|
||||
{
|
||||
property = $"({property})";
|
||||
}
|
||||
|
||||
var column = dataFilter.properties.Where(c => c.Property == filter.Property).FirstOrDefault();
|
||||
if (column == null) return;
|
||||
|
||||
if (column.FilterPropertyType == typeof(string) &&
|
||||
!(filter.FilterOperator == FilterOperator.IsNotNull || filter.FilterOperator == FilterOperator.IsNull
|
||||
|| filter.FilterOperator == FilterOperator.IsEmpty || filter.FilterOperator == FilterOperator.IsNotEmpty))
|
||||
{
|
||||
property = $@"({property} == null ? """" : {property})";
|
||||
}
|
||||
|
||||
string filterCaseSensitivityOperator = column.FilterPropertyType == typeof(string)
|
||||
&& filter.FilterOperator != FilterOperator.IsNotNull && filter.FilterOperator != FilterOperator.IsNull
|
||||
&& filter.FilterOperator != FilterOperator.IsEmpty && filter.FilterOperator != FilterOperator.IsNotEmpty
|
||||
&& dataFilter.FilterCaseSensitivity == FilterCaseSensitivity.CaseInsensitive ? ".ToLower()" : "";
|
||||
|
||||
|
||||
var comparison = LinqFilterOperators[filter.FilterOperator];
|
||||
|
||||
if (comparison == "StartsWith" || comparison == "EndsWith" || comparison == "Contains")
|
||||
{
|
||||
if (column.FilterPropertyType == typeof(string) && filter.FilterValue == null)
|
||||
{
|
||||
filter.FilterValue = "";
|
||||
}
|
||||
|
||||
if (IsEnumerable(column.FilterPropertyType) && column.FilterPropertyType != typeof(string) && comparison == "Contains")
|
||||
{
|
||||
filterExpressions.Add($@"(@{index}).Contains({property})");
|
||||
filterValues.Add(new object[] { filter.FilterValue });
|
||||
}
|
||||
else
|
||||
{
|
||||
filterExpressions.Add($@"{property}{filterCaseSensitivityOperator}.{comparison}(@{index}{filterCaseSensitivityOperator})");
|
||||
filterValues.Add(new object[] { filter.FilterValue });
|
||||
}
|
||||
|
||||
index++;
|
||||
}
|
||||
else if (comparison == "DoesNotContain")
|
||||
{
|
||||
if (column.FilterPropertyType == typeof(string) && filter.FilterValue == null)
|
||||
{
|
||||
filter.FilterValue = "";
|
||||
}
|
||||
|
||||
if (IsEnumerable(column.FilterPropertyType) && column.FilterPropertyType != typeof(string) && comparison == "DoesNotContain")
|
||||
{
|
||||
filterExpressions.Add($@"!(@{index}).Contains({property})");
|
||||
filterValues.Add(new object[] { filter.FilterValue });
|
||||
}
|
||||
else
|
||||
{
|
||||
filterExpressions.Add($@"!{property}{filterCaseSensitivityOperator}.Contains(@{index}{filterCaseSensitivityOperator})");
|
||||
filterValues.Add(new object[] { filter.FilterValue });
|
||||
}
|
||||
|
||||
index++;
|
||||
}
|
||||
else if (!(IsEnumerable(column.FilterPropertyType) && column.FilterPropertyType != typeof(string)))
|
||||
{
|
||||
var value = filter.FilterValue;
|
||||
|
||||
if (column.FilterPropertyType == typeof(DateTimeOffset) || column.FilterPropertyType == typeof(DateTimeOffset?))
|
||||
{
|
||||
value = filter.FilterValue != null ? (object)(new DateTimeOffset((DateTime)filter.FilterValue, TimeSpan.Zero)) : null;
|
||||
}
|
||||
|
||||
filterExpressions.Add($@"{property}{filterCaseSensitivityOperator} {comparison} @{index}{filterCaseSensitivityOperator}");
|
||||
filterValues.Add(new object[] { value });
|
||||
index++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Converts to OData filter expression.
|
||||
/// </summary>
|
||||
/// <param name="dataFilter">The DataFilter.</param>
|
||||
/// <returns>System.String.</returns>
|
||||
public static string ToODataFilterString<T>(this RadzenDataFilter<T> dataFilter)
|
||||
{
|
||||
Func<CompositeFilterDescriptor, bool> canFilter = (c) => dataFilter.properties.Where(col => col.Property == c.Property).FirstOrDefault()?.FilterPropertyType != null &&
|
||||
(!(c.FilterValue == null || c.FilterValue as string == string.Empty)
|
||||
|| c.FilterOperator == FilterOperator.IsNotNull || c.FilterOperator == FilterOperator.IsNull
|
||||
|| c.FilterOperator == FilterOperator.IsEmpty || c.FilterOperator == FilterOperator.IsNotEmpty)
|
||||
&& c.Property != null;
|
||||
|
||||
if (dataFilter.Filters.Concat(dataFilter.Filters.SelectManyRecursive(i => i.Filters ?? Enumerable.Empty<CompositeFilterDescriptor>())).Where(canFilter).Any())
|
||||
{
|
||||
var filterExpressions = new List<string>();
|
||||
|
||||
foreach (var filter in dataFilter.Filters)
|
||||
{
|
||||
AddODataExpression(canFilter, filter, ref filterExpressions, dataFilter);
|
||||
}
|
||||
|
||||
return filterExpressions.Any() ?
|
||||
string.Join($" {dataFilter.LogicalFilterOperator.ToString().ToLower()} ", filterExpressions)
|
||||
: "";
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
private static void AddODataExpression<T>(Func<CompositeFilterDescriptor, bool> canFilter, CompositeFilterDescriptor filter, ref List<string> filterExpressions, RadzenDataFilter<T> dataFilter)
|
||||
{
|
||||
if (filter.Filters != null)
|
||||
{
|
||||
var innerFilterExpressions = new List<string>();
|
||||
|
||||
foreach (var f in filter.Filters)
|
||||
{
|
||||
AddODataExpression(canFilter, f, ref innerFilterExpressions, dataFilter);
|
||||
}
|
||||
|
||||
if (innerFilterExpressions.Any())
|
||||
{
|
||||
filterExpressions.Add("(" + string.Join($" {filter.LogicalFilterOperator.ToString().ToLower()} ", innerFilterExpressions) + ")");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (filter.Property == null || (filter.FilterValue == null &&
|
||||
filter.FilterOperator != FilterOperator.IsNull && filter.FilterOperator != FilterOperator.IsNotNull))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var property = filter.Property.Replace('.', '/');
|
||||
|
||||
var column = dataFilter.properties.Where(c => c.Property == filter.Property).FirstOrDefault();
|
||||
if (column == null) return;
|
||||
|
||||
if (dataFilter.FilterCaseSensitivity == FilterCaseSensitivity.CaseInsensitive && column.FilterPropertyType == typeof(string))
|
||||
{
|
||||
property = $"tolower({property})";
|
||||
}
|
||||
|
||||
if (filter.FilterOperator == FilterOperator.StartsWith || filter.FilterOperator == FilterOperator.EndsWith
|
||||
|| filter.FilterOperator == FilterOperator.Contains || filter.FilterOperator == FilterOperator.DoesNotContain)
|
||||
{
|
||||
if (IsEnumerable(column.FilterPropertyType) && column.FilterPropertyType != typeof(string) &&
|
||||
(filter.FilterOperator == FilterOperator.Contains || filter.FilterOperator == FilterOperator.DoesNotContain))
|
||||
{
|
||||
var enumerableValue = ((IEnumerable)(filter.FilterValue != null ? filter.FilterValue : Enumerable.Empty<object>())).AsQueryable();
|
||||
var firstItemType = enumerableValue.Any() ? enumerableValue.FirstOrDefault().GetType() : typeof(object);
|
||||
|
||||
var enumerableValueAsString = "(" + String.Join(",",
|
||||
(enumerableValue.ElementType == typeof(string) || firstItemType == typeof(string) ? enumerableValue.Cast<string>().Select(i => $@"'{i}'").Cast<object>() : enumerableValue.Cast<object>())) + ")";
|
||||
|
||||
if (enumerableValue.Any() && filter.FilterOperator == FilterOperator.Contains)
|
||||
{
|
||||
filterExpressions.Add($"{property} in {enumerableValueAsString}");
|
||||
}
|
||||
else if (enumerableValue.Any() && filter.FilterOperator == FilterOperator.DoesNotContain)
|
||||
{
|
||||
filterExpressions.Add($"not({property} in {enumerableValueAsString})");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
var expression = dataFilter.FilterCaseSensitivity == FilterCaseSensitivity.CaseInsensitive ?
|
||||
$"{ODataFilterOperators[filter.FilterOperator]}({property}, tolower('{filter.FilterValue}'))" :
|
||||
$"{ODataFilterOperators[filter.FilterOperator]}({property}, '{filter.FilterValue}')";
|
||||
|
||||
if (filter.FilterOperator == FilterOperator.DoesNotContain)
|
||||
{
|
||||
expression = $"not({expression})";
|
||||
}
|
||||
|
||||
filterExpressions.Add(expression);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (IsEnumerable(column.FilterPropertyType) && column.FilterPropertyType != typeof(string))
|
||||
return;
|
||||
|
||||
var value = $"{filter.FilterValue}";
|
||||
|
||||
if (filter.FilterOperator == FilterOperator.IsNull || filter.FilterOperator == FilterOperator.IsNotNull)
|
||||
{
|
||||
value = $"null";
|
||||
}
|
||||
else if (filter.FilterOperator == FilterOperator.IsEmpty || filter.FilterOperator == FilterOperator.IsNotEmpty)
|
||||
{
|
||||
value = $"''";
|
||||
}
|
||||
else if (column.FilterPropertyType == typeof(string) || PropertyAccess.IsEnum(column.FilterPropertyType) || PropertyAccess.IsNullableEnum(column.FilterPropertyType))
|
||||
{
|
||||
value = $"'{value}'";
|
||||
}
|
||||
else if (column.FilterPropertyType == typeof(DateTime) || column.FilterPropertyType == typeof(DateTime?))
|
||||
{
|
||||
try
|
||||
{
|
||||
value = Convert.ToDateTime(filter.FilterValue).ToString(CultureInfo.InvariantCulture);
|
||||
}
|
||||
catch
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
value = $"{DateTime.Parse(value, CultureInfo.InvariantCulture, System.Globalization.DateTimeStyles.RoundtripKind).ToString("yyyy-MM-ddTHH:mm:ss.fffZ", CultureInfo.InvariantCulture)}";
|
||||
}
|
||||
else if (column.FilterPropertyType == typeof(bool) || column.FilterPropertyType == typeof(bool?))
|
||||
{
|
||||
value = $"{value?.ToLower()}";
|
||||
}
|
||||
|
||||
filterExpressions.Add($@"{property} {ODataFilterOperators[filter.FilterOperator]} {value}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Ases the o data enumerable.
|
||||
/// </summary>
|
||||
|
||||
105
Radzen.Blazor/README.md
Normal file
105
Radzen.Blazor/README.md
Normal file
@@ -0,0 +1,105 @@
|
||||
## Radzen Blazor is a set of 70+ free native Blazor UI controls packed with DataGrid, Scheduler, Charts and robust theming including Material design and Fluent UI.
|
||||
|
||||

|
||||
|
||||
## Why choose Radzen Blazor Components?
|
||||
|
||||
### :sparkles: Free
|
||||
|
||||
Radzen Blazor Components are open source and free for commercial use. You can install them from [nuget](https://www.nuget.org/packages/Radzen.Blazor) or build your own copy from source.
|
||||
|
||||
Paid support is available as part of the [Radzen Professional subscription](https://www.radzen.com/blazor-studio/pricing/).
|
||||
|
||||
### :computer: Native
|
||||
|
||||
The components are implemented in C# and take full advantage of the Blazor framework. They do not depend on or wrap existing JavaScript frameworks or libraries.
|
||||
|
||||
Blazor Server and Blazor WebAssembly are fully supported.
|
||||
|
||||
### :seedling: Growing
|
||||
|
||||
We add new components and features on a regular basis.
|
||||
|
||||
Short development cycle. We release as soon as new stuff is available. No more quarterly releases.
|
||||
|
||||
## Support exceeding your expectations
|
||||
|
||||
### :speech_balloon: Community Support
|
||||
Everybody is welcome to visit the [Radzen Community forum](https://forum.radzen.com/). Join the growing community and participate in the discussions!
|
||||
|
||||
### :dart: Dedicated Support
|
||||
|
||||
The Radzen team monitors the forum threads, but does not guarantee a response to every question. For guaranteed responses you may consider the dedicated support option.
|
||||
|
||||
Dedicated support for the Radzen Blazor Components is available as part of the [Radzen Professional subscription](https://www.radzen.com/blazor-studio/pricing/).
|
||||
|
||||
Our flagship product [Radzen Blazor Studio](https://www.radzen.com/blazor-studio/) provides tons of productivity features for Blazor developers:
|
||||
- An industry-leading WYSIWYG Blazor design time canvas
|
||||
- Scaffolding a complete CRUD applications from a database
|
||||
- Built-in security - authentication and authorization
|
||||
- Visual Studio Code and Professional support
|
||||
- Deployment to IIS and Azure
|
||||
- Dedicated support with 24 hour guaranteed response time
|
||||
|
||||
## Get started with Radzen Blazor Components
|
||||
|
||||
### 1. Install
|
||||
|
||||
Radzen Blazor Components are distributed as a [Radzen.Blazor nuget package](https://www.nuget.org/packages/Radzen.Blazor). You can add them to your project in one of the following ways
|
||||
- Install the package from command line by running `dotnet add package Radzen.Blazor`
|
||||
- Add the project from the Visual Nuget Package Manager
|
||||
- Manually edit the .csproj file and add a project reference
|
||||
|
||||
### 2. Import the namespace
|
||||
|
||||
Open the `_Imports.razor` file of your Blazor application and add this line `@using Radzen.Blazor`.
|
||||
|
||||
### 3. Include a theme
|
||||
Radzen Blazor components come with five free themes: Material, Standard, Default, Dark, Software and Humanistic.
|
||||
|
||||
To use a theme
|
||||
1. Pick a theme. The [online demos](https://blazor.radzen.com/colors) allow you to preview the available options via the theme dropdown located in the header. The Material theme is currently selected by default.
|
||||
1. Include the theme CSS file in your Blazor application. Open `Pages\_Layout.cshtml` (Blazor Server .NET 6), `Pages\_Host.cshtml` (Blazor Server .NET 7) or `wwwroot/index.html` (Blazor WebAssembly) and include a theme CSS file by adding this snippet
|
||||
```html
|
||||
<link rel="stylesheet" href="_content/Radzen.Blazor/css/material-base.css">
|
||||
```
|
||||
|
||||
To include a different theme (i.e. Standard) just change the name of the CSS file:
|
||||
```
|
||||
<link rel="stylesheet" href="_content/Radzen.Blazor/css/standard-base.css">
|
||||
```
|
||||
|
||||
### 4. Include Radzen.Blazor.js
|
||||
|
||||
Open `Pages\_Layout.cshtml` (Blazor Server .NET 6), `Pages\_Host.cshtml` (Blazor Server .NET 7) or `wwwroot/index.html` (Blazor WebAssembly) and include this snippet:
|
||||
|
||||
```html
|
||||
<script src="_content/Radzen.Blazor/Radzen.Blazor.js"></script>
|
||||
```
|
||||
|
||||
### 5. Use a component
|
||||
Use any Radzen Blazor component by typing its tag name in a Blazor page e.g.
|
||||
```html
|
||||
<RadzenButton Text="Hi"></RadzenButton>
|
||||
```
|
||||
|
||||
#### Data-binding a property
|
||||
```razor
|
||||
<RadzenButton Text=@text />
|
||||
<RadzenTextBox @bind-Value=@text />
|
||||
@code {
|
||||
string text = "Hi";
|
||||
}
|
||||
```
|
||||
|
||||
#### Handing events
|
||||
|
||||
```razor
|
||||
<RadzenButton Click="@ButtonClicked" Text="Hi"></RadzenButton>
|
||||
@code {
|
||||
void ButtonClicked()
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
```
|
||||
@@ -1,18 +1,19 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk.Razor">
|
||||
<PropertyGroup>
|
||||
<NoWarn>BL9993</NoWarn>
|
||||
<TargetFrameworks>netstandard2.1;net5.0</TargetFrameworks>
|
||||
<NoWarn>BL9993;BL0007;BL0005</NoWarn>
|
||||
<TargetFrameworks>netstandard2.1;net5.0;net6.0;net7.0</TargetFrameworks>
|
||||
<RazorLangVersion>3.0</RazorLangVersion>
|
||||
<LangVersion>7.3</LangVersion>
|
||||
<OutputType>Library</OutputType>
|
||||
<IsPackable>true</IsPackable>
|
||||
<PackageId>Radzen.Blazor</PackageId>
|
||||
<Product>Radzen.Blazor</Product>
|
||||
<Version>3.18.6</Version>
|
||||
<Version>4.20.2</Version>
|
||||
<Copyright>Radzen Ltd.</Copyright>
|
||||
<Authors>Radzen Ltd.</Authors>
|
||||
<Description>Native Blazor UI components by Radzen Ltd.</Description>
|
||||
<PackageTags>blazor blazor-component blazor-grid blazor-datagrid</PackageTags>
|
||||
<Description>Radzen Blazor is a set of 70+ free native Blazor UI controls packed with DataGrid, Scheduler, Charts and robust theming including Material design and Fluent UI.</Description>
|
||||
<PackageTags>blazor material design fluent fluentui components datagrid scheduler charts</PackageTags>
|
||||
<PackageReadmeFile>README.md</PackageReadmeFile>
|
||||
<PackageProjectUrl>https://www.radzen.com</PackageProjectUrl>
|
||||
<PackageIcon>icon.png</PackageIcon>
|
||||
<PackageLicenseFile>LICENSE.txt</PackageLicenseFile>
|
||||
@@ -20,22 +21,24 @@
|
||||
<RepositoryUrl>https://github.com/radzenhq/radzen-blazor</RepositoryUrl>
|
||||
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(TargetFramework)' == 'net5.0'">
|
||||
<DefineConstants>NET5</DefineConstants>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="LibSassBuilder" Version="2.0.1" />
|
||||
<PackageReference Include="DartSassBuilder" Version="1.0.0" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Components" Condition="'$(TargetFramework)' == 'netstandard2.1'" Version="3.1.0" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Components.Web" Condition="'$(TargetFramework)' == 'netstandard2.1'" Version="3.1.0" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Components" Condition="'$(TargetFramework)' == 'net5.0'" Version="5.0.0" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Components.Web" Condition="'$(TargetFramework)' == 'net5.0'" Version="5.0.0" />
|
||||
<PackageReference Include="Microsoft.CSharp" Version="4.7.0" />
|
||||
<PackageReference Include="System.Linq.Dynamic.Core" Version="1.2.12" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Components" Condition="'$(TargetFramework)' == 'net6.0'" Version="6.0.0" />
|
||||
<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.0" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Components.Web" Condition="'$(TargetFramework)' == 'net7.0'" Version="7.0.0" />
|
||||
<PackageReference Include="Microsoft.CSharp" Version="4.7.0" Condition="'$(TargetFramework)' == 'netstandard2.1'" />
|
||||
<PackageReference Include="System.Linq.Dynamic.Core" Version="1.3.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Include="LICENSE.txt" Pack="true" PackagePath="" />
|
||||
<None Include="icon.png" Pack="true" PackagePath="" />
|
||||
<None Include="README.md" Pack="true" PackagePath="\" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
@@ -45,24 +48,24 @@
|
||||
</ItemGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
<LibSassOutputStyle>expanded</LibSassOutputStyle>
|
||||
<EnableDefaultSassItems>false</EnableDefaultSassItems>
|
||||
<DartSassOutputStyle>expanded</DartSassOutputStyle>
|
||||
<EnableDefaultSassItems>false</EnableDefaultSassItems>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Sass Include="$(MSBuildProjectDirectory)/themes/*.scss" Exclude="$(MSBuildProjectDirectory)/themes/_*.scss" Condition="'$(TargetFramework)' == 'net5.0'" />
|
||||
<Sass Include="$(MSBuildProjectDirectory)/themes/*.scss" Exclude="$(MSBuildProjectDirectory)/themes/_*.scss" Condition="'$(TargetFramework)' == 'net6.0'" />
|
||||
</ItemGroup>
|
||||
|
||||
<Target Name="Sass" BeforeTargets="BeforeBuild" Condition="'$(TargetFramework)' == 'net5.0'">
|
||||
<Target Name="Sass" BeforeTargets="BeforeBuild" Condition="'$(TargetFramework)' == 'net6.0'">
|
||||
<PropertyGroup>
|
||||
<_SassFileList>@(Sass->'"%(FullPath)"', ' ')</_SassFileList>
|
||||
<LibSassBuilderArgs>files $(_SassFileList) --outputstyle $(LibSassOutputStyle) --level $(LibSassOutputLevel)</LibSassBuilderArgs>
|
||||
<DartSassBuilderArgs>files $(_SassFileList) --outputstyle $(DartSassOutputStyle) --level $(DartSassOutputLevel)</DartSassBuilderArgs>
|
||||
</PropertyGroup>
|
||||
<Message Text="$(LibSassBuilderArgs)" Importance="$(LibSassMessageLevel)" />
|
||||
<Message Text="Converted SassFile list to argument" Importance="$(LibSassMessageLevel)" />
|
||||
<Message Text="$(DartSassBuilderArgs)" Importance="$(DartSassMessageLevel)" />
|
||||
<Message Text="Converted SassFile list to argument" Importance="$(DartSassMessageLevel)" />
|
||||
</Target>
|
||||
|
||||
<Target Name="MoveCss" AfterTargets="AfterCompile" Condition="'$(TargetFramework)' == 'net5.0'" >
|
||||
<Target Name="MoveCss" AfterTargets="AfterCompile" Condition="'$(TargetFramework)' == 'net6.0'">
|
||||
<ItemGroup>
|
||||
<CssFile Include="$(MSBuildProjectDirectory)/themes/*.css" />
|
||||
</ItemGroup>
|
||||
|
||||
@@ -10,15 +10,15 @@
|
||||
}
|
||||
@if (Visible)
|
||||
{
|
||||
<div @ref="@Element" role="tablist" @attributes="Attributes" class="@GetCssClass()" id="@GetId()">
|
||||
<div @ref="@Element" role="tablist" style=@Style @attributes="Attributes" class="@GetCssClass()" id="@GetId()">
|
||||
@for (var i = 0; i < items.Count; i++)
|
||||
{
|
||||
var item = items[i];
|
||||
var item = items[i];
|
||||
if (!item.Visible)
|
||||
continue;
|
||||
|
||||
<div class="rz-accordion-header" @attributes="item.Attributes" style="@item.Style">
|
||||
<a @onclick="@((args) => SelectItem(item))" href="javascript:void(0)" role="tab" tabindex="0"
|
||||
<div @ref="@item.Element" id="@item.GetItemId()" @attributes="item.Attributes" class="@item.GetItemCssClass()" style="@item.Style">
|
||||
<a @onclick="@((args) => SelectItem(item))" aria-label="@ItemAriaLabel(i, item)" title="@ItemTitle(i, item)" href="javascript:void(0)" role="tab" tabindex="0"
|
||||
id="@($"rz-accordiontab-{items.IndexOf(item)}")" aria-controls="@($"rz-accordiontab-{items.IndexOf(item)}-content")" aria-expanded="true">
|
||||
@if (IsSelected(i, item))
|
||||
{
|
||||
@@ -30,11 +30,11 @@
|
||||
}
|
||||
@if (!string.IsNullOrEmpty(item.Icon))
|
||||
{
|
||||
<i class="rzi">@((MarkupString)item.Icon)</i>
|
||||
<i class="rzi" style="@(!string.IsNullOrEmpty(item.IconColor) ? $"color:{item.IconColor}" : null)">@((MarkupString)item.Icon)</i>
|
||||
}
|
||||
@if (!string.IsNullOrEmpty(item.Text))
|
||||
{
|
||||
<span>@item.Text</span>
|
||||
<span>@((MarkupString)item.Text)</span>
|
||||
}
|
||||
</a>
|
||||
</div>
|
||||
|
||||
@@ -130,6 +130,38 @@ namespace Radzen.Blazor
|
||||
|
||||
List<int> expandedIdexes = new List<int>();
|
||||
|
||||
/// <summary>
|
||||
/// Gets the item's title attribute value.
|
||||
/// </summary>
|
||||
/// <param name="index">The index.</param>
|
||||
/// <param name="item">The item.</param>
|
||||
/// <returns>The item's collapse or expand title value depending on if the item is expanded or collapsed.
|
||||
/// If the relevant title is null or whitespace this method returns "Expand" or "Collapse".</returns>
|
||||
protected string ItemTitle(int index, RadzenAccordionItem item)
|
||||
{
|
||||
if (IsSelected(index, item))
|
||||
{
|
||||
return string.IsNullOrWhiteSpace(item.CollapseTitle) ? "Collapse" : item.CollapseTitle;
|
||||
}
|
||||
return string.IsNullOrWhiteSpace(item.ExpandTitle) ? "Expand" : item.ExpandTitle;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the item's aria-label attribute value.
|
||||
/// </summary>
|
||||
/// <param name="index">The index.</param>
|
||||
/// <param name="item">The item.</param>
|
||||
/// <returns>The item's collapse or expand aria-label value depending on if the item is expanded or collapsed.
|
||||
/// If the relevant aria-label is null or whitespace this method returns "Expand" or "Collapse".</returns>
|
||||
protected string ItemAriaLabel(int index, RadzenAccordionItem item)
|
||||
{
|
||||
if (IsSelected(index, item))
|
||||
{
|
||||
return string.IsNullOrWhiteSpace(item.CollapseAriaLabel) ? "Collapse" : item.CollapseAriaLabel;
|
||||
}
|
||||
return string.IsNullOrWhiteSpace(item.ExpandAriaLabel) ? "Expand" : item.ExpandAriaLabel;
|
||||
}
|
||||
|
||||
internal async System.Threading.Tasks.Task SelectItem(RadzenAccordionItem item)
|
||||
{
|
||||
await CollapseAll(item);
|
||||
|
||||
@@ -22,6 +22,13 @@ namespace Radzen.Blazor
|
||||
[Parameter]
|
||||
public string Icon { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the icon color.
|
||||
/// </summary>
|
||||
/// <value>The icon color.</value>
|
||||
[Parameter]
|
||||
public string IconColor { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether this <see cref="RadzenAccordionItem"/> is selected.
|
||||
/// </summary>
|
||||
@@ -29,14 +36,41 @@ namespace Radzen.Blazor
|
||||
[Parameter]
|
||||
public bool Selected { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the title attribute of the expand button.
|
||||
/// </summary>
|
||||
/// <value>The title attribute value of the expand button.</value>
|
||||
[Parameter]
|
||||
public string ExpandTitle { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the title attribute of the collapse button.
|
||||
/// </summary>
|
||||
/// <value>The title attribute value of the collapse button.</value>
|
||||
[Parameter]
|
||||
public string CollapseTitle { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the aria-label attribute of the expand button.
|
||||
/// </summary>
|
||||
/// <value>The aria-label attribute value of the expand button.</value>
|
||||
[Parameter]
|
||||
public string ExpandAriaLabel { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the aria-label attribute of the collapse button.
|
||||
/// </summary>
|
||||
/// <value>The aria-label attribute value of the collapse button.</value>
|
||||
[Parameter]
|
||||
public string CollapseAriaLabel { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the child content.
|
||||
/// </summary>
|
||||
/// <value>The child content.</value>
|
||||
[Parameter]
|
||||
public RenderFragment ChildContent { get; set; }
|
||||
|
||||
|
||||
|
||||
bool _visible = true;
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether this <see cref="RadzenAccordionItem"/> is visible.
|
||||
@@ -54,7 +88,10 @@ namespace Radzen.Blazor
|
||||
if (_visible != value)
|
||||
{
|
||||
_visible = value;
|
||||
Accordion.Refresh();
|
||||
if (Accordion != null)
|
||||
{
|
||||
Accordion.Refresh();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -106,5 +143,21 @@ namespace Radzen.Blazor
|
||||
|
||||
Accordion?.RemoveItem(this);
|
||||
}
|
||||
|
||||
internal string GetItemId()
|
||||
{
|
||||
return GetId();
|
||||
}
|
||||
|
||||
internal string GetItemCssClass()
|
||||
{
|
||||
return GetCssClass();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override string GetComponentCssClass()
|
||||
{
|
||||
return "rz-accordion-header";
|
||||
}
|
||||
}
|
||||
}
|
||||
89
Radzen.Blazor/RadzenAlert.razor
Normal file
89
Radzen.Blazor/RadzenAlert.razor
Normal file
@@ -0,0 +1,89 @@
|
||||
@inherits RadzenComponentWithChildren
|
||||
@if (GetVisible())
|
||||
{
|
||||
<div @ref="@Element" style="@Style" @attributes="Attributes" class="@GetCssClass()" id="@GetId()" aria-live="polite">
|
||||
<div class="rz-alert-item">
|
||||
@if (ShowIcon)
|
||||
{
|
||||
<RadzenIcon Icon="@getIcon()" IconColor="@IconColor" Class="rz-alert-icon" />
|
||||
}
|
||||
<div class="rz-alert-message">
|
||||
@if (!string.IsNullOrEmpty(Title))
|
||||
{
|
||||
<div class="rz-alert-title">@Title</div>
|
||||
}
|
||||
<div class="rz-alert-content">
|
||||
@if(ChildContent != null)
|
||||
{
|
||||
@ChildContent
|
||||
}
|
||||
else
|
||||
{
|
||||
@Text
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@if (AllowClose)
|
||||
{
|
||||
if (Shade == Shade.Light || Shade == Shade.Lighter)
|
||||
{
|
||||
if (AlertStyle == AlertStyle.Primary)
|
||||
{
|
||||
<RadzenButton Click=@Close Icon="close" Variant="Variant.Text" ButtonStyle="ButtonStyle.Primary" Shade="Shade.Darker" Size="@GetCloseButtonSize()" />
|
||||
}
|
||||
else if (AlertStyle == AlertStyle.Secondary)
|
||||
{
|
||||
<RadzenButton Click=@Close Icon="close" Variant="Variant.Text" ButtonStyle="ButtonStyle.Secondary" Shade="Shade.Darker" Size="@GetCloseButtonSize()" />
|
||||
}
|
||||
else if (AlertStyle == AlertStyle.Light)
|
||||
{
|
||||
<RadzenButton Click=@Close Icon="close" Variant="Variant.Text" ButtonStyle="ButtonStyle.Dark" Shade="Shade.Darker" Size="@GetCloseButtonSize()" />
|
||||
}
|
||||
else if (AlertStyle == AlertStyle.Base)
|
||||
{
|
||||
<RadzenButton Click=@Close Icon="close" Variant="Variant.Text" ButtonStyle="ButtonStyle.Dark" Shade="Shade.Darker" Size="@GetCloseButtonSize()" />
|
||||
}
|
||||
else if (AlertStyle == AlertStyle.Dark)
|
||||
{
|
||||
<RadzenButton Click=@Close Icon="close" Variant="Variant.Text" ButtonStyle="ButtonStyle.Light" Shade="Shade.Darker" Size="@GetCloseButtonSize()" />
|
||||
}
|
||||
else if (AlertStyle == AlertStyle.Success)
|
||||
{
|
||||
<RadzenButton Click=@Close Icon="close" Variant="Variant.Text" ButtonStyle="ButtonStyle.Success" Shade="Shade.Darker" Size="@GetCloseButtonSize()" />
|
||||
}
|
||||
else if (AlertStyle == AlertStyle.Danger)
|
||||
{
|
||||
<RadzenButton Click=@Close Icon="close" Variant="Variant.Text" ButtonStyle="ButtonStyle.Danger" Shade="Shade.Darker" Size="@GetCloseButtonSize()" />
|
||||
}
|
||||
else if (AlertStyle == AlertStyle.Warning)
|
||||
{
|
||||
<RadzenButton Click=@Close Icon="close" Variant="Variant.Text" ButtonStyle="ButtonStyle.Warning" Shade="Shade.Darker" Size="@GetCloseButtonSize()" />
|
||||
}
|
||||
else if (AlertStyle == AlertStyle.Info)
|
||||
{
|
||||
<RadzenButton Click=@Close Icon="close" Variant="Variant.Text" ButtonStyle="ButtonStyle.Info" Shade="Shade.Darker" Size="@GetCloseButtonSize()" />
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (AlertStyle == AlertStyle.Light)
|
||||
{
|
||||
<RadzenButton Click=@Close Icon="close" Variant="Variant.Text" ButtonStyle="ButtonStyle.Dark" Size="@GetCloseButtonSize()" />
|
||||
}
|
||||
else if (AlertStyle == AlertStyle.Base)
|
||||
{
|
||||
<RadzenButton Click=@Close Icon="close" Variant="Variant.Text" ButtonStyle="ButtonStyle.Dark" Size="@GetCloseButtonSize()" />
|
||||
}
|
||||
else if (AlertStyle == AlertStyle.Dark)
|
||||
{
|
||||
<RadzenButton Click=@Close Icon="close" Variant="Variant.Text" ButtonStyle="ButtonStyle.Light" Size="@GetCloseButtonSize()" />
|
||||
}
|
||||
else
|
||||
{
|
||||
<RadzenButton Click=@Close Icon="close" Variant="Variant.Text" ButtonStyle="ButtonStyle.Light" Size="@GetCloseButtonSize()" />
|
||||
}
|
||||
}
|
||||
}
|
||||
</div>
|
||||
}
|
||||
165
Radzen.Blazor/RadzenAlert.razor.cs
Normal file
165
Radzen.Blazor/RadzenAlert.razor.cs
Normal file
@@ -0,0 +1,165 @@
|
||||
using Microsoft.AspNetCore.Components;
|
||||
using Microsoft.AspNetCore.Components.Web;
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Radzen.Blazor
|
||||
{
|
||||
/// <summary>
|
||||
/// RadzenAlert component.
|
||||
/// </summary>
|
||||
/// <example>
|
||||
/// <code>
|
||||
/// <RadzenAlert>
|
||||
/// <ChildContent>
|
||||
/// Content
|
||||
/// </ChildContent>
|
||||
/// </RadzenAlert>
|
||||
/// </code>
|
||||
/// </example>
|
||||
public partial class RadzenAlert : RadzenComponentWithChildren
|
||||
{
|
||||
private string GetAlertSize()
|
||||
{
|
||||
return Size == AlertSize.Medium ? "md" : Size == AlertSize.Large ? "lg" : Size == AlertSize.Small ? "sm" : "xs";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether close is allowed. Set to <c>true</c> by default.
|
||||
/// </summary>
|
||||
/// <value><c>true</c> if close is allowed; otherwise, <c>false</c>.</value>
|
||||
[Parameter]
|
||||
public bool AllowClose { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether icon should be shown. Set to <c>true</c> by default.
|
||||
/// </summary>
|
||||
/// <value><c>true</c> if icon is shown; otherwise, <c>false</c>.</value>
|
||||
[Parameter]
|
||||
public bool ShowIcon { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the title.
|
||||
/// </summary>
|
||||
/// <value>The title.</value>
|
||||
[Parameter]
|
||||
public string Title { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the text of the alert. Overriden by <see cref="RadzenComponentWithChildren.ChildContent" />.
|
||||
/// </summary>
|
||||
/// <value>The title.</value>
|
||||
[Parameter]
|
||||
public string Text { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the icon.
|
||||
/// </summary>
|
||||
/// <value>The icon.</value>
|
||||
[Parameter]
|
||||
public string Icon { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the icon color.
|
||||
/// </summary>
|
||||
/// <value>The icon color.</value>
|
||||
[Parameter]
|
||||
public string IconColor { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the severity.
|
||||
/// </summary>
|
||||
/// <value>The severity.</value>
|
||||
[Parameter]
|
||||
public AlertStyle AlertStyle { get; set; } = AlertStyle.Base;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the design variant of the alert.
|
||||
/// </summary>
|
||||
/// <value>The variant of the alert.</value>
|
||||
[Parameter]
|
||||
public Variant Variant { get; set; } = Variant.Filled;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the color shade of the alert.
|
||||
/// </summary>
|
||||
/// <value>The color shade of the alert.</value>
|
||||
[Parameter]
|
||||
public Shade Shade { get; set; } = Shade.Default;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the size.
|
||||
/// </summary>
|
||||
/// <value>The size.</value>
|
||||
[Parameter]
|
||||
public AlertSize Size { get; set; } = AlertSize.Medium;
|
||||
|
||||
ButtonSize GetCloseButtonSize()
|
||||
{
|
||||
return Size == AlertSize.ExtraSmall ? ButtonSize.ExtraSmall : ButtonSize.Small;
|
||||
}
|
||||
|
||||
bool? visible;
|
||||
bool GetVisible()
|
||||
{
|
||||
return visible ?? Visible;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override string GetComponentCssClass()
|
||||
{
|
||||
return $"rz-alert rz-alert-{GetAlertSize()} rz-variant-{Enum.GetName(typeof(Variant), Variant).ToLowerInvariant()} rz-{Enum.GetName(typeof(AlertStyle), AlertStyle).ToLowerInvariant()} rz-shade-{Enum.GetName(typeof(Shade), Shade).ToLowerInvariant()}";
|
||||
}
|
||||
|
||||
string getIcon()
|
||||
{
|
||||
if (!string.IsNullOrEmpty(Icon))
|
||||
{
|
||||
return Icon;
|
||||
}
|
||||
else if (AlertStyle == AlertStyle.Primary)
|
||||
{
|
||||
return "lightbulb_outline";
|
||||
}
|
||||
else if (AlertStyle == AlertStyle.Secondary)
|
||||
{
|
||||
return "lightbulb_outline";
|
||||
}
|
||||
else if (AlertStyle == AlertStyle.Light)
|
||||
{
|
||||
return "lightbulb_outline";
|
||||
}
|
||||
else if (AlertStyle == AlertStyle.Base)
|
||||
{
|
||||
return "lightbulb_outline";
|
||||
}
|
||||
else if (AlertStyle == AlertStyle.Dark)
|
||||
{
|
||||
return "lightbulb_outline";
|
||||
}
|
||||
else if (AlertStyle == AlertStyle.Success)
|
||||
{
|
||||
return "check_circle_outline";
|
||||
}
|
||||
else if (AlertStyle == AlertStyle.Danger)
|
||||
{
|
||||
return "error_outline";
|
||||
}
|
||||
else if (AlertStyle == AlertStyle.Warning)
|
||||
{
|
||||
return "warning_amber";
|
||||
}
|
||||
else if (AlertStyle == AlertStyle.Info)
|
||||
{
|
||||
return "info_outline";
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
void Close()
|
||||
{
|
||||
visible = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -12,18 +12,9 @@
|
||||
|
||||
var value = ComposeValue(valueScale);
|
||||
|
||||
IPathGenerator pathGenerator;
|
||||
|
||||
if (Smooth)
|
||||
{
|
||||
pathGenerator = new SplineGenerator();
|
||||
}
|
||||
else
|
||||
{
|
||||
pathGenerator = new LineGenerator();
|
||||
}
|
||||
var pathGenerator = GetPathGenerator();
|
||||
|
||||
var data = Items.Select(item =>
|
||||
var data = Items.Select(item =>
|
||||
{
|
||||
var x = category(item);
|
||||
var y = value(item);
|
||||
@@ -35,7 +26,7 @@
|
||||
var index = Chart.Series.IndexOf(this);
|
||||
var className = $"rz-area-series rz-series-{index}";
|
||||
|
||||
return
|
||||
return
|
||||
@<g class="@className">
|
||||
@if (Items.Any())
|
||||
{
|
||||
@@ -52,7 +43,7 @@
|
||||
<path @key="@area" style="@style" d="@area" fill="@Fill" stroke="none"></path>
|
||||
<Path @key="@line" D="@line" Stroke="@Stroke" StrokeWidth="@StrokeWidth" LineType="@LineType" Style="@style" Fill="none" />
|
||||
}
|
||||
<Markers Data="@Items" Category="@category" Value="@value" MarkerType="@MarkerType" Stroke="@Markers.Stroke" Fill="@(Markers.Fill ?? Stroke)" StrokeWidth="@Markers.StrokeWidth" Size="@Markers.Size" />
|
||||
<Markers Series="@this" Data="@Items" Category="@category" Value="@value" MarkerType="@MarkerType" Stroke="@Markers.Stroke" Fill="@(Markers.Fill ?? Stroke)" StrokeWidth="@Markers.StrokeWidth" Size="@Markers.Size" />
|
||||
</g>;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
using Microsoft.AspNetCore.Components;
|
||||
using Radzen.Blazor.Rendering;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace Radzen.Blazor
|
||||
@@ -40,7 +42,17 @@ namespace Radzen.Blazor
|
||||
/// Specifies whether to render a smooth line. Set to <c>false</c> by default.
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
public bool Smooth { get; set; }
|
||||
public bool Smooth
|
||||
{
|
||||
get => Interpolation == Interpolation.Spline;
|
||||
set => Interpolation = value ? Interpolation.Spline : Interpolation.Line;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Specifies how to render lines between data points. Set to <see cref="Line"/> by default
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
public Interpolation Interpolation { get; set; } = Interpolation.Line;
|
||||
|
||||
/// <inheritdoc />
|
||||
public override string Color
|
||||
@@ -82,19 +94,17 @@ namespace Radzen.Blazor
|
||||
var valueTicks = Chart.ValueScale.Ticks(Chart.ValueAxis.TickDistance);
|
||||
var axisY = Chart.ValueScale.Scale(Math.Max(0, valueTicks.Start));
|
||||
|
||||
if (points.Any())
|
||||
if (points.Length > 0)
|
||||
{
|
||||
for (var i = 0; i < points.Length - 1; i++)
|
||||
if (points.Length == 1)
|
||||
{
|
||||
var start = points[i];
|
||||
var end = points[i + 1];
|
||||
var point = points[0];
|
||||
|
||||
var polygon = new[]
|
||||
{
|
||||
new Point { X = start.X, Y = start.Y - tolerance },
|
||||
new Point { X = end.X, Y = end.Y - tolerance },
|
||||
new Point { X = end.X, Y = axisY },
|
||||
new Point { X = start.X, Y = axisY },
|
||||
var polygon = new[] {
|
||||
new Point { X = point.X - tolerance, Y = point.Y - tolerance },
|
||||
new Point { X = point.X - tolerance, Y = point.Y + tolerance },
|
||||
new Point { X = point.X + tolerance, Y = point.Y + tolerance },
|
||||
new Point { X = point.X + tolerance, Y = point.Y - tolerance },
|
||||
};
|
||||
|
||||
if (InsidePolygon(new Point { X = x, Y = y }, polygon))
|
||||
@@ -102,9 +112,51 @@ namespace Radzen.Blazor
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (var i = 0; i < points.Length - 1; i++)
|
||||
{
|
||||
var start = points[i];
|
||||
var end = points[i + 1];
|
||||
|
||||
var polygon = new[]
|
||||
{
|
||||
new Point { X = start.X, Y = start.Y - tolerance },
|
||||
new Point { X = end.X, Y = end.Y - tolerance },
|
||||
new Point { X = end.X, Y = axisY },
|
||||
new Point { X = start.X, Y = axisY },
|
||||
};
|
||||
|
||||
if (InsidePolygon(new Point { X = x, Y = y }, polygon))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override IEnumerable<ChartDataLabel> GetDataLabels(double offsetX, double offsetY)
|
||||
{
|
||||
return base.GetDataLabels(offsetX, offsetY - 16);
|
||||
}
|
||||
|
||||
private IPathGenerator GetPathGenerator()
|
||||
{
|
||||
switch(Interpolation)
|
||||
{
|
||||
case Interpolation.Line:
|
||||
return new LineGenerator();
|
||||
case Interpolation.Spline:
|
||||
return new SplineGenerator();
|
||||
case Interpolation.Step:
|
||||
return new StepGenerator();
|
||||
default:
|
||||
throw new NotSupportedException($"Interpolation {Interpolation} is not supported yet.");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -10,19 +10,39 @@
|
||||
@if (Visible)
|
||||
{
|
||||
<div @ref="@Element" style="@($"{Style};display:inline-block;")" @attributes="Attributes" class="@GetCssClass()" id="@GetId()">
|
||||
<input @ref="@search" @onkeydown="@OnFilterKeyPress" value="@Value" disabled="@Disabled"
|
||||
onfocus="@OpenScript()" onkeypress="@OpenScript()" tabindex="@TabIndex" @onchange="@OnChange"
|
||||
@if (Multiline)
|
||||
{
|
||||
<textarea @ref="@search" @attributes="InputAttributes" @onkeydown="@OnFilterKeyPress" value="@Value" disabled="@Disabled"
|
||||
oninput="@OpenScript()" tabindex="@(Disabled ? "-1" : $"{TabIndex}")" @onchange="@OnChange"
|
||||
aria-autocomplete="list" aria-haspopup="true" autocomplete="off" role="combobox"
|
||||
class="@InputClassList"
|
||||
type="text" id="@Name" aria-expanded="true" placeholder="@Placeholder" />
|
||||
<div id="@PopupID" class="rz-autocomplete-panel" style="display:none; transform: none; box-sizing: border-box; max-height: 200px;">
|
||||
class="@InputClassList" onblur="Radzen.activeElement = null"
|
||||
id="@Name" aria-expanded="true" placeholder="@CurrentPlaceholder" />
|
||||
}
|
||||
else
|
||||
{
|
||||
<input @ref="@search" @attributes="InputAttributes" @onkeydown="@OnFilterKeyPress" value="@Value" disabled="@Disabled"
|
||||
oninput="@OpenScript()" tabindex="@(Disabled ? "-1" : $"{TabIndex}")" @onchange="@OnChange"
|
||||
aria-autocomplete="list" aria-haspopup="true" autocomplete="off" role="combobox"
|
||||
class="@InputClassList" onblur="Radzen.activeElement = null"
|
||||
type="text" id="@Name" aria-expanded="true" placeholder="@CurrentPlaceholder" />
|
||||
}
|
||||
<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))
|
||||
{
|
||||
@foreach (var item in LoadData.HasDelegate ? Data != null ? Data : Enumerable.Empty<object>() : (View != null ? View : Enumerable.Empty<object>()))
|
||||
{
|
||||
<li role="option" class="rz-autocomplete-list-item" @onclick="@(() => OnSelectItem(item))" onmousedown="Radzen.activeElement = null">
|
||||
<span>@PropertyAccess.GetItemOrValueFromProperty(item, TextProperty)</span>
|
||||
<span>
|
||||
@if (Template != null)
|
||||
{
|
||||
@Template(item)
|
||||
}
|
||||
else
|
||||
{
|
||||
@PropertyAccess.GetItemOrValueFromProperty(item, TextProperty)
|
||||
}
|
||||
</span>
|
||||
</li>
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@ using Microsoft.AspNetCore.Components.Web;
|
||||
using System.Linq;
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Radzen.Blazor
|
||||
{
|
||||
@@ -22,6 +23,33 @@ namespace Radzen.Blazor
|
||||
/// </example>
|
||||
public partial class RadzenAutoComplete : DataBoundFormComponent<string>
|
||||
{
|
||||
/// <summary>
|
||||
/// Specifies additional custom attributes that will be rendered by the input.
|
||||
/// </summary>
|
||||
/// <value>The attributes.</value>
|
||||
public IReadOnlyDictionary<string, object> InputAttributes { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether this <see cref="RadzenAutoComplete"/> is multiline.
|
||||
/// </summary>
|
||||
/// <value><c>true</c> if multiline; otherwise, <c>false</c>.</value>
|
||||
[Parameter]
|
||||
public bool Multiline { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the Popup height.
|
||||
/// </summary>
|
||||
/// <value>The number Popup height.</value>
|
||||
[Parameter]
|
||||
public string PopupStyle { get; set; } = "display:none; transform: none; box-sizing: border-box; max-height: 200px;";
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the template.
|
||||
/// </summary>
|
||||
/// <value>The template.</value>
|
||||
[Parameter]
|
||||
public RenderFragment<dynamic> Template { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the minimum length.
|
||||
/// </summary>
|
||||
@@ -95,7 +123,10 @@ namespace Radzen.Blazor
|
||||
var value = await JSRuntime.InvokeAsync<string>("Radzen.getInputValue", search);
|
||||
|
||||
if (value.Length < MinLength)
|
||||
{
|
||||
await JSRuntime.InvokeVoidAsync("Radzen.closePopup", PopupID);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!LoadData.HasDelegate)
|
||||
{
|
||||
@@ -148,7 +179,9 @@ namespace Radzen.Blazor
|
||||
{
|
||||
string filterCaseSensitivityOperator = FilterCaseSensitivity == FilterCaseSensitivity.CaseInsensitive ? ".ToLower()" : "";
|
||||
|
||||
return Query.Where($"{TextProperty}{filterCaseSensitivityOperator}.{Enum.GetName(typeof(StringFilterOperator), FilterOperator)}(@0)",
|
||||
string textProperty = string.IsNullOrEmpty(TextProperty) ? string.Empty : $".{TextProperty}";
|
||||
|
||||
return Query.Where($"o=>o{textProperty}{filterCaseSensitivityOperator}.{Enum.GetName(typeof(StringFilterOperator), FilterOperator)}(@0)",
|
||||
FilterCaseSensitivity == FilterCaseSensitivity.CaseInsensitive ? searchText.ToLower() : searchText);
|
||||
}
|
||||
|
||||
@@ -249,5 +282,15 @@ namespace Radzen.Blazor
|
||||
await JSRuntime.InvokeVoidAsync("Radzen.destroyPopup", PopupID);
|
||||
}
|
||||
}
|
||||
|
||||
#if NET5_0_OR_GREATER
|
||||
/// <summary>
|
||||
/// Sets the focus on the input element.
|
||||
/// </summary>
|
||||
public override async ValueTask FocusAsync()
|
||||
{
|
||||
await search.FocusAsync();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,6 +20,8 @@ namespace Radzen.Blazor
|
||||
|
||||
classList.Add("rz-badge");
|
||||
classList.Add($"rz-badge-{BadgeStyle.ToString().ToLowerInvariant()}");
|
||||
classList.Add($"rz-variant-{Variant.ToString().ToLowerInvariant()}");
|
||||
classList.Add($"rz-shade-{Shade.ToString().ToLowerInvariant()}");
|
||||
|
||||
if (IsPill)
|
||||
{
|
||||
@@ -50,6 +52,20 @@ namespace Radzen.Blazor
|
||||
[Parameter]
|
||||
public BadgeStyle BadgeStyle { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the badge variant.
|
||||
/// </summary>
|
||||
/// <value>The badge variant.</value>
|
||||
[Parameter]
|
||||
public Variant Variant { get; set; } = Variant.Filled;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the badge shade color.
|
||||
/// </summary>
|
||||
/// <value>The badge shade color.</value>
|
||||
[Parameter]
|
||||
public Shade Shade { get; set; } = Shade.Default;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether this instance is pill.
|
||||
/// </summary>
|
||||
|
||||
@@ -21,6 +21,13 @@ namespace Radzen.Blazor
|
||||
[Parameter]
|
||||
public double Margin { get; set; } = 10;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the height of all bars in pixels. By default it is automatically calculated depending on the chart height.
|
||||
/// </summary>
|
||||
/// <value>The pixel height of the bar. By default set to <c>null</c></value>
|
||||
[Parameter]
|
||||
public double? Height { get; set;}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Initialize()
|
||||
{
|
||||
@@ -30,7 +37,9 @@ namespace Radzen.Blazor
|
||||
/// <inheritdoc />
|
||||
protected override bool ShouldRefreshChart(ParameterView parameters)
|
||||
{
|
||||
return DidParameterChange(parameters, nameof(Radius), Radius) || DidParameterChange(parameters, nameof(Margin), Margin);
|
||||
return DidParameterChange(parameters, nameof(Radius), Radius) ||
|
||||
DidParameterChange(parameters, nameof(Height), Height) ||
|
||||
DidParameterChange(parameters, nameof(Margin), Margin);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
using Microsoft.AspNetCore.Components;
|
||||
using Radzen.Blazor.Rendering;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
@@ -120,9 +121,18 @@ namespace Radzen.Blazor
|
||||
{
|
||||
get
|
||||
{
|
||||
var availableHeight = Chart.ValueScale.OutputSize; // - (Chart.ValueAxis.Padding * 2);
|
||||
var bands = VisibleBarSeries.Cast<IChartBarSeries>().Max(series => series.Count) + 2;
|
||||
return availableHeight / bands;
|
||||
var barSeries = VisibleBarSeries;
|
||||
|
||||
if (Chart.BarOptions.Height.HasValue)
|
||||
{
|
||||
return Chart.BarOptions.Height.Value * barSeries.Count;
|
||||
}
|
||||
else
|
||||
{
|
||||
var availableHeight = Chart.ValueScale.OutputSize; // - (Chart.ValueAxis.Padding * 2);
|
||||
var bands = barSeries.Cast<IChartBarSeries>().Max(series => series.Count) + 2;
|
||||
return availableHeight / bands;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -137,11 +147,11 @@ namespace Radzen.Blazor
|
||||
/// <inheritdoc />
|
||||
public override bool Contains(double x, double y, double tolerance)
|
||||
{
|
||||
return DataAt(x, y) != null;
|
||||
return DataAt(x, y).Item1 != null;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override double TooltipX(TItem item)
|
||||
internal override double TooltipX(TItem item)
|
||||
{
|
||||
var value = Chart.CategoryScale.Compose(Value);
|
||||
var x = value(item);
|
||||
@@ -163,7 +173,7 @@ namespace Radzen.Blazor
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override object DataAt(double x, double y)
|
||||
public override (object, Point) DataAt(double x, double y)
|
||||
{
|
||||
var value = ComposeValue(Chart.CategoryScale);
|
||||
var category = ComposeCategory(Chart.ValueScale);
|
||||
@@ -186,15 +196,15 @@ namespace Radzen.Blazor
|
||||
|
||||
if (startX <= x && x <= endX && startY <= y && y <= endY)
|
||||
{
|
||||
return data;
|
||||
return (data, new Point() { X = x, Y = y });
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
return (null, null);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override double TooltipY(TItem item)
|
||||
internal override double TooltipY(TItem item)
|
||||
{
|
||||
var category = ComposeCategory(Chart.ValueScale);
|
||||
var barSeries = VisibleBarSeries;
|
||||
@@ -206,5 +216,23 @@ namespace Radzen.Blazor
|
||||
|
||||
return y + height / 2;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override IEnumerable<ChartDataLabel> GetDataLabels(double offsetX, double offsetY)
|
||||
{
|
||||
var list = new List<ChartDataLabel>();
|
||||
|
||||
foreach (var d in Data)
|
||||
{
|
||||
list.Add(new ChartDataLabel
|
||||
{
|
||||
Position = new Point() { X = TooltipX(d) + offsetX + 8, Y = TooltipY(d) + offsetY },
|
||||
TextAnchor = "start",
|
||||
Text = Chart.ValueAxis.Format(Chart.CategoryScale, Value(d))
|
||||
});
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,8 +25,7 @@ namespace Radzen.Blazor
|
||||
protected override string GetComponentCssClass()
|
||||
{
|
||||
var classList = ClassList.Create("rz-body")
|
||||
.Add("body")
|
||||
.Add("body-expanded", Expanded);
|
||||
.Add("rz-body-expanded", Expanded);
|
||||
|
||||
return classList.ToString();
|
||||
}
|
||||
|
||||
@@ -3,7 +3,11 @@
|
||||
@if (Visible)
|
||||
{
|
||||
<div class="@GetCssClass()" id="@GetId()" style="@Style" @attributes="@Attributes">
|
||||
@if (Template != null)
|
||||
@if (ChildContent != null)
|
||||
{
|
||||
@ChildContent
|
||||
}
|
||||
else if (Template != null)
|
||||
{
|
||||
@Template(this)
|
||||
}
|
||||
@@ -11,13 +15,13 @@
|
||||
{
|
||||
@if (!string.IsNullOrWhiteSpace(Path))
|
||||
{
|
||||
<RadzenLink Icon="@Icon" Path="@Path" Text="@Text" />
|
||||
<RadzenLink Icon="@Icon" IconColor="@IconColor" Path="@Path" Text="@Text" />
|
||||
}
|
||||
else
|
||||
{
|
||||
@if (!string.IsNullOrWhiteSpace(Icon))
|
||||
{
|
||||
<RadzenIcon Icon="@Icon" />
|
||||
<RadzenIcon Icon="@Icon" IconColor="@IconColor" />
|
||||
}
|
||||
<RadzenLabel Text="@Text" />
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@ namespace Radzen.Blazor
|
||||
public partial class RadzenBreadCrumbItem : RadzenComponent
|
||||
{
|
||||
/// <summary>
|
||||
/// Cascaded TEmplate Parameter from <see cref="RadzenBreadCrumb"/> Component
|
||||
/// Cascaded Template Parameter from <see cref="RadzenBreadCrumb"/> Component
|
||||
/// </summary>
|
||||
[CascadingParameter]
|
||||
public RenderFragment<RadzenBreadCrumbItem> Template { get; set; }
|
||||
@@ -31,6 +31,20 @@ namespace Radzen.Blazor
|
||||
[Parameter]
|
||||
public string Icon { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the icon color.
|
||||
/// </summary>
|
||||
/// <value>The icon color.</value>
|
||||
[Parameter]
|
||||
public string IconColor { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Template Parameter used only for this Item
|
||||
/// Note: this overrides the <see cref="Template"/> Cascading Parameter
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
public RenderFragment ChildContent { get; set; }
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override string GetComponentCssClass()
|
||||
{
|
||||
|
||||
@@ -6,35 +6,37 @@
|
||||
type="@Enum.GetName(typeof(ButtonType), ButtonType).ToLower()"
|
||||
@attributes="Attributes" class="@GetCssClass()" id="@GetId()"
|
||||
@onclick="@OnClick">
|
||||
@if (ChildContent != null)
|
||||
{
|
||||
@ChildContent
|
||||
}
|
||||
else
|
||||
{
|
||||
@if (IsBusy)
|
||||
<span class="rz-button-box">
|
||||
@if (ChildContent != null)
|
||||
{
|
||||
<RadzenIcon Icon="refresh" Style="animation: rotation 700ms linear infinite" />
|
||||
@if (!string.IsNullOrEmpty(BusyText))
|
||||
{
|
||||
<span class="rz-button-text">@BusyText</span>
|
||||
}
|
||||
@ChildContent
|
||||
}
|
||||
else
|
||||
{
|
||||
@if (!string.IsNullOrEmpty(@Icon))
|
||||
@if (IsBusy)
|
||||
{
|
||||
<i class="rz-button-icon-left rzi">@((MarkupString)Icon)</i>
|
||||
<RadzenIcon Icon="refresh" Style="animation: rotation 700ms linear infinite" />
|
||||
@if (!string.IsNullOrEmpty(BusyText))
|
||||
{
|
||||
<span class="rz-button-text">@BusyText</span>
|
||||
}
|
||||
}
|
||||
@if (!string.IsNullOrEmpty(Image))
|
||||
else
|
||||
{
|
||||
<img class="rz-button-icon-left rzi" src="@Image" />
|
||||
}
|
||||
@if (!string.IsNullOrEmpty(Text))
|
||||
{
|
||||
<span class="rz-button-text">@Text</span>
|
||||
@if (!string.IsNullOrEmpty(@Icon))
|
||||
{
|
||||
<i class="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" />
|
||||
}
|
||||
@if (!string.IsNullOrEmpty(Text))
|
||||
{
|
||||
<span class="rz-button-text">@Text</span>
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</span>
|
||||
</button>
|
||||
}
|
||||
|
||||
@@ -15,9 +15,9 @@ namespace Radzen.Blazor
|
||||
/// </example>
|
||||
public partial class RadzenButton : RadzenComponent
|
||||
{
|
||||
private string getButtonSize()
|
||||
internal string getButtonSize()
|
||||
{
|
||||
return Size == ButtonSize.Medium ? "md" : "sm";
|
||||
return Size == ButtonSize.Medium ? "md" : Size == ButtonSize.Large ? "lg" : Size == ButtonSize.Small ? "sm" : "xs";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -41,6 +41,13 @@ namespace Radzen.Blazor
|
||||
[Parameter]
|
||||
public string Icon { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the icon color.
|
||||
/// </summary>
|
||||
/// <value>The icon color.</value>
|
||||
[Parameter]
|
||||
public string IconColor { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the image.
|
||||
/// </summary>
|
||||
@@ -62,6 +69,20 @@ namespace Radzen.Blazor
|
||||
[Parameter]
|
||||
public ButtonType ButtonType { get; set; } = ButtonType.Button;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the design variant of the button.
|
||||
/// </summary>
|
||||
/// <value>The variant of the button.</value>
|
||||
[Parameter]
|
||||
public Variant Variant { get; set; } = Variant.Filled;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the color shade of the button.
|
||||
/// </summary>
|
||||
/// <value>The color shade of the button.</value>
|
||||
[Parameter]
|
||||
public Shade Shade { get; set; } = Shade.Default;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the size.
|
||||
/// </summary>
|
||||
@@ -109,7 +130,7 @@ namespace Radzen.Blazor
|
||||
/// Handles the <see cref="E:Click" /> event.
|
||||
/// </summary>
|
||||
/// <param name="args">The <see cref="MouseEventArgs"/> instance containing the event data.</param>
|
||||
public async Task OnClick(MouseEventArgs args)
|
||||
public virtual async Task OnClick(MouseEventArgs args)
|
||||
{
|
||||
if (clicking)
|
||||
{
|
||||
@@ -131,7 +152,7 @@ namespace Radzen.Blazor
|
||||
/// <inheritdoc />
|
||||
protected override string GetComponentCssClass()
|
||||
{
|
||||
return $"rz-button rz-button-{getButtonSize()} btn-{Enum.GetName(typeof(ButtonStyle), ButtonStyle).ToLowerInvariant()}{(IsDisabled ? " rz-state-disabled" : "")}{(string.IsNullOrEmpty(Text) && !string.IsNullOrEmpty(Icon) ? " rz-button-icon-only" : "")}";
|
||||
return $"rz-button rz-button-{getButtonSize()} rz-variant-{Enum.GetName(typeof(Variant), Variant).ToLowerInvariant()} rz-{Enum.GetName(typeof(ButtonStyle), ButtonStyle).ToLowerInvariant()} rz-shade-{Enum.GetName(typeof(Shade), Shade).ToLowerInvariant()}{(IsDisabled ? " rz-state-disabled" : "")}{(string.IsNullOrEmpty(Text) && !string.IsNullOrEmpty(Icon) ? " rz-button-icon-only" : "")}";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
using Microsoft.AspNetCore.Components.Web;
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Radzen.Blazor
|
||||
{
|
||||
@@ -13,7 +14,18 @@ namespace Radzen.Blazor
|
||||
/// <inheritdoc />
|
||||
protected override string GetComponentCssClass()
|
||||
{
|
||||
return "rz-card card";
|
||||
var classList = new List<string>();
|
||||
classList.Add("rz-card");
|
||||
classList.Add($"rz-variant-{Variant.ToString().ToLowerInvariant()}");
|
||||
|
||||
return string.Join(" ", classList);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the card variant.
|
||||
/// </summary>
|
||||
/// <value>The card variant.</value>
|
||||
[Parameter]
|
||||
public Variant Variant { get; set; } = Variant.Filled;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -26,6 +26,7 @@
|
||||
@if (series.Visible)
|
||||
{
|
||||
@series.Render(CategoryScale, ValueScale);
|
||||
@series.RenderOverlays(CategoryScale, ValueScale);
|
||||
}
|
||||
}
|
||||
</g>
|
||||
@@ -37,10 +38,13 @@
|
||||
@donut.RenderTitle(MarginLeft, MarginTop)
|
||||
}
|
||||
}
|
||||
@if (tooltip != null)
|
||||
{
|
||||
@tooltip
|
||||
}
|
||||
<ChartTooltipContainer @ref="@chartTooltipContainer">
|
||||
@if (tooltip != null)
|
||||
{
|
||||
@tooltip
|
||||
}
|
||||
</ChartTooltipContainer>
|
||||
|
||||
</CascadingValue>
|
||||
}
|
||||
</div>
|
||||
|
||||
@@ -42,11 +42,16 @@ namespace Radzen.Blazor
|
||||
public ColorScheme ColorScheme { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// A callback that will be invoked when the user clicks on a series.
|
||||
/// A callback that will be invoked when the user clicks on a series.
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
public EventCallback<SeriesClickEventArgs> SeriesClick { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// A callback that will be invoked when the user clicks on a legend.
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
public EventCallback<LegendClickEventArgs> LegendClick { get; set; }
|
||||
double? Width { get; set; }
|
||||
|
||||
double? Height { get; set; }
|
||||
@@ -202,12 +207,7 @@ namespace Radzen.Blazor
|
||||
ValueScale.Fit(ValueAxis.TickDistance);
|
||||
CategoryScale.Fit(CategoryAxis.TickDistance);
|
||||
|
||||
var stateHasChanged = false;
|
||||
|
||||
if (!ValueScale.IsEqualTo(valueScale))
|
||||
{
|
||||
stateHasChanged = true;
|
||||
}
|
||||
var stateHasChanged = !ValueScale.IsEqualTo(valueScale);
|
||||
|
||||
if (!CategoryScale.IsEqualTo(categoryScale))
|
||||
{
|
||||
@@ -249,6 +249,7 @@ namespace Radzen.Blazor
|
||||
}
|
||||
}
|
||||
|
||||
ChartTooltipContainer chartTooltipContainer;
|
||||
RenderFragment tooltip;
|
||||
object tooltipData;
|
||||
double mouseX;
|
||||
@@ -268,6 +269,18 @@ namespace Radzen.Blazor
|
||||
await DisplayTooltip();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The minimum pixel distance from a data point to the mouse cursor required for the SeriesClick event to fire. Set to 25 by default.
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
public int ClickTolerance { get; set; } = 25;
|
||||
|
||||
/// <summary>
|
||||
/// The minimum pixel distance from a data point to the mouse cursor required by the tooltip to show. Set to 25 by default.
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
public int TooltipTolerance { get; set; } = 25;
|
||||
|
||||
/// <summary>
|
||||
/// Invoked via interop when the user clicks the RadzenChart. Raises the <see cref="SeriesClick" /> handler.
|
||||
/// </summary>
|
||||
@@ -276,20 +289,37 @@ namespace Radzen.Blazor
|
||||
[JSInvokable]
|
||||
public async Task Click(double x, double y)
|
||||
{
|
||||
IChartSeries closestSeries = null;
|
||||
object closestSeriesData = null;
|
||||
double closestSeriesDistanceSquared = ClickTolerance * ClickTolerance;
|
||||
|
||||
var queryX = x - MarginLeft;
|
||||
var queryY = y - MarginTop;
|
||||
|
||||
foreach (var series in Series)
|
||||
{
|
||||
if (series.Visible && series.Contains(mouseX - MarginLeft, mouseY - MarginTop, 5))
|
||||
if (series.Visible)
|
||||
{
|
||||
var data = series.DataAt(mouseX - MarginLeft, mouseY - MarginTop);
|
||||
|
||||
if (data != null)
|
||||
var (seriesData, seriesDataPoint) = series.DataAt(queryX, queryY);
|
||||
if (seriesData != null)
|
||||
{
|
||||
await series.InvokeClick(SeriesClick, data);
|
||||
double xDelta = queryX - seriesDataPoint.X;
|
||||
double yDelta = queryY - seriesDataPoint.Y;
|
||||
double squaredDistance = xDelta * xDelta + yDelta * yDelta;
|
||||
if (squaredDistance < closestSeriesDistanceSquared)
|
||||
{
|
||||
closestSeries = series;
|
||||
closestSeriesData = seriesData;
|
||||
closestSeriesDistanceSquared = squaredDistance;
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (closestSeriesData != null)
|
||||
{
|
||||
await closestSeries.InvokeClick(SeriesClick, closestSeriesData);
|
||||
}
|
||||
}
|
||||
|
||||
internal async Task DisplayTooltip()
|
||||
@@ -297,31 +327,64 @@ namespace Radzen.Blazor
|
||||
if (Tooltip.Visible)
|
||||
{
|
||||
var orderedSeries = Series.OrderBy(s => s.RenderingOrder).Reverse();
|
||||
IChartSeries closestSeries = null;
|
||||
object closestSeriesData = null;
|
||||
double closestSeriesDistanceSquared = TooltipTolerance * TooltipTolerance;
|
||||
|
||||
var queryX = mouseX - MarginLeft;
|
||||
var queryY = mouseY - MarginTop;
|
||||
|
||||
foreach (var series in orderedSeries)
|
||||
{
|
||||
if (series.Visible && series.Contains(mouseX - MarginLeft, mouseY - MarginTop, 25))
|
||||
if (series.Visible)
|
||||
{
|
||||
var data = series.DataAt(mouseX - MarginLeft, mouseY - MarginTop);
|
||||
|
||||
if (data != tooltipData)
|
||||
foreach (var overlay in series.Overlays.Reverse())
|
||||
{
|
||||
tooltipData = data;
|
||||
tooltip = series.RenderTooltip(data, MarginLeft, MarginTop);
|
||||
StateHasChanged();
|
||||
await Task.Yield();
|
||||
if (overlay.Visible && overlay.Contains(mouseX - MarginLeft, mouseY - MarginTop, TooltipTolerance))
|
||||
{
|
||||
tooltipData = null;
|
||||
tooltip = overlay.RenderTooltip(mouseX, mouseY, MarginLeft, MarginTop);
|
||||
chartTooltipContainer.Refresh();
|
||||
await Task.Yield();
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
var (seriesData, seriesDataPoint) = series.DataAt(queryX, queryY);
|
||||
if (seriesData != null)
|
||||
{
|
||||
double xDelta = queryX - seriesDataPoint.X;
|
||||
double yDelta = queryY - seriesDataPoint.Y;
|
||||
double squaredDistance = xDelta * xDelta + yDelta * yDelta;
|
||||
if (squaredDistance < closestSeriesDistanceSquared)
|
||||
{
|
||||
closestSeries = series;
|
||||
closestSeriesData = seriesData;
|
||||
closestSeriesDistanceSquared = squaredDistance;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (closestSeriesData != null)
|
||||
{
|
||||
if (closestSeriesData != tooltipData)
|
||||
{
|
||||
tooltipData = closestSeriesData;
|
||||
tooltip = closestSeries.RenderTooltip(closestSeriesData, MarginLeft, MarginTop, Height ?? 0);
|
||||
chartTooltipContainer.Refresh();
|
||||
await Task.Yield();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (tooltip != null)
|
||||
{
|
||||
tooltipData = null;
|
||||
tooltip = null;
|
||||
|
||||
StateHasChanged();
|
||||
chartTooltipContainer.Refresh();
|
||||
await Task.Yield();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,10 +5,10 @@
|
||||
@inherits FormComponent<TValue>
|
||||
@if (Visible)
|
||||
{
|
||||
<div @ref="@Element" @attributes="Attributes" class="@GetCssClass()" @onkeypress=@OnKeyPress @onkeypress:preventDefault style="@Style" tabindex="@TabIndex" id="@GetId()">
|
||||
<div @ref="@Element" @attributes="Attributes" class="@GetCssClass()" @onkeypress=@OnKeyPress @onkeypress:preventDefault style="@Style" tabindex="@(Disabled || ReadOnly ? "-1" : $"{TabIndex}")" id="@GetId()">
|
||||
<div class="rz-helper-hidden-accessible">
|
||||
<input type="checkbox" @onchange=@Toggle value=@CheckBoxValue name=@Name id=@Name checked=@CheckBoxChecked
|
||||
tabindex="-1">
|
||||
tabindex="-1" readonly="@ReadOnly">
|
||||
</div>
|
||||
<div class=@BoxClassList @onclick=@Toggle @onclick:preventDefault>
|
||||
<span class=@IconClassList></span>
|
||||
|
||||
@@ -49,9 +49,16 @@ namespace Radzen.Blazor
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether is read only.
|
||||
/// </summary>
|
||||
/// <value><c>true</c> if is read only; otherwise, <c>false</c>.</value>
|
||||
[Parameter]
|
||||
public bool ReadOnly { get; set; }
|
||||
|
||||
async Task Toggle()
|
||||
{
|
||||
if (Disabled)
|
||||
if (Disabled || ReadOnly)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -15,18 +15,25 @@
|
||||
@if (Visible)
|
||||
{
|
||||
<div @ref="@Element" style="@Style" @attributes="Attributes" class="@GetCssClass()" id="@GetId()">
|
||||
@if (AllowSelectAll)
|
||||
{
|
||||
<div class="rz-multiselect-header rz-helper-clearfix" @onclick:preventDefault>
|
||||
<RadzenCheckBox ReadOnly="@ReadOnly" Disabled="@Disabled" Name="SelectAll" TValue="bool?" Value="@IsAllSelected()" Change="@SelectAll" />
|
||||
<RadzenLabel Component="SelectAll" Text="@SelectAllText" class="rz-chkbox-label" />
|
||||
</div>
|
||||
}
|
||||
@foreach (var item in allItems.Where(i => i.Visible))
|
||||
{
|
||||
<div class="rz-checkbox" @onclick="@(args => SelectItem(item))" @attributes="item.Attributes" style="@item.Style">
|
||||
<div class="rz-chkbox " @onkeypress="@(async args => { if (args.Code == "Space") { await SelectItem(item); } })" tabindex="@TabIndex">
|
||||
<div @ref="@item.Element" id="@item.GetItemId()" @onclick="@(args => SelectItem(item))" @attributes="item.Attributes" class="@item.GetItemCssClass()" style="@item.Style">
|
||||
<div class="rz-chkbox " @onkeypress="@(async args => { if (args.Code == "Space") { await SelectItem(item); } })" tabindex="@(Disabled || ReadOnly || item.Disabled || item.ReadOnly ? "-1" : $"{TabIndex}")">
|
||||
<div class="rz-helper-hidden-accessible">
|
||||
<input type="checkbox" name="@Name" value="@item.Value" disabled="@Disabled" tabindex="-1">
|
||||
<input type="checkbox" name="@Name" value="@item.Value" disabled="@Disabled" readonly="@ReadOnly" tabindex="-1">
|
||||
</div>
|
||||
<div class=@ItemClassList(item)>
|
||||
<span class=@IconClassList(item)></span>
|
||||
</div>
|
||||
</div>
|
||||
<label class="rz-chkbox-label">@item.Text</label>
|
||||
<label class="rz-chkbox-label">@((MarkupString)item.Text)</label>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using Microsoft.AspNetCore.Components;
|
||||
using Microsoft.AspNetCore.Components.Web;
|
||||
using Radzen.Blazor.Rendering;
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
@@ -45,6 +46,20 @@ namespace Radzen.Blazor
|
||||
[Parameter]
|
||||
public string TextProperty { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the disabled property.
|
||||
/// </summary>
|
||||
/// <value>The disabled property.</value>
|
||||
[Parameter]
|
||||
public string DisabledProperty { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the read-only property.
|
||||
/// </summary>
|
||||
/// <value>The read-only property.</value>
|
||||
[Parameter]
|
||||
public string ReadOnlyProperty { get; set; }
|
||||
|
||||
IEnumerable<RadzenCheckBoxListItem<TValue>> allItems
|
||||
{
|
||||
get
|
||||
@@ -54,12 +69,77 @@ namespace Radzen.Blazor
|
||||
var item = new RadzenCheckBoxListItem<TValue>();
|
||||
item.SetText((string)PropertyAccess.GetItemOrValueFromProperty(i, TextProperty));
|
||||
item.SetValue((TValue)PropertyAccess.GetItemOrValueFromProperty(i, ValueProperty));
|
||||
|
||||
if (DisabledProperty != null && PropertyAccess.TryGetItemOrValueFromProperty<bool>(i, DisabledProperty, out var disabledResult))
|
||||
{
|
||||
item.SetDisabled(disabledResult);
|
||||
}
|
||||
|
||||
if (ReadOnlyProperty != null && PropertyAccess.TryGetItemOrValueFromProperty<bool>(i, ReadOnlyProperty, out var readOnlyResult))
|
||||
{
|
||||
item.SetReadOnly(readOnlyResult);
|
||||
}
|
||||
|
||||
return item;
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether the user can select all values. Set to <c>false</c> by default.
|
||||
/// </summary>
|
||||
/// <value><c>true</c> if select all values is allowed; otherwise, <c>false</c>.</value>
|
||||
[Parameter]
|
||||
public bool AllowSelectAll { get; set; } = false;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the select all text.
|
||||
/// </summary>
|
||||
/// <value>The select all text.</value>
|
||||
[Parameter]
|
||||
public string SelectAllText { get; set; }
|
||||
|
||||
async Task SelectAll(bool? value)
|
||||
{
|
||||
if (Disabled || ReadOnly)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (value == true)
|
||||
{
|
||||
Value = allItems.Select(i => i.Value);
|
||||
}
|
||||
else if (value == false)
|
||||
{
|
||||
Value = null;
|
||||
}
|
||||
|
||||
await ValueChanged.InvokeAsync(Value);
|
||||
if (FieldIdentifier.FieldName != null) { EditContext?.NotifyFieldChanged(FieldIdentifier); }
|
||||
await Change.InvokeAsync(Value);
|
||||
|
||||
StateHasChanged();
|
||||
}
|
||||
|
||||
bool? IsAllSelected()
|
||||
{
|
||||
Func<RadzenCheckBoxListItem<TValue>, bool> predicate = i => Value != null && Value.Contains(i.Value);
|
||||
var all = allItems.All(predicate);
|
||||
var any = allItems.Any(predicate);
|
||||
|
||||
if (all)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return any ? null : (bool?)false;
|
||||
}
|
||||
}
|
||||
|
||||
IEnumerable _data = null;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the data used to generate items.
|
||||
/// </summary>
|
||||
@@ -81,6 +161,13 @@ namespace Radzen.Blazor
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether is read only.
|
||||
/// </summary>
|
||||
/// <value><c>true</c> if is read only; otherwise, <c>false</c>.</value>
|
||||
[Parameter]
|
||||
public bool ReadOnly { get; set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override string GetComponentCssClass()
|
||||
{
|
||||
@@ -160,7 +247,7 @@ namespace Radzen.Blazor
|
||||
/// <param name="item">The item.</param>
|
||||
protected async System.Threading.Tasks.Task SelectItem(RadzenCheckBoxListItem<TValue> item)
|
||||
{
|
||||
if (Disabled || item.Disabled)
|
||||
if (Disabled || item.Disabled || ReadOnly || item.ReadOnly)
|
||||
return;
|
||||
|
||||
List<TValue> selectedValues = new List<TValue>(Value != null ? Value : Enumerable.Empty<TValue>());
|
||||
@@ -182,10 +269,5 @@ namespace Radzen.Blazor
|
||||
|
||||
StateHasChanged();
|
||||
}
|
||||
|
||||
private string getDisabledState(RadzenCheckBoxListItem<TValue> item)
|
||||
{
|
||||
return Disabled || item.Disabled ? " rz-state-disabled" : "";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,6 +29,13 @@ namespace Radzen.Blazor
|
||||
[Parameter]
|
||||
public virtual bool Disabled { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether is read only.
|
||||
/// </summary>
|
||||
/// <value><c>true</c> if is read only; otherwise, <c>false</c>.</value>
|
||||
[Parameter]
|
||||
public bool ReadOnly { get; set; }
|
||||
|
||||
RadzenCheckBoxList<TValue> _checkBoxList;
|
||||
|
||||
/// <summary>
|
||||
@@ -70,5 +77,31 @@ namespace Radzen.Blazor
|
||||
{
|
||||
Value = value;
|
||||
}
|
||||
|
||||
internal void SetDisabled(bool value)
|
||||
{
|
||||
Disabled = value;
|
||||
}
|
||||
|
||||
internal void SetReadOnly(bool value)
|
||||
{
|
||||
ReadOnly = value;
|
||||
}
|
||||
|
||||
internal string GetItemId()
|
||||
{
|
||||
return GetId();
|
||||
}
|
||||
|
||||
internal string GetItemCssClass()
|
||||
{
|
||||
return GetCssClass();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override string GetComponentCssClass()
|
||||
{
|
||||
return "rz-checkbox";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,19 +6,19 @@
|
||||
@if (Visible)
|
||||
{
|
||||
<div @ref=@Element style=@Style @onclick=@Toggle @attributes=@Attributes class=@GetCssClass() id=@GetId()>
|
||||
@if(Icon != null)
|
||||
@if (Icon != null)
|
||||
{
|
||||
<i class="rzi">@Icon</i>
|
||||
<i class="rzi" style="@(!string.IsNullOrEmpty(IconColor) ? $"color:{IconColor}" : null)">@Icon</i>
|
||||
}
|
||||
<div class="rz-colorpicker-value" style="background-color: @Color" ></div>
|
||||
<div class="rz-colorpicker-value" style="background-color: @Value" ></div>
|
||||
<button type="button" tabindex="-1" class="rz-colorpicker-trigger" disabled=@Disabled @onclick:preventDefault><i class="rzi" /></button>
|
||||
<Popup @ref=@Popup class="rz-colorpicker-popup" Close=@Close Open=@Open>
|
||||
<Popup Lazy=@(PopupRenderMode == PopupRenderMode.OnDemand) @ref=@Popup class="rz-colorpicker-popup" Close=@OnClosePopup Open=@Open>
|
||||
@if (ShowHSV)
|
||||
{
|
||||
<Draggable class="rz-saturation-picker rz-colorpicker-section" style=@($"background-color: {HSV.ToRGB().ToCSS()}") Drag=@OnSaturationMove>
|
||||
<Draggable class="rz-saturation-picker rz-colorpicker-section" style=@($"background-color: hsl({(HueHandleLeft * 360).ToInvariantString()}, 100%, 50%)") Drag=@OnSaturationMove>
|
||||
<div class="rz-saturation-white">
|
||||
<div class="rz-saturation-black"></div>
|
||||
<div class="rz-saturation-handle" style=@($"top: {(SaturationHandleTop*100).ToInvariantString()}%; left: {(SaturationHandleLeft * 100).ToInvariantString()}%")></div>
|
||||
<div class="rz-saturation-handle" style=@($"top: {(SaturationHandleTop * 100).ToInvariantString()}%; left: {(SaturationHandleLeft * 100).ToInvariantString()}%")></div>
|
||||
</div>
|
||||
</Draggable>
|
||||
<div class="rz-colorpicker-preview-area rz-colorpicker-section">
|
||||
@@ -107,7 +107,7 @@
|
||||
</div>
|
||||
|
||||
}
|
||||
@if(ShowButton)
|
||||
@if (ShowButton)
|
||||
{
|
||||
<div class="rz-colorpicker-button rz-colorpicker-section">
|
||||
<RadzenButton ButtonStyle="ButtonStyle.Primary" Click=@OnClick Text=@ButtonText @onclick:preventDefault />
|
||||
|
||||
@@ -37,6 +37,13 @@ namespace Radzen.Blazor
|
||||
[Parameter]
|
||||
public string Icon { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the icon color.
|
||||
/// </summary>
|
||||
/// <value>The icon color.</value>
|
||||
[Parameter]
|
||||
public string IconColor { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the hexadecimal color label text.
|
||||
/// </summary>
|
||||
@@ -151,16 +158,24 @@ namespace Radzen.Blazor
|
||||
}
|
||||
}
|
||||
|
||||
void UpdateColorUsingHsvHandles()
|
||||
{
|
||||
var hsv = new HSV {
|
||||
Hue = HueHandleLeft,
|
||||
Saturation = SaturationHandleLeft,
|
||||
Value = 1 - SaturationHandleTop,
|
||||
Alpha = AlphaHandleLeft
|
||||
};
|
||||
Color = hsv.ToRGB().ToCSS();
|
||||
TriggerChange();
|
||||
}
|
||||
|
||||
void OnSaturationMove(DraggableEventArgs args)
|
||||
{
|
||||
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);
|
||||
|
||||
var hsv = new HSV { Hue = HSV.Hue, Saturation = SaturationHandleLeft, Value = 1 - SaturationHandleTop, Alpha = AlphaHandleLeft };
|
||||
|
||||
Color = hsv.ToRGB().ToCSS();
|
||||
|
||||
TriggerChange();
|
||||
UpdateColorUsingHsvHandles();
|
||||
}
|
||||
|
||||
void TriggerChange()
|
||||
@@ -176,23 +191,17 @@ namespace Radzen.Blazor
|
||||
|
||||
void ChangeRGB(object value)
|
||||
{
|
||||
SetValue(value as string);
|
||||
}
|
||||
|
||||
void SetValue(string value)
|
||||
{
|
||||
var rgb = RGB.Parse(value);
|
||||
|
||||
var rgb = RGB.Parse(value as string);
|
||||
if (rgb != null)
|
||||
{
|
||||
Color = rgb.ToCSS();
|
||||
rgb.Alpha = AlphaHandleLeft;
|
||||
UpdateColor(rgb);
|
||||
}
|
||||
}
|
||||
|
||||
internal async Task SelectColor(string value)
|
||||
{
|
||||
SetValue(value);
|
||||
UpdateColor(RGB.Parse(value));
|
||||
|
||||
if (!ShowButton)
|
||||
{
|
||||
@@ -204,11 +213,12 @@ namespace Radzen.Blazor
|
||||
{
|
||||
Color = rgb.ToCSS();
|
||||
|
||||
HSV = rgb.ToHSV();
|
||||
var hsv = rgb.ToHSV();
|
||||
|
||||
SaturationHandleLeft = HSV.Saturation;
|
||||
SaturationHandleTop = 1 - HSV.Value;
|
||||
HueHandleLeft = HSV.Hue;
|
||||
SaturationHandleLeft = hsv.Saturation;
|
||||
SaturationHandleTop = 1 - hsv.Value;
|
||||
HueHandleLeft = hsv.Hue;
|
||||
AlphaHandleLeft = hsv.Alpha;
|
||||
|
||||
TriggerChange();
|
||||
}
|
||||
@@ -258,25 +268,14 @@ namespace Radzen.Blazor
|
||||
{
|
||||
AlphaHandleLeft = Math.Round(Math.Clamp((args.ClientX - args.Rect.Left) / args.Rect.Width, 0, 1), 2);
|
||||
|
||||
HSV.Alpha = AlphaHandleLeft;
|
||||
|
||||
var hsv = new HSV { Hue = HSV.Hue, Saturation = SaturationHandleLeft, Value = 1 - SaturationHandleTop, Alpha = AlphaHandleLeft };
|
||||
|
||||
Color = hsv.ToRGB().ToCSS();
|
||||
|
||||
TriggerChange();
|
||||
UpdateColorUsingHsvHandles();
|
||||
}
|
||||
|
||||
void OnHueMove(DraggableEventArgs args)
|
||||
{
|
||||
HueHandleLeft = Math.Clamp((args.ClientX - args.Rect.Left) / args.Rect.Width, 0, 1);
|
||||
|
||||
HSV.Hue = HueHandleLeft;
|
||||
var hsv = new HSV { Hue = HSV.Hue, Saturation = SaturationHandleLeft, Value = 1 - SaturationHandleTop, Alpha = AlphaHandleLeft };
|
||||
|
||||
Color = hsv.ToRGB().ToCSS();
|
||||
|
||||
TriggerChange();
|
||||
UpdateColorUsingHsvHandles();
|
||||
}
|
||||
|
||||
async Task OnClick()
|
||||
@@ -286,6 +285,15 @@ namespace Radzen.Blazor
|
||||
await Popup.CloseAsync();
|
||||
}
|
||||
|
||||
async Task OnClosePopup()
|
||||
{
|
||||
if (ShowButton)
|
||||
{
|
||||
SetInitialValue();
|
||||
}
|
||||
await Close.InvokeAsync(null);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether button is shown.
|
||||
/// </summary>
|
||||
@@ -321,11 +329,17 @@ namespace Radzen.Blazor
|
||||
[Parameter]
|
||||
public RenderFragment ChildContent { get; set; }
|
||||
|
||||
double SaturationHandleLeft { get; set; }
|
||||
double HueHandleLeft { get; set; }
|
||||
/// <summary>
|
||||
/// Gets or sets the render mode.
|
||||
/// </summary>
|
||||
/// <value>The render mode.</value>
|
||||
[Parameter]
|
||||
public PopupRenderMode PopupRenderMode { get; set; } = PopupRenderMode.Initial;
|
||||
|
||||
double SaturationHandleLeft { get; set; } = 0;
|
||||
double SaturationHandleTop { get; set; } = 0;
|
||||
double HueHandleLeft { get; set; } = 0;
|
||||
double AlphaHandleLeft { get; set; } = 1;
|
||||
double SaturationHandleTop { get; set; }
|
||||
HSV HSV { get; set; } = new HSV { Hue = 0, Saturation = 1, Value = 1 };
|
||||
string Color { get; set; } = "rgb(255, 255, 255)";
|
||||
|
||||
async Task Toggle()
|
||||
@@ -342,7 +356,7 @@ namespace Radzen.Blazor
|
||||
|
||||
if (Disabled)
|
||||
{
|
||||
classList.Add("rz-disabled");
|
||||
classList.Add("rz-state-disabled");
|
||||
}
|
||||
|
||||
return string.Join(" ", classList);
|
||||
@@ -351,15 +365,16 @@ namespace Radzen.Blazor
|
||||
/// <inheritdoc />
|
||||
protected override void OnInitialized()
|
||||
{
|
||||
Init();
|
||||
SetInitialValue();
|
||||
|
||||
base.OnInitialized();
|
||||
}
|
||||
|
||||
void Init()
|
||||
void SetInitialValue()
|
||||
{
|
||||
var value = Value;
|
||||
if (String.IsNullOrEmpty(Value))
|
||||
|
||||
if (String.IsNullOrEmpty(Value) || RGB.Parse(Value) == null)
|
||||
{
|
||||
value = "rgb(255, 255, 255)";
|
||||
}
|
||||
@@ -368,17 +383,11 @@ namespace Radzen.Blazor
|
||||
{
|
||||
Color = value;
|
||||
|
||||
HSV = RGB.Parse(Color).ToHSV();
|
||||
SaturationHandleLeft = HSV.Saturation;
|
||||
SaturationHandleTop = 1 - HSV.Value;
|
||||
HSV.Saturation = 1;
|
||||
HSV.Value = 1;
|
||||
HueHandleLeft = HSV.Hue;
|
||||
|
||||
if (value.StartsWith("rgba"))
|
||||
{
|
||||
AlphaHandleLeft = HSV.Alpha;
|
||||
}
|
||||
var hsv = RGB.Parse(Color).ToHSV();
|
||||
SaturationHandleLeft = hsv.Saturation;
|
||||
SaturationHandleTop = 1 - hsv.Value;
|
||||
HueHandleLeft = hsv.Hue;
|
||||
AlphaHandleLeft = hsv.Alpha;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -391,7 +400,7 @@ namespace Radzen.Blazor
|
||||
|
||||
if (valueChanged)
|
||||
{
|
||||
Init();
|
||||
SetInitialValue();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
6
Radzen.Blazor/RadzenColumn.razor
Normal file
6
Radzen.Blazor/RadzenColumn.razor
Normal file
@@ -0,0 +1,6 @@
|
||||
@inherits RadzenComponentWithChildren
|
||||
|
||||
@if (Visible)
|
||||
{
|
||||
<div @ref="@Element" @attributes="Attributes" class="@GetCssClass()" style="@GetStyle()" id="@GetId()">@ChildContent</div>
|
||||
}
|
||||
245
Radzen.Blazor/RadzenColumn.razor.cs
Normal file
245
Radzen.Blazor/RadzenColumn.razor.cs
Normal file
@@ -0,0 +1,245 @@
|
||||
using Microsoft.AspNetCore.Components;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace Radzen.Blazor
|
||||
{
|
||||
/// <summary>
|
||||
/// RadzenColumn component.
|
||||
/// </summary>
|
||||
public partial class RadzenColumn : RadzenComponentWithChildren
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the size.
|
||||
/// </summary>
|
||||
/// <value>The size.</value>
|
||||
[Parameter]
|
||||
public int? Size { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the XS size.
|
||||
/// </summary>
|
||||
/// <value>The XS size.</value>
|
||||
[Parameter]
|
||||
public int? SizeXS { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the SM size.
|
||||
/// </summary>
|
||||
/// <value>The SM size.</value>
|
||||
[Parameter]
|
||||
public int? SizeSM { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the MD size.
|
||||
/// </summary>
|
||||
/// <value>The MD size.</value>
|
||||
[Parameter]
|
||||
public int? SizeMD { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the LG size.
|
||||
/// </summary>
|
||||
/// <value>The LG size.</value>
|
||||
[Parameter]
|
||||
public int? SizeLG { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the XL size.
|
||||
/// </summary>
|
||||
/// <value>The XL size.</value>
|
||||
[Parameter]
|
||||
public int? SizeXL { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the XX size.
|
||||
/// </summary>
|
||||
/// <value>The XX size.</value>
|
||||
[Parameter]
|
||||
public int? SizeXX { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the offset.
|
||||
/// </summary>
|
||||
/// <value>The offset.</value>
|
||||
[Parameter]
|
||||
public int? Offset { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the XS offset.
|
||||
/// </summary>
|
||||
/// <value>The XS offset.</value>
|
||||
[Parameter]
|
||||
public int? OffsetXS { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the SM offset.
|
||||
/// </summary>
|
||||
/// <value>The SM offset.</value>
|
||||
[Parameter]
|
||||
public int? OffsetSM { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the MD offset.
|
||||
/// </summary>
|
||||
/// <value>The MD offset.</value>
|
||||
[Parameter]
|
||||
public int? OffsetMD { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the LG offset.
|
||||
/// </summary>
|
||||
/// <value>The LG offset.</value>
|
||||
[Parameter]
|
||||
public int? OffsetLG { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the XL offset.
|
||||
/// </summary>
|
||||
/// <value>The XL offset.</value>
|
||||
[Parameter]
|
||||
public int? OffsetXL { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the XX offset.
|
||||
/// </summary>
|
||||
/// <value>The XX offset.</value>
|
||||
[Parameter]
|
||||
public int? OffsetXX { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the order.
|
||||
/// </summary>
|
||||
/// <value>The order.</value>
|
||||
[Parameter]
|
||||
public string Order { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the XS order.
|
||||
/// </summary>
|
||||
/// <value>The XS order.</value>
|
||||
[Parameter]
|
||||
public string OrderXS { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the SM order.
|
||||
/// </summary>
|
||||
/// <value>The SM order.</value>
|
||||
[Parameter]
|
||||
public string OrderSM { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the MD order.
|
||||
/// </summary>
|
||||
/// <value>The MD order.</value>
|
||||
[Parameter]
|
||||
public string OrderMD { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the LG order.
|
||||
/// </summary>
|
||||
/// <value>The LG order.</value>
|
||||
[Parameter]
|
||||
public string OrderLG { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the XL order.
|
||||
/// </summary>
|
||||
/// <value>The XL order.</value>
|
||||
[Parameter]
|
||||
public string OrderXL { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the XX order.
|
||||
/// </summary>
|
||||
/// <value>The XX order.</value>
|
||||
[Parameter]
|
||||
public string OrderXX { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the final CSS style rendered by the component. Combines it with a <c>style</c> custom attribute.
|
||||
/// </summary>
|
||||
protected string GetStyle()
|
||||
{
|
||||
if (Attributes != null && Attributes.TryGetValue("style", out var style) && !string.IsNullOrEmpty(Convert.ToString(@style)))
|
||||
{
|
||||
return $"{GetComponentStyle()} {@style}";
|
||||
}
|
||||
|
||||
return GetComponentStyle();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the component CSS style.
|
||||
/// </summary>
|
||||
protected string GetComponentStyle()
|
||||
{
|
||||
return $"{Style}{(!string.IsNullOrEmpty(Style) && !Style.EndsWith(";") ? ";" : "")}";
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override string GetComponentCssClass()
|
||||
{
|
||||
var list = new List<string>
|
||||
{
|
||||
Size != null ? $"rz-col-{GetColumnValue("Size", Size)}" : "rz-col"
|
||||
};
|
||||
|
||||
if (Offset != null)
|
||||
{
|
||||
list.Add($"rz-offset-{GetColumnValue("Offset", Offset)}");
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(Order))
|
||||
{
|
||||
list.Add($"rz-order-{GetOrderValue("Order", Order)}");
|
||||
}
|
||||
|
||||
var breakPoints = new string[] { "xs", "sm", "md", "lg", "xl", "xx" };
|
||||
|
||||
var properties = GetType().GetProperties()
|
||||
.Where(p => breakPoints.Any(bp => p.Name.ToLower().EndsWith(bp)))
|
||||
.Select(p => new { p.Name, BreakPoint = string.Concat(p.Name.ToLower().TakeLast(2)), Value = p.GetValue(this) });
|
||||
|
||||
foreach (var p in properties)
|
||||
{
|
||||
if (p.Value != null)
|
||||
{
|
||||
list.Add($"rz-{(!p.Name.StartsWith("Size") ? p.Name.ToLower().Replace(p.BreakPoint, "") + "-" : "col-")}{p.BreakPoint}-{GetColumnValue(p.Name, p.Value)}");
|
||||
}
|
||||
}
|
||||
|
||||
return string.Join(" ", list);
|
||||
}
|
||||
|
||||
string GetColumnValue(string name, object value)
|
||||
{
|
||||
if (name.StartsWith("Order"))
|
||||
{
|
||||
return GetOrderValue(name, value.ToString());
|
||||
}
|
||||
|
||||
if ((int)value < 0 || (int)value > 12)
|
||||
{
|
||||
throw new Exception($"Property {name} value should be between 0 and 12.");
|
||||
}
|
||||
|
||||
return $"{value}";
|
||||
}
|
||||
|
||||
string GetOrderValue(string name, string value)
|
||||
{
|
||||
var orders = Enumerable.Range(0, 12).Select(i => $"{i}").ToArray().Concat(new string[] { "first", "last" });
|
||||
|
||||
if (!orders.Contains(value))
|
||||
{
|
||||
throw new Exception($"Property {name} value should be between 0 and 12 or first/last.");
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -21,6 +21,13 @@ namespace Radzen.Blazor
|
||||
[Parameter]
|
||||
public double Margin { get; set; } = 10;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the width of all columns in pixels. By default it is automatically calculated depending on the chart width.
|
||||
/// </summary>
|
||||
/// <value>The pixel width of the column. By default set to <c>null</c></value>
|
||||
[Parameter]
|
||||
public double? Width { get; set;}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Initialize()
|
||||
{
|
||||
@@ -30,7 +37,9 @@ namespace Radzen.Blazor
|
||||
/// <inheritdoc />
|
||||
protected override bool ShouldRefreshChart(ParameterView parameters)
|
||||
{
|
||||
return DidParameterChange(parameters, nameof(Radius), Radius) || DidParameterChange(parameters, nameof(Margin), Margin);
|
||||
return DidParameterChange(parameters, nameof(Radius), Radius) ||
|
||||
DidParameterChange(parameters, nameof(Width), Width) ||
|
||||
DidParameterChange(parameters, nameof(Margin), Margin);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using Microsoft.AspNetCore.Components;
|
||||
using Radzen.Blazor.Rendering;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
@@ -115,20 +116,29 @@ namespace Radzen.Blazor
|
||||
{
|
||||
get
|
||||
{
|
||||
var availableWidth = Chart.CategoryScale.OutputSize - (Chart.CategoryAxis.Padding * 2);
|
||||
var bands = VisibleColumnSeries.Cast<IChartColumnSeries>().Max(series => series.Count) + 2;
|
||||
return availableWidth / bands;
|
||||
var columnSeries = VisibleColumnSeries;
|
||||
|
||||
if (Chart.ColumnOptions.Width.HasValue)
|
||||
{
|
||||
return Chart.ColumnOptions.Width.Value * columnSeries.Count + Chart.ColumnOptions.Margin * (columnSeries.Count - 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
var availableWidth = Chart.CategoryScale.OutputSize - (Chart.CategoryAxis.Padding * 2);
|
||||
var bands = columnSeries.Cast<IChartColumnSeries>().Max(series => series.Count) + 2;
|
||||
return availableWidth / bands;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override bool Contains(double x, double y, double tolerance)
|
||||
{
|
||||
return DataAt(x, y) != null;
|
||||
return DataAt(x, y).Item1 != null;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override double TooltipX(TItem item)
|
||||
internal override double TooltipX(TItem item)
|
||||
{
|
||||
var columnSeries = VisibleColumnSeries;
|
||||
var index = columnSeries.IndexOf(this);
|
||||
@@ -142,7 +152,7 @@ namespace Radzen.Blazor
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override double TooltipY(TItem item)
|
||||
internal override double TooltipY(TItem item)
|
||||
{
|
||||
var y = base.TooltipY(item);
|
||||
var ticks = Chart.ValueScale.Ticks(Chart.ValueAxis.TickDistance);
|
||||
@@ -152,7 +162,7 @@ namespace Radzen.Blazor
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override object DataAt(double x, double y)
|
||||
public override (object, Point) DataAt(double x, double y)
|
||||
{
|
||||
var category = ComposeCategory(Chart.CategoryScale);
|
||||
var value = ComposeValue(Chart.ValueScale);
|
||||
@@ -163,7 +173,7 @@ namespace Radzen.Blazor
|
||||
var index = columnSeries.IndexOf(this);
|
||||
var padding = Chart.ColumnOptions.Margin;
|
||||
var bandWidth = BandWidth;
|
||||
var width = bandWidth / columnSeries.Count() - padding + padding / columnSeries.Count();
|
||||
var width = Chart.ColumnOptions.Width ?? bandWidth / columnSeries.Count() - padding + padding / columnSeries.Count();
|
||||
|
||||
foreach (var data in Items)
|
||||
{
|
||||
@@ -175,11 +185,17 @@ namespace Radzen.Blazor
|
||||
|
||||
if (startX <= x && x <= endX && startY <= y && y <= endY)
|
||||
{
|
||||
return data;
|
||||
return (data, new Point() { X = x, Y = y });
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
return (null, null);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override IEnumerable<ChartDataLabel> GetDataLabels(double offsetX, double offsetY)
|
||||
{
|
||||
return base.GetDataLabels(offsetX, offsetY - 16);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,7 +22,7 @@ namespace Radzen
|
||||
/// <summary>
|
||||
/// Gets a reference to the HTML element rendered by the component.
|
||||
/// </summary>
|
||||
public ElementReference Element { get; internal set; }
|
||||
public ElementReference Element { get; protected internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// A callback that will be invoked when the user hovers the component. Commonly used to display a tooltip via
|
||||
@@ -233,17 +233,17 @@ namespace Radzen
|
||||
{
|
||||
if (ContextMenu.HasDelegate)
|
||||
{
|
||||
await JSRuntime.InvokeVoidAsync("Radzen.addContextMenu", UniqueID, Reference);
|
||||
await JSRuntime.InvokeVoidAsync("Radzen.addContextMenu", GetId(), Reference);
|
||||
}
|
||||
|
||||
if (MouseEnter.HasDelegate)
|
||||
{
|
||||
await JSRuntime.InvokeVoidAsync("Radzen.addMouseEnter", UniqueID, Reference);
|
||||
await JSRuntime.InvokeVoidAsync("Radzen.addMouseEnter", GetId(), Reference);
|
||||
}
|
||||
|
||||
if (MouseLeave.HasDelegate)
|
||||
{
|
||||
await JSRuntime.InvokeVoidAsync("Radzen.addMouseLeave", UniqueID, Reference);
|
||||
await JSRuntime.InvokeVoidAsync("Radzen.addMouseLeave", GetId(), Reference);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -347,4 +347,4 @@ namespace Radzen
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
78
Radzen.Blazor/RadzenComponentActivator.cs
Normal file
78
Radzen.Blazor/RadzenComponentActivator.cs
Normal file
@@ -0,0 +1,78 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Microsoft.AspNetCore.Components;
|
||||
|
||||
#if NET5_0_OR_GREATER
|
||||
namespace Radzen
|
||||
{
|
||||
/// <summary>
|
||||
/// Allows the developer to replace a component with another. Useful to specify default values for component properties.
|
||||
/// </summary>
|
||||
/// <example>
|
||||
/// <code>
|
||||
/// var builder = WebApplication.CreateBuilder(args);
|
||||
/// var activator = new RadzenComponentActivator();
|
||||
/// // Replace RadzenButton with MyButton
|
||||
/// activator.Override<RadzenButton, MyButton>();
|
||||
/// // Replace RadzenDataGrid with MyDataGrid
|
||||
/// activator.Override(typeof(RadzenDataGrid<>), typeof(MyDataGrid<>));
|
||||
/// // Register the activator
|
||||
/// builder.Services.AddSingleton<IComponentActivator>(activator);
|
||||
/// </code>
|
||||
/// </example>
|
||||
public class RadzenComponentActivator : IComponentActivator
|
||||
{
|
||||
private readonly Dictionary<Type, Type> replacedTypes = new Dictionary<Type, Type>();
|
||||
|
||||
/// <summary>
|
||||
/// Replaces the specified component type with another.
|
||||
/// </summary>
|
||||
/// <typeparam name="TOriginal"></typeparam>
|
||||
/// <typeparam name="TOverride"></typeparam>
|
||||
public void Override<TOriginal, TOverride>()
|
||||
{
|
||||
Override(typeof(TOriginal), typeof(TOverride));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Replaces the specified component type with another.
|
||||
/// </summary>
|
||||
/// <param name="original"></param>
|
||||
/// <param name="override"></param>
|
||||
public void Override(Type original, Type @override)
|
||||
{
|
||||
replacedTypes.Add(original, @override);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a component of the specified type.
|
||||
/// </summary>
|
||||
/// <param name="componentType"></param>
|
||||
/// <returns></returns>
|
||||
/// <exception cref="ArgumentException"></exception>
|
||||
public IComponent CreateInstance(Type componentType)
|
||||
{
|
||||
if (!typeof(IComponent).IsAssignableFrom(componentType))
|
||||
{
|
||||
throw new ArgumentException($"The type {componentType.FullName} does not implement {nameof(IComponent)}.", nameof(componentType));
|
||||
}
|
||||
|
||||
if (replacedTypes.ContainsKey(componentType))
|
||||
{
|
||||
componentType = replacedTypes[componentType];
|
||||
}
|
||||
else if (componentType.IsGenericType)
|
||||
{
|
||||
var genericTypeDefinition = componentType.GetGenericTypeDefinition();
|
||||
|
||||
if (replacedTypes.ContainsKey(genericTypeDefinition))
|
||||
{
|
||||
componentType = replacedTypes[genericTypeDefinition].MakeGenericType(componentType.GetGenericArguments());
|
||||
}
|
||||
}
|
||||
|
||||
return (IComponent)Activator.CreateInstance(componentType);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
4
Radzen.Blazor/RadzenComponents.razor
Normal file
4
Radzen.Blazor/RadzenComponents.razor
Normal file
@@ -0,0 +1,4 @@
|
||||
<RadzenDialog />
|
||||
<RadzenNotification />
|
||||
<RadzenContextMenu />
|
||||
<RadzenTooltip />
|
||||
@@ -1,4 +1,4 @@
|
||||
@implements IDisposable
|
||||
@implements IAsyncDisposable
|
||||
@using Microsoft.JSInterop
|
||||
@inject IJSRuntime JSRuntime
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
<RadzenMenu Click="@(args => { if (menu.Options.Click != null) { menu.Options.Click(args); } })" Responsive="false">
|
||||
@foreach (var item in menu.Options.Items)
|
||||
{
|
||||
<RadzenMenuItem Text="@item.Text" Value="@item.Value"></RadzenMenuItem>
|
||||
<RadzenMenuItem Text="@item.Text" Value="@item.Value" Icon="@item.Icon" IconColor="@item.IconColor" Image="@item.Image"></RadzenMenuItem>
|
||||
}
|
||||
</RadzenMenu>
|
||||
</div>
|
||||
|
||||
@@ -35,7 +35,7 @@ namespace Radzen.Blazor
|
||||
/// }
|
||||
/// </code>
|
||||
/// </example>
|
||||
public partial class RadzenContextMenu
|
||||
public partial class RadzenContextMenu : IAsyncDisposable
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the unique identifier.
|
||||
@@ -77,7 +77,28 @@ namespace Radzen.Blazor
|
||||
await JSRuntime.InvokeVoidAsync("Radzen.openContextMenu",
|
||||
menu.MouseEventArgs.ClientX,
|
||||
menu.MouseEventArgs.ClientY,
|
||||
UniqueID);
|
||||
UniqueID,
|
||||
Reference,
|
||||
"RadzenContextMenu.CloseMenu");
|
||||
}
|
||||
}
|
||||
|
||||
private DotNetObjectReference<RadzenContextMenu> reference;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the reference for the current component.
|
||||
/// </summary>
|
||||
/// <value>The reference.</value>
|
||||
protected DotNetObjectReference<RadzenContextMenu> Reference
|
||||
{
|
||||
get
|
||||
{
|
||||
if (reference == null)
|
||||
{
|
||||
reference = DotNetObjectReference.Create(this);
|
||||
}
|
||||
|
||||
return reference;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -96,12 +117,34 @@ namespace Radzen.Blazor
|
||||
await InvokeAsync(() => { StateHasChanged(); });
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void Dispose()
|
||||
/// <summary>
|
||||
/// Closes this instance.
|
||||
/// </summary>
|
||||
[JSInvokable("RadzenContextMenu.CloseMenu")]
|
||||
public void CloseMenu()
|
||||
{
|
||||
Service.Close();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async ValueTask DisposeAsync()
|
||||
{
|
||||
while (menus.Count != 0)
|
||||
{
|
||||
await Close();
|
||||
}
|
||||
|
||||
reference?.Dispose();
|
||||
reference = null;
|
||||
|
||||
if (IsJSRuntimeAvailable)
|
||||
{
|
||||
JSRuntime.InvokeVoidAsync("Radzen.destroyPopup", UniqueID);
|
||||
try
|
||||
{
|
||||
await JSRuntime.InvokeVoidAsync("Radzen.destroyPopup", UniqueID);
|
||||
}
|
||||
catch
|
||||
{ }
|
||||
}
|
||||
|
||||
Service.OnOpen -= OnOpen;
|
||||
|
||||
52
Radzen.Blazor/RadzenCustomValidator.cs
Normal file
52
Radzen.Blazor/RadzenCustomValidator.cs
Normal file
@@ -0,0 +1,52 @@
|
||||
using System;
|
||||
using Microsoft.AspNetCore.Components;
|
||||
|
||||
namespace Radzen.Blazor
|
||||
{
|
||||
/// <summary>
|
||||
/// A validator component which compares a component value with a specified value.
|
||||
/// Must be placed inside a <see cref="RadzenTemplateForm{TItem}" />
|
||||
/// </summary>
|
||||
/// <example>
|
||||
/// <code>
|
||||
/// <RadzenTemplateForm TItem="Model" Data=@model>
|
||||
/// <RadzenTextBox Name="Email" @bind-Value=@model.Email />
|
||||
/// <RadzenCustomValidator Value=@model.Email Component="Email" Text="Email must be unique" Validator="@(() => ValidateNewEmail(model.Email))" Style="position: absolute" />
|
||||
/// </RadzenTemplateForm>
|
||||
/// @code {
|
||||
/// class Model
|
||||
/// {
|
||||
/// public string Email { get; set; }
|
||||
/// }
|
||||
/// Model model = new Model();
|
||||
///
|
||||
/// string[] emails = new string[] { "andy@smith" };
|
||||
///
|
||||
/// bool ValidateNewEmail(string email)
|
||||
/// {
|
||||
/// return !emails.Any(e => e.ToUpper().Equals(email.ToUpper()));
|
||||
/// }
|
||||
/// }
|
||||
/// </code>
|
||||
/// </example>
|
||||
public class RadzenCustomValidator : ValidatorBase
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the message displayed when the component is invalid. Set to <c>"Value should match"</c> by default.
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
public override string Text { get; set; } = "Value should match";
|
||||
|
||||
/// <summary>
|
||||
/// Specifies the function which validates the component value. Must return <c>true</c> if the component is valid.
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
public Func<bool> Validator { get; set; } = () => true;
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override bool Validate(IRadzenFormComponent component)
|
||||
{
|
||||
return Validator();
|
||||
}
|
||||
}
|
||||
}
|
||||
38
Radzen.Blazor/RadzenDataFilter.razor
Normal file
38
Radzen.Blazor/RadzenDataFilter.razor
Normal file
@@ -0,0 +1,38 @@
|
||||
@using System.Linq.Expressions
|
||||
@typeparam TItem
|
||||
@inherits RadzenComponent
|
||||
|
||||
@if (Properties != null)
|
||||
{
|
||||
<CascadingValue Value=this>
|
||||
@Properties
|
||||
</CascadingValue>
|
||||
}
|
||||
|
||||
@if (Visible)
|
||||
{
|
||||
<div @ref="@Element" style="@Style" @attributes="Attributes" class="@GetCssClass()" id="@GetId()">
|
||||
<RadzenSelectBar @bind-Value=LogicalFilterOperator Change="@((LogicalFilterOperator args) => { InvokeAsync(ChangeState); if(Auto) { InvokeAsync(Filter); } })" Size="ButtonSize.Small" class="rz-datafilter-operator-bar">
|
||||
<Items>
|
||||
<RadzenSelectBarItem Text="@AndOperatorText" Value="LogicalFilterOperator.And" title="@AndOperatorText" />
|
||||
<RadzenSelectBarItem Text="@OrOperatorText" Value="LogicalFilterOperator.Or" title="@OrOperatorText" />
|
||||
</Items>
|
||||
</RadzenSelectBar>
|
||||
<RadzenButton title="@ClearFilterText" class="rz-datafilter-item-clear rz-datafilter-all-items-clear" Icon="clear" Click="@(args => ClearFilters())" Visible=@(Filters.Any()) Variant="Variant.Text" Size="ButtonSize.Small" ButtonStyle="ButtonStyle.Dark" />
|
||||
|
||||
<ul class="rz-datafilter-group">
|
||||
@foreach(var filter in Filters)
|
||||
{
|
||||
<li class="rz-datafilter-item @(filter.Filters != null ? "rz-datafilter-group-item" : "")">
|
||||
<RadzenDataFilterItem @key=@filter.GetHashCode() DataFilter="@this" Filter="@filter" />
|
||||
</li>
|
||||
}
|
||||
<li class="rz-datafilter-item rz-datafilter-bar">
|
||||
<RadzenSplitButton Icon="add" Click="@(args => AddFilter(args?.Value == "group"))" Size="ButtonSize.Small" Variant="Variant.Flat" ButtonStyle="ButtonStyle.Primary" Shade="Shade.Lighter">
|
||||
<RadzenSplitButtonItem Icon="add" Text="@AddFilterText" />
|
||||
<RadzenSplitButtonItem Icon="playlist_add" Value="group" Text="@AddFilterGroupText" />
|
||||
</RadzenSplitButton>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
}
|
||||
410
Radzen.Blazor/RadzenDataFilter.razor.cs
Normal file
410
Radzen.Blazor/RadzenDataFilter.razor.cs
Normal file
@@ -0,0 +1,410 @@
|
||||
using Microsoft.AspNetCore.Components;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Radzen.Blazor
|
||||
{
|
||||
/// <summary>
|
||||
/// RadzenDataFilter component.
|
||||
/// </summary>
|
||||
/// <typeparam name="TItem">The type of the item.</typeparam>
|
||||
public partial class RadzenDataFilter<TItem> : RadzenComponent
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override string GetComponentCssClass()
|
||||
{
|
||||
return "rz-datafilter";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the properties.
|
||||
/// </summary>
|
||||
/// <value>The properties.</value>
|
||||
[Parameter]
|
||||
public RenderFragment Properties { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The data
|
||||
/// </summary>
|
||||
IEnumerable<TItem> _data;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the data.
|
||||
/// </summary>
|
||||
/// <value>The data.</value>
|
||||
[Parameter]
|
||||
public IEnumerable<TItem> Data
|
||||
{
|
||||
get
|
||||
{
|
||||
return _data;
|
||||
}
|
||||
set
|
||||
{
|
||||
if (_data != value)
|
||||
{
|
||||
_data = value;
|
||||
StateHasChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
IQueryable<TItem> _view = null;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the view.
|
||||
/// </summary>
|
||||
/// <value>The view.</value>
|
||||
public virtual IQueryable<TItem> View
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_view == null)
|
||||
{
|
||||
_view = Data != null ? Data.AsQueryable().Where<TItem>(this) : Enumerable.Empty<TItem>().AsQueryable();
|
||||
}
|
||||
|
||||
return _view;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether this filter is automatic.
|
||||
/// </summary>
|
||||
/// <value><c>true</c> if filter automatic; otherwise, <c>false</c>.</value>
|
||||
[Parameter]
|
||||
public bool Auto { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the filters.
|
||||
/// </summary>
|
||||
/// <value>The filters.</value>
|
||||
public IEnumerable<CompositeFilterDescriptor> Filters { get; set; } = Enumerable.Empty<CompositeFilterDescriptor>();
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the logical filter operator.
|
||||
/// </summary>
|
||||
/// <value>The logical filter operator.</value>
|
||||
[Parameter]
|
||||
public LogicalFilterOperator LogicalFilterOperator { get; set; } = LogicalFilterOperator.And;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the filter case sensitivity.
|
||||
/// </summary>
|
||||
/// <value>The filter case sensitivity.</value>
|
||||
[Parameter]
|
||||
public FilterCaseSensitivity FilterCaseSensitivity { get; set; } = FilterCaseSensitivity.Default;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the filter text.
|
||||
/// </summary>
|
||||
/// <value>The filter text.</value>
|
||||
[Parameter]
|
||||
public string FilterText { get; set; } = "Filter";
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the enum filter select text.
|
||||
/// </summary>
|
||||
/// <value>The enum filter select text.</value>
|
||||
[Parameter]
|
||||
public string EnumFilterSelectText { get; set; } = "Select...";
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the and operator text.
|
||||
/// </summary>
|
||||
/// <value>The and operator text.</value>
|
||||
[Parameter]
|
||||
public string AndOperatorText { get; set; } = "And";
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the or operator text.
|
||||
/// </summary>
|
||||
/// <value>The or operator text.</value>
|
||||
[Parameter]
|
||||
public string OrOperatorText { get; set; } = "Or";
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the apply filter text.
|
||||
/// </summary>
|
||||
/// <value>The apply filter text.</value>
|
||||
[Parameter]
|
||||
public string ApplyFilterText { get; set; } = "Apply";
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the clear filter text.
|
||||
/// </summary>
|
||||
/// <value>The clear filter text.</value>
|
||||
[Parameter]
|
||||
public string ClearFilterText { get; set; } = "Clear all";
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the add filter text.
|
||||
/// </summary>
|
||||
/// <value>The add filter text.</value>
|
||||
[Parameter]
|
||||
public string AddFilterText { get; set; } = "Add filter";
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the remove filter text.
|
||||
/// </summary>
|
||||
/// <value>The remove filter text.</value>
|
||||
[Parameter]
|
||||
public string RemoveFilterText { get; set; } = "Remove filter";
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the add filter group text.
|
||||
/// </summary>
|
||||
/// <value>The add filter group text.</value>
|
||||
[Parameter]
|
||||
public string AddFilterGroupText { get; set; } = "Add filter group";
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the equals text.
|
||||
/// </summary>
|
||||
/// <value>The equals text.</value>
|
||||
[Parameter]
|
||||
public string EqualsText { get; set; } = "Equals";
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the not equals text.
|
||||
/// </summary>
|
||||
/// <value>The not equals text.</value>
|
||||
[Parameter]
|
||||
public string NotEqualsText { get; set; } = "Not equals";
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the less than text.
|
||||
/// </summary>
|
||||
/// <value>The less than text.</value>
|
||||
[Parameter]
|
||||
public string LessThanText { get; set; } = "Less than";
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the less than or equals text.
|
||||
/// </summary>
|
||||
/// <value>The less than or equals text.</value>
|
||||
[Parameter]
|
||||
public string LessThanOrEqualsText { get; set; } = "Less than or equals";
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the greater than text.
|
||||
/// </summary>
|
||||
/// <value>The greater than text.</value>
|
||||
[Parameter]
|
||||
public string GreaterThanText { get; set; } = "Greater than";
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the greater than or equals text.
|
||||
/// </summary>
|
||||
/// <value>The greater than or equals text.</value>
|
||||
[Parameter]
|
||||
public string GreaterThanOrEqualsText { get; set; } = "Greater than or equals";
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the ends with text.
|
||||
/// </summary>
|
||||
/// <value>The ends with text.</value>
|
||||
[Parameter]
|
||||
public string EndsWithText { get; set; } = "Ends with";
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the contains text.
|
||||
/// </summary>
|
||||
/// <value>The contains text.</value>
|
||||
[Parameter]
|
||||
public string ContainsText { get; set; } = "Contains";
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the does not contain text.
|
||||
/// </summary>
|
||||
/// <value>The does not contain text.</value>
|
||||
[Parameter]
|
||||
public string DoesNotContainText { get; set; } = "Does not contain";
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the starts with text.
|
||||
/// </summary>
|
||||
/// <value>The starts with text.</value>
|
||||
[Parameter]
|
||||
public string StartsWithText { get; set; } = "Starts with";
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the not null text.
|
||||
/// </summary>
|
||||
/// <value>The not null text.</value>
|
||||
[Parameter]
|
||||
public string IsNotNullText { get; set; } = "Is not null";
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the is null text.
|
||||
/// </summary>
|
||||
/// <value>The null text.</value>
|
||||
[Parameter]
|
||||
public string IsNullText { get; set; } = "Is null";
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the is empty text.
|
||||
/// </summary>
|
||||
/// <value>The empty text.</value>
|
||||
[Parameter]
|
||||
public string IsEmptyText { get; set; } = "Is empty";
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the is not empty text.
|
||||
/// </summary>
|
||||
/// <value>The not empty text.</value>
|
||||
[Parameter]
|
||||
public string IsNotEmptyText { get; set; } = "Is not empty";
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether the columns can be filtered.
|
||||
/// </summary>
|
||||
/// <value><c>true</c> if columns can be filtered; otherwise, <c>false</c>.</value>
|
||||
[Parameter]
|
||||
public bool AllowColumnFiltering { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether properties can be reused in the filter.
|
||||
/// </summary>
|
||||
/// <value><c>true</c>, if there is only one filter by property; otherwise <c>false</c>.</value>
|
||||
[Parameter]
|
||||
public bool UniqueFilters { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the properties collection.
|
||||
/// </summary>
|
||||
/// <value>The properties collection.</value>
|
||||
public IList<RadzenDataFilterProperty<TItem>> PropertiesCollection
|
||||
{
|
||||
get
|
||||
{
|
||||
return properties;
|
||||
}
|
||||
}
|
||||
|
||||
internal List<RadzenDataFilterProperty<TItem>> properties = new List<RadzenDataFilterProperty<TItem>>();
|
||||
internal void AddProperty(RadzenDataFilterProperty<TItem> property)
|
||||
{
|
||||
if (!properties.Contains(property))
|
||||
{
|
||||
properties.Add(property);
|
||||
}
|
||||
|
||||
StateHasChanged();
|
||||
}
|
||||
|
||||
internal void RemoveProperty(RadzenDataFilterProperty<TItem> property)
|
||||
{
|
||||
if (properties.Contains(property))
|
||||
{
|
||||
properties.Remove(property);
|
||||
}
|
||||
|
||||
if (!disposed)
|
||||
{
|
||||
try { InvokeAsync(StateHasChanged); } catch { }
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Recreates View using current Filters.
|
||||
/// </summary>
|
||||
public async Task Filter()
|
||||
{
|
||||
_view = null;
|
||||
|
||||
await ViewChanged.InvokeAsync(View);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the view changed callback.
|
||||
/// </summary>
|
||||
/// <value>The view changed callback.</value>
|
||||
[Parameter]
|
||||
public EventCallback<IQueryable<TItem>> ViewChanged { get; set; }
|
||||
|
||||
internal async Task ChangeState()
|
||||
{
|
||||
await InvokeAsync(StateHasChanged);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the filter date format.
|
||||
/// </summary>
|
||||
/// <value>The filter date format.</value>
|
||||
[Parameter]
|
||||
public string FilterDateFormat { get; set; }
|
||||
|
||||
internal async Task AddFilter(bool isGroup)
|
||||
{
|
||||
if (UniqueFilters && properties.All(f => f.IsSelected))
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (isGroup)
|
||||
{
|
||||
Filters = Filters.Concat(new CompositeFilterDescriptor[]
|
||||
{
|
||||
new CompositeFilterDescriptor()
|
||||
{
|
||||
Filters = Enumerable.Empty<CompositeFilterDescriptor>()
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
Filters = Filters.Concat(new CompositeFilterDescriptor[] { new CompositeFilterDescriptor() });
|
||||
}
|
||||
|
||||
if (Auto)
|
||||
{
|
||||
await Filter();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Clear filters.
|
||||
/// </summary>
|
||||
public async Task ClearFilters()
|
||||
{
|
||||
Filters = Enumerable.Empty<CompositeFilterDescriptor>();
|
||||
|
||||
properties.ForEach(p => p.IsSelected = false);
|
||||
|
||||
if (Auto)
|
||||
{
|
||||
await Filter();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Add filter.
|
||||
/// </summary>
|
||||
public async Task AddFilter(CompositeFilterDescriptor filter)
|
||||
{
|
||||
Filters = Filters.Concat(new CompositeFilterDescriptor[] { filter });
|
||||
|
||||
if (Auto)
|
||||
{
|
||||
await Filter();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Remove filter.
|
||||
/// </summary>
|
||||
public async Task RemoveFilter(CompositeFilterDescriptor filter)
|
||||
{
|
||||
Filters = Filters.Where(f => f != filter);
|
||||
|
||||
if (Auto)
|
||||
{
|
||||
await Filter();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
316
Radzen.Blazor/RadzenDataFilterItem.razor
Normal file
316
Radzen.Blazor/RadzenDataFilterItem.razor
Normal file
@@ -0,0 +1,316 @@
|
||||
@typeparam TItem
|
||||
@if (Filter.Filters != null)
|
||||
{
|
||||
<RadzenSelectBar @bind-Value=Filter.LogicalFilterOperator Change="@((LogicalFilterOperator args) => { InvokeAsync(ChangeState); InvokeAsync(ApplyFilter); })" Size="ButtonSize.Small">
|
||||
<Items>
|
||||
<RadzenSelectBarItem Text="@DataFilter.AndOperatorText" Value="LogicalFilterOperator.And" title="@DataFilter.AndOperatorText" />
|
||||
<RadzenSelectBarItem Text="@DataFilter.OrOperatorText" Value="LogicalFilterOperator.Or" title="@DataFilter.OrOperatorText" />
|
||||
</Items>
|
||||
</RadzenSelectBar>
|
||||
|
||||
<RadzenButton title="@DataFilter.RemoveFilterText" class="rz-datafilter-item-clear" Icon="clear" Click="@RemoveFilter" Variant="Variant.Text" Size="ButtonSize.Small" ButtonStyle="ButtonStyle.Dark"/>
|
||||
|
||||
<ul class="rz-datafilter-group">
|
||||
@foreach(var filter in Filter.Filters)
|
||||
{
|
||||
<li class="rz-datafilter-item @(filter.Filters != null ? "rz-datafilter-group-item" : "")">
|
||||
<RadzenDataFilterItem DataFilter="@this.DataFilter" Filter="@filter" Parent=@this />
|
||||
</li>
|
||||
}
|
||||
<li class="rz-datafilter-item rz-datafilter-bar">
|
||||
<RadzenSplitButton Icon="add" Click="@(args => AddFilter(args?.Value == "group"))" Size="ButtonSize.Small" Variant="Variant.Flat" ButtonStyle="ButtonStyle.Primary" Shade="Shade.Lighter">
|
||||
<RadzenSplitButtonItem Icon="add" Text="@DataFilter.AddFilterText" />
|
||||
<RadzenSplitButtonItem Icon="playlist_add" Value="group" Text="@DataFilter.AddFilterGroupText" />
|
||||
</RadzenSplitButton>
|
||||
</li>
|
||||
</ul>
|
||||
}
|
||||
else
|
||||
{
|
||||
<RadzenDropDown @bind-Value="@Filter.Property" Data="@(DataFilter?.properties)" TextProperty="Title" ValueProperty="Property" TValue="string"
|
||||
DisabledProperty="@(DataFilter?.UniqueFilters == true ? nameof(property.IsSelected) : null)"
|
||||
Change="@OnPropertyChange" AllowFiltering="@(DataFilter?.AllowColumnFiltering ?? false)" FilterCaseSensitivity="FilterCaseSensitivity.CaseInsensitive" class="rz-datafilter-property">
|
||||
<Template>
|
||||
@{
|
||||
var property = (RadzenDataFilterProperty<TItem>)context;
|
||||
}
|
||||
@(property.Title ?? property.Property)
|
||||
</Template>
|
||||
</RadzenDropDown>
|
||||
if (property != null)
|
||||
{
|
||||
<RadzenDropDown @onclick:preventDefault="true" Data="@(property.GetFilterOperators().Select(t => new { Value = property.GetFilterOperatorText(t), Key = t }))"
|
||||
TextProperty="Value" ValueProperty="Key" TValue="FilterOperator" @bind-Value="@Filter.FilterOperator" Change="@OnOperatorChange" class="rz-datafilter-operator" />
|
||||
@if (property.FilterTemplate != null)
|
||||
{
|
||||
<div class="rz-datafilter-editor" style="display:flex">
|
||||
@property.FilterTemplate(Filter)
|
||||
</div>
|
||||
}
|
||||
else if (PropertyAccess.IsNullableEnum(property.FilterPropertyType) || PropertyAccess.IsEnum(property.FilterPropertyType))
|
||||
{
|
||||
<RadzenDropDown Disabled="@IsOperatorNullOrEmpty()" AllowClear="false" AllowFiltering="false" TValue="@object" class="rz-datafilter-editor"
|
||||
@bind-Value=@Filter.FilterValue Multiple="false" Placeholder="@DataFilter.EnumFilterSelectText" TextProperty="Text" ValueProperty="Value"
|
||||
Data=@EnumExtensions.EnumAsKeyValuePair(Nullable.GetUnderlyingType(property.FilterPropertyType) ?? property.FilterPropertyType) Change=@(args => InvokeAsync(ApplyFilter))/>
|
||||
}
|
||||
else if (PropertyAccess.IsNumeric(property.FilterPropertyType))
|
||||
{
|
||||
@(DrawNumericFilter())
|
||||
}
|
||||
else if (PropertyAccess.IsDate(property.FilterPropertyType))
|
||||
{
|
||||
<RadzenDatePicker Disabled="@IsOperatorNullOrEmpty()" @bind-Value=@Filter.FilterValue TValue="@object" ShowTime="true" class="rz-datafilter-editor"
|
||||
ShowTimeOkButton="true" DateFormat="@getFilterDateFormat()" Change=@(args => InvokeAsync(ApplyFilter)) />
|
||||
}
|
||||
else if (property.FilterPropertyType == typeof(bool) || property.FilterPropertyType == typeof(bool?))
|
||||
{
|
||||
<RadzenCheckBox Disabled="@IsOperatorNullOrEmpty()" TriState="true" TValue="@object" @bind-Value=@Filter.FilterValue Change=@(args => InvokeAsync(ApplyFilter)) class="rz-datafilter-check" />
|
||||
}
|
||||
else
|
||||
{
|
||||
<RadzenTextBox Disabled="@IsOperatorNullOrEmpty()" class="rz-datafilter-editor" Value="@($"{Filter.FilterValue}")" Change=@(args => { Filter.FilterValue = args; InvokeAsync(ApplyFilter); }) />
|
||||
}
|
||||
|
||||
<RadzenButton title="@DataFilter.RemoveFilterText" class="rz-datafilter-item-clear" Icon="clear" Click="@RemoveFilter" Variant="Variant.Text" Size="ButtonSize.Small" ButtonStyle="ButtonStyle.Dark"/>
|
||||
}
|
||||
}
|
||||
@code {
|
||||
[Parameter]
|
||||
public RadzenDataFilter<TItem> DataFilter { get; set; }
|
||||
|
||||
[Parameter]
|
||||
public RadzenDataFilterItem<TItem> Parent { get; set; }
|
||||
|
||||
CompositeFilterDescriptor _filter;
|
||||
[Parameter]
|
||||
public CompositeFilterDescriptor Filter
|
||||
{
|
||||
get
|
||||
{
|
||||
return _filter;
|
||||
}
|
||||
set
|
||||
{
|
||||
_filter = value;
|
||||
|
||||
if (property == null && Filter.Filters == null)
|
||||
{
|
||||
if (Filter.Property != null)
|
||||
{
|
||||
property = DataFilter?.properties.FirstOrDefault(f => object.Equals(f.Property, Filter.Property));
|
||||
}
|
||||
else if (property == null && DataFilter?.UniqueFilters == true)
|
||||
{
|
||||
property = DataFilter?.properties.FirstOrDefault(f => f.IsSelected == false);
|
||||
}
|
||||
else
|
||||
{
|
||||
property = DataFilter?.properties.FirstOrDefault();
|
||||
}
|
||||
|
||||
if (property != null)
|
||||
{
|
||||
property.FilterValueChange -= OnFilterValueChange;
|
||||
property.FilterValueChange += OnFilterValueChange;
|
||||
|
||||
if (DataFilter?.UniqueFilters == true)
|
||||
{
|
||||
property.IsSelected = true;
|
||||
}
|
||||
|
||||
Filter.Property = property.Property;
|
||||
|
||||
if (!property.GetFilterOperators().Contains(Filter.FilterOperator))
|
||||
{
|
||||
Filter.FilterOperator = property.GetFilterOperators().FirstOrDefault();
|
||||
}
|
||||
|
||||
var v = property.GetFilterValue();
|
||||
if (v != null)
|
||||
{
|
||||
Filter.FilterValue = v;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void OnFilterValueChange(object value)
|
||||
{
|
||||
if (property != null)
|
||||
{
|
||||
Filter.FilterValue = property.GetFilterValue();
|
||||
}
|
||||
}
|
||||
|
||||
RadzenDataFilterProperty<TItem> property;
|
||||
|
||||
async Task ApplyFilter()
|
||||
{
|
||||
if (DataFilter.Auto)
|
||||
{
|
||||
await DataFilter.Filter();
|
||||
}
|
||||
}
|
||||
|
||||
async Task OnPropertyChange(object p)
|
||||
{
|
||||
property.FilterValueChange -= OnFilterValueChange;
|
||||
property.IsSelected = false;
|
||||
|
||||
property = DataFilter.properties.Where(c => object.Equals(c.Property, p)).FirstOrDefault();
|
||||
|
||||
property.FilterValueChange += OnFilterValueChange;
|
||||
if (DataFilter?.UniqueFilters == true)
|
||||
{
|
||||
property.IsSelected = true;
|
||||
}
|
||||
Filter.FilterValue = null;
|
||||
|
||||
var defaultOperator = typeof(System.Collections.IEnumerable).IsAssignableFrom(property.FilterPropertyType) ? FilterOperator.Contains : default(FilterOperator);
|
||||
|
||||
if (property.GetFilterOperators().Any(o => o == property.FilterOperator))
|
||||
{
|
||||
Filter.FilterOperator = property.FilterOperator;
|
||||
}
|
||||
else if (property.GetFilterOperators().Contains(defaultOperator))
|
||||
{
|
||||
Filter.FilterOperator = defaultOperator;
|
||||
}
|
||||
else
|
||||
{
|
||||
Filter.FilterOperator = property.GetFilterOperators().FirstOrDefault();
|
||||
}
|
||||
|
||||
await ApplyFilter();
|
||||
}
|
||||
|
||||
bool IsOperatorNullOrEmpty()
|
||||
{
|
||||
if (Filter != null)
|
||||
{
|
||||
return Filter.FilterOperator == FilterOperator.IsEmpty || Filter.FilterOperator == FilterOperator.IsNotEmpty ||
|
||||
Filter.FilterOperator == FilterOperator.IsNull || Filter.FilterOperator == FilterOperator.IsNotNull;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
async Task OnOperatorChange(object p)
|
||||
{
|
||||
if (IsOperatorNullOrEmpty())
|
||||
{
|
||||
Filter.FilterValue = null;
|
||||
}
|
||||
|
||||
await ApplyFilter();
|
||||
}
|
||||
|
||||
async Task AddFilter(bool isGroup)
|
||||
{
|
||||
if (DataFilter?.UniqueFilters == true && DataFilter.properties.All(f => f.IsSelected))
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (isGroup)
|
||||
{
|
||||
Filter.Filters = Filter.Filters.Concat(new CompositeFilterDescriptor[]
|
||||
{
|
||||
new CompositeFilterDescriptor()
|
||||
{
|
||||
Filters = Enumerable.Empty<CompositeFilterDescriptor>()
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
Filter.Filters = Filter.Filters.Concat(new CompositeFilterDescriptor[] { new CompositeFilterDescriptor() });
|
||||
}
|
||||
|
||||
if (DataFilter.Auto)
|
||||
{
|
||||
await DataFilter.Filter();
|
||||
}
|
||||
}
|
||||
|
||||
async Task RemoveFilter()
|
||||
{
|
||||
if (property != null)
|
||||
{
|
||||
property.IsSelected = false;
|
||||
}
|
||||
property = null;
|
||||
|
||||
if (Parent != null)
|
||||
{
|
||||
Parent.Filter.Filters = Parent.Filter.Filters.Where(f => f != Filter).ToList();
|
||||
await Parent.ChangeState();
|
||||
}
|
||||
else
|
||||
{
|
||||
DataFilter.Filters = DataFilter.Filters.Where(f => f != Filter).ToList();
|
||||
await DataFilter.ChangeState();
|
||||
}
|
||||
|
||||
await ApplyFilter();
|
||||
}
|
||||
|
||||
internal async Task ChangeState()
|
||||
{
|
||||
await InvokeAsync(StateHasChanged);
|
||||
}
|
||||
|
||||
RenderFragment DrawNumericFilter()
|
||||
{
|
||||
return new RenderFragment(builder =>
|
||||
{
|
||||
var type = Nullable.GetUnderlyingType(property.FilterPropertyType) != null ?
|
||||
property.FilterPropertyType : typeof(Nullable<>).MakeGenericType(property.FilterPropertyType);
|
||||
|
||||
var numericType = typeof(RadzenNumeric<>).MakeGenericType(type);
|
||||
|
||||
builder.OpenComponent(0, numericType);
|
||||
|
||||
builder.AddAttribute(1, "Value", Filter.FilterValue);
|
||||
builder.AddAttribute(2, "class", "rz-datafilter-editor");
|
||||
builder.AddAttribute(3, "Disabled", IsOperatorNullOrEmpty());
|
||||
|
||||
Action<object> action = args =>
|
||||
{
|
||||
Filter.FilterValue = args; InvokeAsync(ApplyFilter);
|
||||
};
|
||||
|
||||
var eventCallbackGenericCreate = typeof(NumericFilterEventCallback).GetMethod("Create").MakeGenericMethod(type);
|
||||
var eventCallbackGenericAction = typeof(NumericFilterEventCallback).GetMethod("Action").MakeGenericMethod(type);
|
||||
|
||||
builder.AddAttribute(3, "Change", eventCallbackGenericCreate.Invoke(this,
|
||||
new object[] { this, eventCallbackGenericAction.Invoke(this, new object[] { action }) }));
|
||||
|
||||
builder.CloseComponent();
|
||||
});
|
||||
}
|
||||
|
||||
internal class NumericFilterEventCallback
|
||||
{
|
||||
public static EventCallback<T> Create<T>(object receiver, Action<T> action)
|
||||
{
|
||||
return EventCallback.Factory.Create<T>(receiver, action);
|
||||
}
|
||||
|
||||
public static Action<T> Action<T>(Action<object> action)
|
||||
{
|
||||
return args => action(args);
|
||||
}
|
||||
}
|
||||
|
||||
internal string getFilterDateFormat()
|
||||
{
|
||||
if (property != null && !string.IsNullOrEmpty(property.FormatString))
|
||||
{
|
||||
return property.FormatString.Replace("{0:", "").Replace("}", "");
|
||||
}
|
||||
|
||||
return DataFilter.FilterDateFormat;
|
||||
}
|
||||
}
|
||||
411
Radzen.Blazor/RadzenDataFilterProperty.cs
Normal file
411
Radzen.Blazor/RadzenDataFilterProperty.cs
Normal file
@@ -0,0 +1,411 @@
|
||||
using Microsoft.AspNetCore.Components;
|
||||
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
|
||||
{
|
||||
/// <summary>
|
||||
/// RadzenDataFilterProperty component.
|
||||
/// Must be placed inside a <see cref="RadzenDataFilter{TItem}" />
|
||||
/// </summary>
|
||||
/// <typeparam name="TItem">The type of the DataFilter item.</typeparam>
|
||||
public partial class RadzenDataFilterProperty<TItem> : ComponentBase, IDisposable
|
||||
{
|
||||
internal event Action<object> FilterValueChange;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the DataFilter.
|
||||
/// </summary>
|
||||
/// <value>The DataFilter.</value>
|
||||
[CascadingParameter]
|
||||
public RadzenDataFilter<TItem> DataFilter { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the format string.
|
||||
/// </summary>
|
||||
/// <value>The format string.</value>
|
||||
[Parameter]
|
||||
public string FormatString { get; set; }
|
||||
|
||||
internal void RemoveColumn(RadzenDataFilterProperty<TItem> property)
|
||||
{
|
||||
if (DataFilter.properties.Contains(property))
|
||||
{
|
||||
DataFilter.properties.Remove(property);
|
||||
if (!DataFilter.disposed)
|
||||
{
|
||||
try { InvokeAsync(StateHasChanged); } catch { }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called when initialized.
|
||||
/// </summary>
|
||||
protected override void OnInitialized()
|
||||
{
|
||||
if (DataFilter != null)
|
||||
{
|
||||
DataFilter.AddProperty(this);
|
||||
|
||||
var property = GetFilterProperty();
|
||||
|
||||
if (!string.IsNullOrEmpty(property) && Type == null)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(property))
|
||||
{
|
||||
_filterPropertyType = PropertyAccess.GetPropertyType(typeof(TItem), property);
|
||||
}
|
||||
}
|
||||
|
||||
if (_filterPropertyType == null)
|
||||
{
|
||||
_filterPropertyType = Type;
|
||||
}
|
||||
else
|
||||
{
|
||||
propertyValueGetter = PropertyAccess.Getter<TItem, object>(Property);
|
||||
}
|
||||
|
||||
if (_filterPropertyType == typeof(string))
|
||||
{
|
||||
FilterOperator = FilterOperator.Contains;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether this <see cref="RadzenDataGridColumn{TItem}"/> is visible.
|
||||
/// </summary>
|
||||
/// <value><c>true</c> if visible; otherwise, <c>false</c>.</value>
|
||||
[Parameter]
|
||||
public bool Visible { get; set; } = true;
|
||||
|
||||
bool? _visible;
|
||||
|
||||
/// <summary>
|
||||
/// Gets if the property is visible or not.
|
||||
/// </summary>
|
||||
/// <returns>System.Boolean.</returns>
|
||||
public bool GetVisible()
|
||||
{
|
||||
return _visible ?? Visible;
|
||||
}
|
||||
|
||||
internal void SetVisible(bool? value)
|
||||
{
|
||||
_visible = value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the title.
|
||||
/// </summary>
|
||||
/// <value>The title.</value>
|
||||
[Parameter]
|
||||
public string Title { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the property name.
|
||||
/// </summary>
|
||||
/// <value>The property name.</value>
|
||||
[Parameter]
|
||||
public string Property { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether this property is selected in the filter.
|
||||
/// </summary>
|
||||
/// <value><c>true</c>, if already selected; otherwise <c>false</c>.</value>
|
||||
[Parameter]
|
||||
public bool IsSelected { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the filter value.
|
||||
/// </summary>
|
||||
/// <value>The filter value.</value>
|
||||
[Parameter]
|
||||
public object FilterValue { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the filter template.
|
||||
/// </summary>
|
||||
/// <value>The filter template.</value>
|
||||
[Parameter]
|
||||
public RenderFragment<CompositeFilterDescriptor> FilterTemplate { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the data type.
|
||||
/// </summary>
|
||||
/// <value>The data type.</value>
|
||||
[Parameter]
|
||||
public Type Type { get; set; }
|
||||
|
||||
Func<TItem, object> propertyValueGetter;
|
||||
|
||||
internal object GetHeader()
|
||||
{
|
||||
if (!string.IsNullOrEmpty(Title))
|
||||
{
|
||||
return Title;
|
||||
}
|
||||
else
|
||||
{
|
||||
return Property;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the filter property.
|
||||
/// </summary>
|
||||
/// <returns>System.String.</returns>
|
||||
public string GetFilterProperty()
|
||||
{
|
||||
return Property;
|
||||
}
|
||||
|
||||
Type _filterPropertyType;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the filter property type.
|
||||
/// </summary>
|
||||
public Type FilterPropertyType
|
||||
{
|
||||
get
|
||||
{
|
||||
return _filterPropertyType;
|
||||
}
|
||||
}
|
||||
|
||||
object filterValue;
|
||||
FilterOperator? filterOperator;
|
||||
|
||||
/// <summary>
|
||||
/// Set parameters as an asynchronous operation.
|
||||
/// </summary>
|
||||
/// <param name="parameters">The parameters.</param>
|
||||
/// <returns>A Task representing the asynchronous operation.</returns>
|
||||
public override async Task SetParametersAsync(ParameterView parameters)
|
||||
{
|
||||
if (parameters.DidParameterChange(nameof(FilterValue), FilterValue))
|
||||
{
|
||||
var value = parameters.GetValueOrDefault<object>(nameof(FilterValue));
|
||||
|
||||
if (filterValue != value)
|
||||
{
|
||||
filterValue = value;
|
||||
|
||||
if (FilterTemplate != null)
|
||||
{
|
||||
if (FilterValueChange != null)
|
||||
{
|
||||
FilterValueChange(filterValue);
|
||||
}
|
||||
|
||||
await DataFilter.Filter();
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
await base.SetParametersAsync(parameters);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get property filter value.
|
||||
/// </summary>
|
||||
public object GetFilterValue()
|
||||
{
|
||||
return filterValue ?? FilterValue;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get property filter operator.
|
||||
/// </summary>
|
||||
public FilterOperator GetFilterOperator()
|
||||
{
|
||||
return filterOperator ?? FilterOperator;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Set property filter value.
|
||||
/// </summary>
|
||||
public void SetFilterValue(object value)
|
||||
{
|
||||
if ((FilterPropertyType == typeof(DateTimeOffset) || FilterPropertyType == typeof(DateTimeOffset?)) && value != null && value is DateTime?)
|
||||
{
|
||||
DateTimeOffset? offset = DateTime.SpecifyKind((DateTime)value, DateTimeKind.Utc);
|
||||
value = offset;
|
||||
}
|
||||
|
||||
filterValue = value;
|
||||
}
|
||||
|
||||
internal bool CanSetFilterValue()
|
||||
{
|
||||
return GetFilterOperator() == FilterOperator.IsNull
|
||||
|| GetFilterOperator() == FilterOperator.IsNotNull
|
||||
|| GetFilterOperator() == FilterOperator.IsEmpty
|
||||
|| GetFilterOperator() == FilterOperator.IsNotEmpty;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets to default property filter values and operators.
|
||||
/// </summary>
|
||||
public void ClearFilters()
|
||||
{
|
||||
SetFilterValue(null);
|
||||
SetFilterOperator(null);
|
||||
|
||||
FilterValue = null;
|
||||
var defaultOperator = typeof(System.Collections.IEnumerable).IsAssignableFrom(FilterPropertyType) ? FilterOperator.Contains : default(FilterOperator);
|
||||
FilterOperator = GetFilterOperators().Contains(defaultOperator) ? defaultOperator : GetFilterOperators().FirstOrDefault();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the filter operator.
|
||||
/// </summary>
|
||||
/// <value>The filter operator.</value>
|
||||
[Parameter]
|
||||
public FilterOperator FilterOperator { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Set property filter operator.
|
||||
/// </summary>
|
||||
public void SetFilterOperator(FilterOperator? value)
|
||||
{
|
||||
if (value == FilterOperator.IsEmpty || value == FilterOperator.IsNotEmpty || value == FilterOperator.IsNull || value == FilterOperator.IsNotNull)
|
||||
{
|
||||
filterValue = value == FilterOperator.IsEmpty || value == FilterOperator.IsNotEmpty ? string.Empty : null;
|
||||
}
|
||||
|
||||
filterOperator = value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get possible property filter operators.
|
||||
/// </summary>
|
||||
public virtual IEnumerable<FilterOperator> GetFilterOperators()
|
||||
{
|
||||
if (PropertyAccess.IsEnum(FilterPropertyType))
|
||||
return new FilterOperator[] { FilterOperator.Equals, FilterOperator.NotEquals };
|
||||
|
||||
if (PropertyAccess.IsNullableEnum(FilterPropertyType))
|
||||
return new FilterOperator[] { FilterOperator.Equals, FilterOperator.NotEquals, FilterOperator.IsNull, FilterOperator.IsNotNull };
|
||||
|
||||
if ((typeof(IEnumerable).IsAssignableFrom(FilterPropertyType) || typeof(IEnumerable<>).IsAssignableFrom(FilterPropertyType))
|
||||
&& FilterPropertyType != typeof(string))
|
||||
{
|
||||
return new FilterOperator[]
|
||||
{
|
||||
FilterOperator.Contains,
|
||||
FilterOperator.DoesNotContain,
|
||||
FilterOperator.Equals,
|
||||
FilterOperator.NotEquals,
|
||||
FilterOperator.IsNull,
|
||||
FilterOperator.IsNotNull,
|
||||
FilterOperator.IsEmpty,
|
||||
FilterOperator.IsNotEmpty
|
||||
};
|
||||
}
|
||||
|
||||
return Enum.GetValues(typeof(FilterOperator)).Cast<FilterOperator>().Where(o => o != FilterOperator.In && o != FilterOperator.NotIn).Where(o => {
|
||||
var isStringOperator = o == FilterOperator.Contains || o == FilterOperator.DoesNotContain
|
||||
|| o == FilterOperator.StartsWith || o == FilterOperator.EndsWith || o == FilterOperator.IsEmpty || o == FilterOperator.IsNotEmpty;
|
||||
return FilterPropertyType == typeof(string) ? isStringOperator
|
||||
|| o == FilterOperator.Equals || o == FilterOperator.NotEquals
|
||||
|| o == FilterOperator.IsNull || o == FilterOperator.IsNotNull
|
||||
: !isStringOperator;
|
||||
});
|
||||
}
|
||||
|
||||
internal string GetFilterOperatorText(FilterOperator filterOperator)
|
||||
{
|
||||
switch (filterOperator)
|
||||
{
|
||||
case FilterOperator.Contains:
|
||||
return DataFilter?.ContainsText;
|
||||
case FilterOperator.DoesNotContain:
|
||||
return DataFilter?.DoesNotContainText;
|
||||
case FilterOperator.EndsWith:
|
||||
return DataFilter?.EndsWithText;
|
||||
case FilterOperator.Equals:
|
||||
return DataFilter?.EqualsText;
|
||||
case FilterOperator.GreaterThan:
|
||||
return DataFilter?.GreaterThanText;
|
||||
case FilterOperator.GreaterThanOrEquals:
|
||||
return DataFilter?.GreaterThanOrEqualsText;
|
||||
case FilterOperator.LessThan:
|
||||
return DataFilter?.LessThanText;
|
||||
case FilterOperator.LessThanOrEquals:
|
||||
return DataFilter?.LessThanOrEqualsText;
|
||||
case FilterOperator.StartsWith:
|
||||
return DataFilter?.StartsWithText;
|
||||
case FilterOperator.NotEquals:
|
||||
return DataFilter?.NotEqualsText;
|
||||
case FilterOperator.IsNull:
|
||||
return DataFilter?.IsNullText;
|
||||
case FilterOperator.IsEmpty:
|
||||
return DataFilter?.IsEmptyText;
|
||||
case FilterOperator.IsNotNull:
|
||||
return DataFilter?.IsNotNullText;
|
||||
case FilterOperator.IsNotEmpty:
|
||||
return DataFilter?.IsNotEmptyText;
|
||||
default:
|
||||
return $"{filterOperator}";
|
||||
}
|
||||
}
|
||||
|
||||
internal string GetFilterOperatorSymbol(FilterOperator filterOperator)
|
||||
{
|
||||
var symbol = DataFilter.FilterCaseSensitivity == FilterCaseSensitivity.CaseInsensitive ? "a" : "A";
|
||||
switch (filterOperator)
|
||||
{
|
||||
case FilterOperator.Contains:
|
||||
return $"*{symbol}*";
|
||||
case FilterOperator.DoesNotContain:
|
||||
return $"*{symbol}*";
|
||||
case FilterOperator.StartsWith:
|
||||
return $"{symbol}**";
|
||||
case FilterOperator.EndsWith:
|
||||
return $"**{symbol}";
|
||||
case FilterOperator.Equals:
|
||||
return "=";
|
||||
case FilterOperator.GreaterThan:
|
||||
return ">";
|
||||
case FilterOperator.GreaterThanOrEquals:
|
||||
return "≥";
|
||||
case FilterOperator.LessThan:
|
||||
return "<";
|
||||
case FilterOperator.LessThanOrEquals:
|
||||
return "≤";
|
||||
case FilterOperator.NotEquals:
|
||||
return "≠";
|
||||
case FilterOperator.IsNull:
|
||||
return "∅";
|
||||
case FilterOperator.IsNotNull:
|
||||
return "!∅";
|
||||
case FilterOperator.IsEmpty:
|
||||
return "= ''";
|
||||
case FilterOperator.IsNotEmpty:
|
||||
return "≠ ''";
|
||||
default:
|
||||
return $"{filterOperator}";
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Disposes this instance.
|
||||
/// </summary>
|
||||
public void Dispose()
|
||||
{
|
||||
DataFilter?.RemoveProperty(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
@using System.Linq.Dynamic.Core
|
||||
@using System.Linq.Dynamic.Core
|
||||
@using Microsoft.JSInterop
|
||||
@using Microsoft.AspNetCore.Components.Forms
|
||||
@using Radzen
|
||||
@@ -17,23 +17,29 @@
|
||||
var visibleColumns = columns.Where(c => c.GetVisible()).ToList();
|
||||
|
||||
<div @ref=@Element style="@Style" @attributes="Attributes" class="rz-data-grid @GetCssClass()" id="@GetId()">
|
||||
@if(AllowGrouping || AllowColumnPicking)
|
||||
@if (AllowGrouping || AllowColumnPicking)
|
||||
{
|
||||
<div class="rz-group-header" @onmouseup=@(args => EndColumnDropToGroup())>
|
||||
@if(AllowGrouping)
|
||||
@if (@HeaderTemplate != null)
|
||||
{
|
||||
@if(Groups.Any())
|
||||
<div class="rz-custom-header">
|
||||
@HeaderTemplate
|
||||
</div>
|
||||
}
|
||||
@if (AllowGrouping)
|
||||
{
|
||||
@if (Groups.Any())
|
||||
{
|
||||
<div class="rz-group-header-items">
|
||||
@foreach(var gd in Groups)
|
||||
{
|
||||
<div class="rz-group-header-item">
|
||||
<span class="rz-group-header-item-title">@gd.GetTitle()</span>
|
||||
<a href="javascript:void(0)" @onclick=@(args => RemoveGroup(gd)) role="button" class="rz-dialog-titlebar-icon rz-dialog-titlebar-close">
|
||||
<span class="rzi rzi-times"></span>
|
||||
</a>
|
||||
</div>
|
||||
}
|
||||
@foreach (var gd in Groups)
|
||||
{
|
||||
<div class="rz-group-header-item">
|
||||
<span class="rz-group-header-item-title">@gd.GetTitle()</span>
|
||||
<a href="javascript:void(0)" @onclick=@(args => RemoveGroupAsync(gd)) role="button" class="rz-dialog-titlebar-icon rz-dialog-titlebar-close">
|
||||
<span class="rzi rzi-times"></span>
|
||||
</a>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
}
|
||||
else
|
||||
@@ -42,124 +48,145 @@
|
||||
}
|
||||
}
|
||||
|
||||
@if(AllowColumnPicking)
|
||||
@if (AllowColumnPicking)
|
||||
{
|
||||
<div class="rz-column-picker">
|
||||
<RadzenDropDown SelectAllText="@AllColumnsText"
|
||||
MaxSelectedLabels="2"
|
||||
SelectedItemsText="@ColumnsShowingText" Change=@ToggleColumns
|
||||
@bind-Value="@selectedColumns"
|
||||
Multiple="true"
|
||||
Placeholder="@ColumnsText"
|
||||
Data="allPickableColumns"
|
||||
TextProperty="Title" />
|
||||
<RadzenDropDown SelectAllText="@AllColumnsText" AllowSelectAll="@AllowPickAllColumns"
|
||||
MaxSelectedLabels="@ColumnsPickerMaxSelectedLabels"
|
||||
SelectedItemsText="@ColumnsShowingText" Change=@ToggleColumns
|
||||
@bind-Value="@selectedColumns" FilterCaseSensitivity=FilterCaseSensitivity.CaseInsensitive
|
||||
Multiple="true" AllowFiltering="@ColumnsPickerAllowFiltering"
|
||||
Placeholder="@ColumnsText"
|
||||
Data="allPickableColumns"
|
||||
TextProperty="ColumnPickerTitle" />
|
||||
</div>
|
||||
|
||||
}
|
||||
</div>
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
@if (@HeaderTemplate != null)
|
||||
{
|
||||
<div class="rz-group-header">
|
||||
<div class="rz-custom-header">
|
||||
@HeaderTemplate
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
}
|
||||
@if (AllowPaging && (PagerPosition == PagerPosition.Top || PagerPosition == PagerPosition.TopAndBottom))
|
||||
{
|
||||
<RadzenPager HorizontalAlign="@PagerHorizontalAlign" AlwaysVisible="@PagerAlwaysVisible" @ref="topPager" Count="@Count" PageSize="@PageSize" PageNumbersCount="@PageNumbersCount" PageChanged="@OnPageChanged" PageSizeChanged="@OnPageSizeChanged" PageSizeOptions="@PageSizeOptions" ShowPagingSummary="@ShowPagingSummary" PagingSummaryFormat="@PagingSummaryFormat" PageSizeText="@PageSizeText" />
|
||||
<RadzenPager HorizontalAlign="@PagerHorizontalAlign" AlwaysVisible="@PagerAlwaysVisible" @ref="topPager" Count="@Count" PageSize="@PageSize" PageNumbersCount="@PageNumbersCount" PageChanged="@ChangePage" PageSizeChanged="@OnPageSizeChanged" PageSizeOptions="@PageSizeOptions" ShowPagingSummary="@ShowPagingSummary" PagingSummaryFormat="@PagingSummaryFormat" PageSizeText="@PageSizeText" Density="@Density" FirstPageTitle="@FirstPageTitle" FirstPageAriaLabel="@FirstPageAriaLabel" PrevPageAriaLabel="@PrevPageAriaLabel" PrevPageTitle="@PrevPageTitle" NextPageAriaLabel="@NextPageAriaLabel" NextPageTitle="@NextPageTitle" LastPageAriaLabel="@LastPageAriaLabel" LastPageTitle="@LastPageTitle" PageAriaLabelFormat="@PageAriaLabelFormat" PageTitleFormat="@PageTitleFormat" />
|
||||
}
|
||||
|
||||
<div class="rz-data-grid-data">
|
||||
<table class="rz-grid-table rz-grid-table-fixed">
|
||||
<colgroup>
|
||||
@foreach(var g in Groups)
|
||||
{
|
||||
<col>
|
||||
}
|
||||
@if (Template != null && ShowExpandColumn)
|
||||
{
|
||||
<col>
|
||||
}
|
||||
@foreach (var column in visibleColumns)
|
||||
{
|
||||
<col id=@(getColumnResizerId(visibleColumns.IndexOf(column)) + "-col") style="@column.GetStyle()">
|
||||
}
|
||||
</colgroup>
|
||||
<thead>
|
||||
@for(var i = 0; i < deepestChildColumnLevel + 1; i++)
|
||||
{
|
||||
<tr>
|
||||
@foreach(var g in Groups)
|
||||
<div class="rz-data-grid-data">
|
||||
<table class="rz-grid-table rz-grid-table-fixed @(AllowAlternatingRows ? "rz-grid-table-striped" : "") @(allColumns.Any(c => c.Parent != null) ? "rz-grid-table-composite" : "") @(getGridLinesCSSClass())">
|
||||
<colgroup>
|
||||
@foreach (var g in Groups)
|
||||
{
|
||||
<th class="rz-col-icon rz-unselectable-text" scope="col" rowspan=@(deepestChildColumnLevel + 1)>
|
||||
<span class="rz-column-title"></span>
|
||||
</th>
|
||||
<col>
|
||||
}
|
||||
@if (Template != null && ShowExpandColumn)
|
||||
{
|
||||
<th class="rz-col-icon rz-unselectable-text" scope="col" rowspan=@(deepestChildColumnLevel + 1)>
|
||||
<span class="rz-column-title"></span>
|
||||
</th>
|
||||
<col>
|
||||
}
|
||||
@for (var j = 0; j < visibleColumns.Count; j++)
|
||||
@foreach (var column in visibleColumns)
|
||||
{
|
||||
var column = visibleColumns[j];
|
||||
|
||||
var cellAttr = HeaderCellAttributes(column);
|
||||
|
||||
object colspan;
|
||||
cellAttr.TryGetValue("colspan", out colspan);
|
||||
|
||||
if (colspan != null)
|
||||
{
|
||||
j = j + (int)Convert.ChangeType(colspan, TypeCode.Int32) - 1;
|
||||
}
|
||||
|
||||
var columnIndex = visibleColumns.IndexOf(column);
|
||||
var sortableClass = AllowSorting && column.Sortable ? "rz-sortable-column" : "";
|
||||
|
||||
<RadzenDataGridHeaderCell RowIndex="@i" Grid="@this" Column="@column" ColumnIndex="@columnIndex" CssClass="@($"rz-unselectable-text {sortableClass} {column.HeaderCssClass} {getFrozenColumnClass(column, visibleColumns)} {(column.Columns != null || column.Parent != null ? "rz-composite-cell" : "")}".Trim())" Attributes="@(cellAttr)" />
|
||||
<col id=@(getColumnUniqueId(visibleColumns.IndexOf(column)) + "-col") style="@column.GetStyle()">
|
||||
}
|
||||
</tr>
|
||||
}
|
||||
@if (AllowFiltering && (FilterMode == FilterMode.Simple || FilterMode == FilterMode.SimpleWithMenu) && columns.Where(column => column.Filterable && (!string.IsNullOrEmpty(column.GetFilterProperty()) || column.FilterTemplate != null)).Any())
|
||||
{
|
||||
<tr>
|
||||
@foreach(var g in Groups)
|
||||
{
|
||||
<th class="rz-col-icon rz-unselectable-text" scope="col" rowspan=@(deepestChildColumnLevel + 1)>
|
||||
<span class="rz-column-title"></span>
|
||||
</th>
|
||||
}
|
||||
@if (Template != null && ShowExpandColumn)
|
||||
{
|
||||
<th class="rz-col-icon rz-unselectable-text" scope="col" rowspan=@(deepestChildColumnLevel + 1)>
|
||||
<span class="rz-column-title"></span>
|
||||
</th>
|
||||
}
|
||||
@foreach (var column in visibleColumns)
|
||||
{
|
||||
<th colspan="@column.GetColSpan()" class="@($" rz-unselectable-text")" scope="col" style="@column.GetStyle(true, true)">
|
||||
@if (AllowFiltering && column.Filterable && column.Columns == null && (!string.IsNullOrEmpty(column.GetFilterProperty()) || column.FilterTemplate != null))
|
||||
</colgroup>
|
||||
<thead>
|
||||
@for (var i = 0; i < deepestChildColumnLevel + 1; i++)
|
||||
{
|
||||
<tr>
|
||||
@if (i == 0) // Only add the th elements for the first row
|
||||
{
|
||||
@foreach (var g in Groups)
|
||||
{
|
||||
<th class="rz-col-icon rz-unselectable-text" scope="col" rowspan=@(deepestChildColumnLevel + 1)>
|
||||
<span class="rz-column-title"></span>
|
||||
</th>
|
||||
}
|
||||
@if (Template != null && ShowExpandColumn && i == 0)
|
||||
{
|
||||
<th class="rz-col-icon rz-unselectable-text" scope="col" rowspan=@(deepestChildColumnLevel + 1)>
|
||||
<span class="rz-column-title"></span>
|
||||
</th>
|
||||
}
|
||||
}
|
||||
@for (var j = 0; j < visibleColumns.Count; j++)
|
||||
{
|
||||
var column = visibleColumns[j];
|
||||
|
||||
var cellAttr = HeaderCellAttributes(column);
|
||||
|
||||
object colspan;
|
||||
cellAttr.TryGetValue("colspan", out colspan);
|
||||
|
||||
if (colspan != null)
|
||||
{
|
||||
<div class="rz-cell-filter">
|
||||
<div class="rz-cell-filter-content">
|
||||
@if (column.FilterTemplate != null)
|
||||
{
|
||||
@column.FilterTemplate(column)
|
||||
}
|
||||
else
|
||||
{
|
||||
<label class="rz-cell-filter-label" style="height:35px" onclick="event.preventDefault()">
|
||||
@if (column.FilterPropertyType == typeof(DateTime) || column.FilterPropertyType == typeof(DateTime?) || column.FilterPropertyType == typeof(DateTimeOffset) || column.FilterPropertyType == typeof(DateTimeOffset?))
|
||||
{
|
||||
j = j + (int)Convert.ChangeType(colspan, TypeCode.Int32) - 1;
|
||||
}
|
||||
|
||||
var columnIndex = visibleColumns.IndexOf(column);
|
||||
var sortableClass = AllowSorting && column.Sortable ? "rz-sortable-column" : "";
|
||||
|
||||
<RadzenDataGridHeaderCell RowIndex="@i" Grid="@this" Column="@column" ColumnIndex="@columnIndex" CssClass="@($"rz-unselectable-text {sortableClass} {column.HeaderCssClass} {getFrozenColumnClass(column, visibleColumns)} {getCompositeCellCSSClass(column)} {getColumnAlignClass(column)}".Trim())" Attributes="@(cellAttr)" />
|
||||
}
|
||||
</tr>
|
||||
}
|
||||
@if (AllowFiltering && (FilterMode == FilterMode.Simple || FilterMode == FilterMode.SimpleWithMenu) && columns.Where(column => column.Filterable && (!string.IsNullOrEmpty(column.GetFilterProperty()) || column.FilterTemplate != null)).Any())
|
||||
{
|
||||
<tr>
|
||||
|
||||
@foreach (var g in Groups)
|
||||
{
|
||||
<th class="rz-col-icon rz-unselectable-text" scope="col" rowspan=@(deepestChildColumnLevel + 1)>
|
||||
<span class="rz-column-title"></span>
|
||||
</th>
|
||||
}
|
||||
@if (Template != null && ShowExpandColumn )
|
||||
{
|
||||
<th class="rz-col-icon rz-unselectable-text" scope="col" rowspan=@(deepestChildColumnLevel + 1)>
|
||||
<span class="rz-column-title"></span>
|
||||
</th>
|
||||
}
|
||||
@foreach (var column in visibleColumns)
|
||||
{
|
||||
<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))
|
||||
{
|
||||
<div class="rz-cell-filter">
|
||||
<div class="rz-cell-filter-content">
|
||||
@if (column.FilterTemplate != null)
|
||||
{
|
||||
@column.FilterTemplate(column)
|
||||
}
|
||||
else
|
||||
{
|
||||
<label class="rz-cell-filter-label" style="height:35px; width:100%;" onclick="event.preventDefault()">
|
||||
@if (PropertyAccess.IsDate(column.FilterPropertyType))
|
||||
{
|
||||
if (FilterMode == FilterMode.Simple)
|
||||
{
|
||||
<button class="rz-button rz-button-md rz-button-icon-only btn-light" onclick="@($"Radzen.togglePopup(this.parentNode, '{PopupID}{column.GetFilterProperty()}')")">
|
||||
<button class="rz-button rz-button-md rz-button-icon-only rz-variant-flat rz-light" onclick="@($"Radzen.togglePopup(this.parentNode, '{PopupID}{column.GetFilterProperty()}')")">
|
||||
<i class="rzi">date_range</i>
|
||||
</button>
|
||||
var filterValue = column.GetFilterValue();
|
||||
@if (filterValue != null)
|
||||
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"
|
||||
style="display:none;width:550px;" tabindex="0">
|
||||
style="display:none;width:550px;" tabindex="0">
|
||||
<div class="rz-overlaypanel-content">
|
||||
|
||||
<div class="rz-date-filter">
|
||||
@@ -167,37 +194,73 @@
|
||||
<div class="rz-listbox rz-inputtext ">
|
||||
<div class="rz-listbox-list-wrapper">
|
||||
<ul class="rz-listbox-list">
|
||||
<li class="@(DateFilterOperatorStyle(column, FilterOperator.Equals))" @onclick="@((args) => ApplyDateFilterByFilterOperator(column, FilterOperator.Equals))" style="display: block;">
|
||||
<span>@EqualsText</span>
|
||||
</li>
|
||||
<li class="@(DateFilterOperatorStyle(column, FilterOperator.NotEquals))" @onclick="@((args) => ApplyDateFilterByFilterOperator(column, FilterOperator.NotEquals))" style="display: block;">
|
||||
<span>@NotEqualsText</span>
|
||||
</li>
|
||||
<li class="@(DateFilterOperatorStyle(column, FilterOperator.LessThan))" @onclick="@((args) => ApplyDateFilterByFilterOperator(column, FilterOperator.LessThan))" style="display: block;">
|
||||
<span>@LessThanText</span>
|
||||
</li>
|
||||
<li class="@(DateFilterOperatorStyle(column, FilterOperator.LessThanOrEquals))" @onclick="@((args) => ApplyDateFilterByFilterOperator(column, FilterOperator.LessThanOrEquals))" style="display: block;">
|
||||
<span>@LessThanOrEqualsText</span>
|
||||
</li>
|
||||
<li class="@(DateFilterOperatorStyle(column, FilterOperator.GreaterThan))" @onclick="@((args) => ApplyDateFilterByFilterOperator(column, FilterOperator.GreaterThan))" style="display: block;">
|
||||
<span>@GreaterThanText</span>
|
||||
</li>
|
||||
<li class="@(DateFilterOperatorStyle(column, FilterOperator.GreaterThanOrEquals))" @onclick="@((args) => ApplyDateFilterByFilterOperator(column, FilterOperator.GreaterThanOrEquals))" style="display: block;">
|
||||
<span>@GreaterThanOrEqualsText</span>
|
||||
</li>
|
||||
<li class="@(DateFilterOperatorStyle(column, FilterOperator.IsNull))" @onclick="@((args) => ApplyDateFilterByFilterOperator(column, FilterOperator.IsNull))" style="display: block;">
|
||||
<span>@IsNullText</span>
|
||||
</li>
|
||||
<li class="@(DateFilterOperatorStyle(column, FilterOperator.IsNotNull))" @onclick="@((args) => ApplyDateFilterByFilterOperator(column, FilterOperator.IsNotNull))" style="display: block;">
|
||||
<span>@IsNotNullText</span>
|
||||
</li>
|
||||
@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"
|
||||
ShowTime="true" ShowTimeOkButton="false" Inline="true" DateFormat="@getFilterDateFormat(column)"
|
||||
Value="@column.GetFilterValue()" Change="@(args => column.SetFilterValue(args.Value))" />
|
||||
<RadzenDatePicker TValue="@object" AllowInput=@(AllowFilterDateInput)
|
||||
ShowTime="@column.ShowTimeForDateTimeFilter()" ShowTimeOkButton="false" Inline="true" DateFormat="@getFilterDateFormat(column)"
|
||||
Value="@column.GetFilterValue()" Change="@(args => { column.SetFilterValue(args.Value); SaveSettings(); })" />
|
||||
|
||||
</div>
|
||||
<div class="rz-date-filter-buttons">
|
||||
@@ -215,123 +278,516 @@
|
||||
else
|
||||
{
|
||||
<RadzenDataGridFilterMenu Grid="@this" Column="@column" />
|
||||
<RadzenDatePicker Disabled=@column.CanSetFilterValue() TValue="@object" Style="width:100%" AllowInput="false" AllowClear="true"
|
||||
ShowTime="false" ShowTimeOkButton="false" DateFormat="@getFilterDateFormat(column)"
|
||||
Value="@column.GetFilterValue()" Change="@(args => { if(!args.HasValue) { ClearFilter(column, true); } else {column.SetFilterValue(args.Value); ApplyFilter(column, true);} })" />
|
||||
<RadzenDatePicker Disabled=@column.CanSetFilterValue() TValue="@object" Style="width:100%" AllowInput=@(AllowFilterDateInput) AllowClear="true"
|
||||
ShowTime="false" ShowTimeOkButton="false" DateFormat="@getFilterDateFormat(column)"
|
||||
Value="@column.GetFilterValue()" Change="@(args => { if(!args.HasValue) { InvokeAsync(() => ClearFilter(column, true)); } else {column.SetFilterValue(args.Value); InvokeAsync(() => ApplyFilter(column, true));} })" />
|
||||
}
|
||||
}
|
||||
else if (PropertyAccess.IsNumeric(column.FilterPropertyType))
|
||||
{
|
||||
if(FilterMode == FilterMode.SimpleWithMenu)
|
||||
else if (PropertyAccess.IsNullableEnum(column.FilterPropertyType) || PropertyAccess.IsEnum(column.FilterPropertyType))
|
||||
{
|
||||
<RadzenDataGridFilterMenu Grid="@this" Column="@column" />
|
||||
<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));})" />
|
||||
}
|
||||
@(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)
|
||||
else if (PropertyAccess.IsNumeric(column.FilterPropertyType))
|
||||
{
|
||||
<RadzenDataGridFilterMenu Grid="@this" Column="@column" />
|
||||
if (FilterMode == FilterMode.SimpleWithMenu)
|
||||
{
|
||||
<RadzenDataGridFilterMenu Grid="@this" Column="@column" />
|
||||
}
|
||||
@(DrawNumericFilter(column))
|
||||
}
|
||||
<input disabled=@column.CanSetFilterValue() id="@(getFilterInputId(column))" @onchange="@((args) => OnFilter(args, column))" @onkeydown="@((args) => OnFilterKeyPress(args, column))" value="@column.GetFilterValue()" type="text" class="rz-textbox" style="width: 100%;" />
|
||||
}
|
||||
</label>
|
||||
}
|
||||
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 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;right:10px;">close</i>
|
||||
}
|
||||
}
|
||||
</label>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
</th>
|
||||
}
|
||||
</tr>
|
||||
}
|
||||
</thead>
|
||||
<tbody>
|
||||
@if (Data != null)
|
||||
{
|
||||
@if (Count > 0 || !AllowPaging && LoadData.HasDelegate && Count == 0)
|
||||
}
|
||||
</th>
|
||||
}
|
||||
</tr>
|
||||
}
|
||||
</thead>
|
||||
<tbody>
|
||||
@if (Data != null)
|
||||
{
|
||||
if (columns.Count > 0)
|
||||
@if (!ShowEmptyMessage || Count > 0 && (IsVirtualizationAllowed() ? Data.Any() : true) || LoadData.HasDelegate && Data != null && Data.Any())
|
||||
{
|
||||
@DrawRows(visibleColumns)
|
||||
if (columns.Count > 0)
|
||||
{
|
||||
@DrawRows(visibleColumns)
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
<tr class=" rz-datatable-emptymessage-row">
|
||||
<td class="rz-datatable-emptymessage" colspan="@(visibleColumns.Sum(c => c.GetColSpan()) + (Template != null && ShowExpandColumn ? 1 : 0))">
|
||||
@if (EmptyTemplate != null)
|
||||
{
|
||||
@EmptyTemplate
|
||||
}
|
||||
else
|
||||
{
|
||||
<span style="white-space: normal">@EmptyText</span>
|
||||
}
|
||||
</td>
|
||||
</tr>
|
||||
}
|
||||
}
|
||||
</tbody>
|
||||
@if (visibleColumns.Where(c => c.FooterTemplate != null).Any())
|
||||
{
|
||||
<tfoot class="rz-datatable-tfoot">
|
||||
@for (var i = 0; i < deepestChildColumnLevel + 1; i++)
|
||||
{
|
||||
<tr class="">
|
||||
@if (i == 0) // Only add the th elements for the first row
|
||||
{
|
||||
@foreach (var g in Groups)
|
||||
{
|
||||
<td class="rz-col-icon rz-unselectable-text" scope="col" rowspan=@(deepestChildColumnLevel + 1)>
|
||||
<span class="rz-column-title"></span>
|
||||
</td>
|
||||
}
|
||||
@if (Template != null && ShowExpandColumn && i == 0)
|
||||
{
|
||||
<td class="rz-col-icon rz-unselectable-text" scope="col" rowspan=@(deepestChildColumnLevel + 1)>
|
||||
<span class="rz-column-title"></span>
|
||||
</td>
|
||||
}
|
||||
}
|
||||
@for (var j = 0; j < visibleColumns.Count; j++)
|
||||
{
|
||||
var column = visibleColumns[j];
|
||||
var cellAttr = FooterCellAttributes(column);
|
||||
|
||||
object colspan;
|
||||
cellAttr.TryGetValue("colspan", out colspan);
|
||||
|
||||
if (colspan != null)
|
||||
{
|
||||
j = j + (int)Convert.ChangeType(colspan, TypeCode.Int32) - 1;
|
||||
}
|
||||
|
||||
<RadzenDataGridFooterCell RowIndex="@i" Grid="@this" Column="@column"
|
||||
CssClass="@($"{column.FooterCssClass} {getFrozenColumnClass(column, visibleColumns)} {getCompositeCellCSSClass(column)}".Trim())"
|
||||
Attributes="@(cellAttr)" />
|
||||
}
|
||||
</tr>
|
||||
}
|
||||
</tfoot>
|
||||
}
|
||||
</table>
|
||||
|
||||
@if (IsLoading)
|
||||
{
|
||||
<div class="rz-datatable-loading"></div>
|
||||
<div class="rz-datatable-loading-content">
|
||||
@if(LoadingTemplate != null)
|
||||
{
|
||||
@LoadingTemplate
|
||||
}
|
||||
else
|
||||
{
|
||||
<tr class=" rz-datatable-emptymessage-row">
|
||||
<td class="rz-datatable-emptymessage" colspan="@(visibleColumns.Count + (Template != null && ShowExpandColumn ? 1 : 0))">
|
||||
@if (EmptyTemplate != null)
|
||||
{
|
||||
@EmptyTemplate
|
||||
}
|
||||
else
|
||||
{
|
||||
<span style="white-space: normal">@EmptyText</span>
|
||||
}
|
||||
</td>
|
||||
</tr>
|
||||
<i class="rzi-circle-o-notch"></i>
|
||||
}
|
||||
}
|
||||
</tbody>
|
||||
@if (visibleColumns.Where(c => c.FooterTemplate != null).Any())
|
||||
{
|
||||
<tfoot class="rz-datatable-tfoot">
|
||||
@for(var i = 0; i < deepestChildColumnLevel + 1; i++)
|
||||
{
|
||||
<tr class="">
|
||||
@foreach(var g in Groups)
|
||||
{
|
||||
<td class="rz-col-icon rz-unselectable-text" scope="col" rowspan=@(deepestChildColumnLevel + 1)>
|
||||
<span class="rz-column-title"></span>
|
||||
</td>
|
||||
}
|
||||
@if (Template != null && ShowExpandColumn)
|
||||
{
|
||||
<td class="rz-col-icon rz-unselectable-text" scope="col" rowspan=@(deepestChildColumnLevel + 1)>
|
||||
<span class="rz-column-title"></span>
|
||||
</td>
|
||||
}
|
||||
@for (var j = 0; j < visibleColumns.Count; j++)
|
||||
{
|
||||
var column = visibleColumns[j];
|
||||
var cellAttr = FooterCellAttributes(column);
|
||||
|
||||
object colspan;
|
||||
cellAttr.TryGetValue("colspan", out colspan);
|
||||
|
||||
if (colspan != null)
|
||||
{
|
||||
j = j + (int)Convert.ChangeType(colspan, TypeCode.Int32) - 1;
|
||||
}
|
||||
|
||||
<RadzenDataGridFooterCell RowIndex="@i" Grid="@this" Column="@column"
|
||||
CssClass="@($"{column.FooterCssClass} {getFrozenColumnClass(column, visibleColumns)} {(column.Columns != null || column.Parent != null ? "rz-composite-cell" : "")}".Trim())"
|
||||
Attributes="@(cellAttr)" />
|
||||
}
|
||||
</tr>
|
||||
}
|
||||
</tfoot>
|
||||
</div>
|
||||
}
|
||||
</table>
|
||||
|
||||
@if (IsLoading)
|
||||
{
|
||||
<div class="rz-datatable-loading"></div>
|
||||
<div class="rz-datatable-loading-content">
|
||||
<i class="rzi-circle-o-notch"></i>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@if (AllowPaging && (PagerPosition == PagerPosition.Bottom || PagerPosition == PagerPosition.TopAndBottom))
|
||||
{
|
||||
<RadzenPager HorizontalAlign="@PagerHorizontalAlign" AlwaysVisible="@PagerAlwaysVisible" @ref="bottomPager" Count="@Count" PageSize="@PageSize" PageNumbersCount="@PageNumbersCount" PageChanged="@OnPageChanged" PageSizeChanged="@OnPageSizeChanged" PageSizeOptions="@PageSizeOptions" ShowPagingSummary="@ShowPagingSummary" PagingSummaryFormat="@PagingSummaryFormat" PageSizeText="@PageSizeText" />
|
||||
<RadzenPager HorizontalAlign="@PagerHorizontalAlign" AlwaysVisible="@PagerAlwaysVisible" @ref="bottomPager" Count="@Count" PageSize="@PageSize" PageNumbersCount="@PageNumbersCount" PageChanged="@ChangePage" PageSizeChanged="@OnPageSizeChanged" PageSizeOptions="@PageSizeOptions" ShowPagingSummary="@ShowPagingSummary" PagingSummaryFormat="@PagingSummaryFormat" PageSizeText="@PageSizeText" Density="@Density" FirstPageTitle="@FirstPageTitle" FirstPageAriaLabel="@FirstPageAriaLabel" PrevPageAriaLabel="@PrevPageAriaLabel" PrevPageTitle="@PrevPageTitle" NextPageAriaLabel="@NextPageAriaLabel" NextPageTitle="@NextPageTitle" LastPageAriaLabel="@LastPageAriaLabel" LastPageTitle="@LastPageTitle" PageAriaLabelFormat="@PageAriaLabelFormat" PageTitleFormat="@PageTitleFormat" />
|
||||
}
|
||||
</div>
|
||||
}
|
||||
@code {
|
||||
internal RenderFragment RenderCell(RadzenDataGridColumn<TItem> column, TItem Item, IReadOnlyDictionary<string, object> Attributes, Tuple<Radzen.RowRenderEventArgs<TItem>, IReadOnlyDictionary<string, object>> rowArgs, int RowIndex)
|
||||
{
|
||||
var cellAttributes = new Dictionary<string, object>(Attributes);
|
||||
|
||||
if (CellClick.HasDelegate)
|
||||
{
|
||||
cellAttributes.Add("onclick", EventCallback.Factory.Create<MouseEventArgs>(receiver: this, callback: (eventArgs) => OnClick(column, Item, eventArgs)));
|
||||
}
|
||||
|
||||
if (CellDoubleClick.HasDelegate)
|
||||
{
|
||||
cellAttributes.Add("ondblclick", EventCallback.Factory.Create<MouseEventArgs>(receiver: this, callback: (eventArgs) => OnDblClick(column, Item, eventArgs)));
|
||||
}
|
||||
|
||||
if (CellContextMenu.HasDelegate)
|
||||
{
|
||||
cellAttributes.Add("oncontextmenu", EventCallback.Factory.Create<MouseEventArgs>(receiver: this, callback: (eventArgs) => OnContextMenu(column, Item, eventArgs)));
|
||||
}
|
||||
|
||||
IReadOnlyDictionary<string, object> CellAttributes = new System.Collections.ObjectModel.ReadOnlyDictionary<string, object>(cellAttributes);
|
||||
|
||||
return __builder => {
|
||||
<text>
|
||||
@if (this.AllowCompositeDataCells ? RowIndex == column.GetLevel() : (column.Parent != null && RowIndex == column.GetLevel() || column.Columns == null))
|
||||
{
|
||||
<td rowspan="@(column.GetRowSpan(true))" colspan="@(column.GetColSpan(true))" @attributes="@CellAttributes" style="@GetCellStyle(column, Attributes)" class="@GetCellCssClass(column, Attributes)" @oncontextmenu:preventDefault="@this.CellContextMenu.HasDelegate">
|
||||
@if (this.Responsive)
|
||||
{
|
||||
<span class="rz-column-title">
|
||||
@if (column.HeaderTemplate != null)
|
||||
{
|
||||
@column.HeaderTemplate
|
||||
}
|
||||
else
|
||||
{
|
||||
@column.GetTitle()
|
||||
}
|
||||
</span>
|
||||
}
|
||||
@if (this.LoadChildData.HasDelegate && this.ShowExpandColumn && this.allColumns.IndexOf(column) == 0)
|
||||
{
|
||||
<span class="rz-cell-toggle">
|
||||
<a class="@(getExpandIconCssClass(this, Item))" style="@(getExpandIconStyle(this, Item, rowArgs.Item1.Expandable))" href="javascript:void(0)" @onclick="_ => this.ExpandItem(Item)" @onclick:stopPropagation>
|
||||
<span class="@(this.ExpandedItemStyle(Item))"></span>
|
||||
</a>
|
||||
<span class="rz-cell-data" title="@(column.Template == null ? column.GetValue(Item) : "")">
|
||||
@if (Item != null)
|
||||
{
|
||||
@if (this.IsRowInEditMode(Item) && column.EditTemplate != null)
|
||||
{
|
||||
@column.EditTemplate(Item)
|
||||
}
|
||||
else if (column.Template != null)
|
||||
{
|
||||
@column.Template(Item)
|
||||
}
|
||||
else
|
||||
{
|
||||
@column.GetValue(Item)
|
||||
}
|
||||
}
|
||||
</span>
|
||||
</span>
|
||||
}
|
||||
else
|
||||
{
|
||||
<span class="rz-cell-data" title="@(column.Template == null && this.ShowCellDataAsTooltip ? column.GetValue(Item) : "")">
|
||||
@if (Item != null)
|
||||
{
|
||||
@if (this.IsRowInEditMode(Item) && column.EditTemplate != null)
|
||||
{
|
||||
@column.EditTemplate(Item)
|
||||
}
|
||||
else if (column.Template != null)
|
||||
{
|
||||
@column.Template(Item)
|
||||
}
|
||||
else
|
||||
{
|
||||
@column.GetValue(Item)
|
||||
}
|
||||
}
|
||||
</span>
|
||||
}
|
||||
</td>
|
||||
}
|
||||
else
|
||||
{
|
||||
@foreach (var c in this.childColumns.Where(c => c.GetVisible() && c.Parent == column))
|
||||
{
|
||||
|
||||
@RenderCell(c, Item, Attributes, rowArgs, RowIndex)
|
||||
|
||||
}
|
||||
}
|
||||
</text>
|
||||
};
|
||||
}
|
||||
|
||||
string GetCellStyle(RadzenDataGridColumn<TItem> column, IReadOnlyDictionary<string, object> Attributes)
|
||||
{
|
||||
var columnStyle = column.GetStyle(true);
|
||||
|
||||
if (Attributes != null && Attributes.TryGetValue("style", out var style) == true && !string.IsNullOrEmpty(Convert.ToString(style)))
|
||||
{
|
||||
return String.IsNullOrEmpty(columnStyle) ? $"{style}" : $"{columnStyle.TrimEnd(';')};{style}";
|
||||
}
|
||||
|
||||
return columnStyle;
|
||||
}
|
||||
|
||||
string GetCellCssClass(RadzenDataGridColumn<TItem> column, IReadOnlyDictionary<string, object> Attributes)
|
||||
{
|
||||
var CssClass = column.CssClass + " " + getFrozenColumnClass(column, columns.Where(c => c.GetVisible()).ToList()) + " " + getCompositeCellCSSClass(column);
|
||||
|
||||
if (Attributes != null && Attributes.TryGetValue("class", out var @class) && !string.IsNullOrEmpty(Convert.ToString(@class)))
|
||||
{
|
||||
return $"{CssClass} {@class}".Trim();
|
||||
}
|
||||
|
||||
return String.IsNullOrWhiteSpace(CssClass) ? null : CssClass;
|
||||
}
|
||||
|
||||
|
||||
async Task OnContextMenu(RadzenDataGridColumn<TItem> Column, TItem Item, MouseEventArgs args)
|
||||
{
|
||||
#if NET5_0_OR_GREATER
|
||||
await OnCellContextMenu(new DataGridCellMouseEventArgs<TItem>
|
||||
{
|
||||
Data = Item,
|
||||
AltKey = args.AltKey,
|
||||
Button = args.Button,
|
||||
Buttons = args.Buttons,
|
||||
ClientX = args.ClientX,
|
||||
ClientY = args.ClientY,
|
||||
CtrlKey = args.CtrlKey,
|
||||
Detail = args.Detail,
|
||||
MetaKey = args.MetaKey,
|
||||
OffsetX = args.OffsetX,
|
||||
OffsetY = args.OffsetY,
|
||||
ScreenX = args.ScreenX,
|
||||
ScreenY = args.ScreenY,
|
||||
ShiftKey = args.ShiftKey,
|
||||
Type = args.Type,
|
||||
Column = Column
|
||||
});
|
||||
#else
|
||||
await OnCellContextMenu(new DataGridCellMouseEventArgs<TItem>
|
||||
{
|
||||
Data = Item,
|
||||
AltKey = args.AltKey,
|
||||
Button = args.Button,
|
||||
Buttons = args.Buttons,
|
||||
ClientX = args.ClientX,
|
||||
ClientY = args.ClientY,
|
||||
CtrlKey = args.CtrlKey,
|
||||
Detail = args.Detail,
|
||||
MetaKey = args.MetaKey,
|
||||
ScreenX = args.ScreenX,
|
||||
ScreenY = args.ScreenY,
|
||||
ShiftKey = args.ShiftKey,
|
||||
Type = args.Type,
|
||||
Column = Column
|
||||
});
|
||||
#endif
|
||||
}
|
||||
|
||||
bool clicking;
|
||||
async Task OnClick(RadzenDataGridColumn<TItem> Column, TItem Item, MouseEventArgs args)
|
||||
{
|
||||
if (clicking)
|
||||
{
|
||||
return;
|
||||
}
|
||||
try
|
||||
{
|
||||
clicking = true;
|
||||
#if NET5_0_OR_GREATER
|
||||
await OnCellClick(new DataGridCellMouseEventArgs<TItem>
|
||||
{
|
||||
Data = Item,
|
||||
AltKey = args.AltKey,
|
||||
Button = args.Button,
|
||||
Buttons = args.Buttons,
|
||||
ClientX = args.ClientX,
|
||||
ClientY = args.ClientY,
|
||||
CtrlKey = args.CtrlKey,
|
||||
Detail = args.Detail,
|
||||
MetaKey = args.MetaKey,
|
||||
OffsetX = args.OffsetX,
|
||||
OffsetY = args.OffsetY,
|
||||
ScreenX = args.ScreenX,
|
||||
ScreenY = args.ScreenY,
|
||||
ShiftKey = args.ShiftKey,
|
||||
Type = args.Type,
|
||||
Column = Column
|
||||
});
|
||||
#else
|
||||
await OnCellClick(new DataGridCellMouseEventArgs<TItem>
|
||||
{
|
||||
Data = Item,
|
||||
AltKey = args.AltKey,
|
||||
Button = args.Button,
|
||||
Buttons = args.Buttons,
|
||||
ClientX = args.ClientX,
|
||||
ClientY = args.ClientY,
|
||||
CtrlKey = args.CtrlKey,
|
||||
Detail = args.Detail,
|
||||
MetaKey = args.MetaKey,
|
||||
ScreenX = args.ScreenX,
|
||||
ScreenY = args.ScreenY,
|
||||
ShiftKey = args.ShiftKey,
|
||||
Type = args.Type,
|
||||
Column = Column
|
||||
});
|
||||
#endif
|
||||
#if NET5_0_OR_GREATER
|
||||
await OnRowClick(new DataGridRowMouseEventArgs<TItem>
|
||||
{
|
||||
Data = Item,
|
||||
AltKey = args.AltKey,
|
||||
Button = args.Button,
|
||||
Buttons = args.Buttons,
|
||||
ClientX = args.ClientX,
|
||||
ClientY = args.ClientY,
|
||||
CtrlKey = args.CtrlKey,
|
||||
Detail = args.Detail,
|
||||
MetaKey = args.MetaKey,
|
||||
OffsetX = args.OffsetX,
|
||||
OffsetY = args.OffsetY,
|
||||
ScreenX = args.ScreenX,
|
||||
ScreenY = args.ScreenY,
|
||||
ShiftKey = args.ShiftKey,
|
||||
Type = args.Type
|
||||
});
|
||||
#else
|
||||
await OnRowClick(new DataGridRowMouseEventArgs<TItem>
|
||||
{
|
||||
Data = Item,
|
||||
AltKey = args.AltKey,
|
||||
Button = args.Button,
|
||||
Buttons = args.Buttons,
|
||||
ClientX = args.ClientX,
|
||||
ClientY = args.ClientY,
|
||||
CtrlKey = args.CtrlKey,
|
||||
Detail = args.Detail,
|
||||
MetaKey = args.MetaKey,
|
||||
ScreenX = args.ScreenX,
|
||||
ScreenY = args.ScreenY,
|
||||
ShiftKey = args.ShiftKey,
|
||||
Type = args.Type
|
||||
});
|
||||
#endif
|
||||
}
|
||||
finally
|
||||
{
|
||||
clicking = false;
|
||||
}
|
||||
}
|
||||
|
||||
async Task OnDblClick(RadzenDataGridColumn<TItem> Column, TItem Item, MouseEventArgs args)
|
||||
{
|
||||
#if NET5_0_OR_GREATER
|
||||
await OnCellDblClick(new DataGridCellMouseEventArgs<TItem>
|
||||
{
|
||||
Data = Item,
|
||||
AltKey = args.AltKey,
|
||||
Button = args.Button,
|
||||
Buttons = args.Buttons,
|
||||
ClientX = args.ClientX,
|
||||
ClientY = args.ClientY,
|
||||
CtrlKey = args.CtrlKey,
|
||||
Detail = args.Detail,
|
||||
MetaKey = args.MetaKey,
|
||||
OffsetX = args.OffsetX,
|
||||
OffsetY = args.OffsetY,
|
||||
ScreenX = args.ScreenX,
|
||||
ScreenY = args.ScreenY,
|
||||
ShiftKey = args.ShiftKey,
|
||||
Type = args.Type,
|
||||
Column = Column
|
||||
});
|
||||
#else
|
||||
await OnCellDblClick(new DataGridCellMouseEventArgs<TItem>
|
||||
{
|
||||
Data = Item,
|
||||
AltKey = args.AltKey,
|
||||
Button = args.Button,
|
||||
Buttons = args.Buttons,
|
||||
ClientX = args.ClientX,
|
||||
ClientY = args.ClientY,
|
||||
CtrlKey = args.CtrlKey,
|
||||
Detail = args.Detail,
|
||||
MetaKey = args.MetaKey,
|
||||
ScreenX = args.ScreenX,
|
||||
ScreenY = args.ScreenY,
|
||||
ShiftKey = args.ShiftKey,
|
||||
Type = args.Type,
|
||||
Column = Column
|
||||
});
|
||||
#endif
|
||||
#if NET5_0_OR_GREATER
|
||||
await OnRowDblClick(new DataGridRowMouseEventArgs<TItem>
|
||||
{
|
||||
Data = Item,
|
||||
AltKey = args.AltKey,
|
||||
Button = args.Button,
|
||||
Buttons = args.Buttons,
|
||||
ClientX = args.ClientX,
|
||||
ClientY = args.ClientY,
|
||||
CtrlKey = args.CtrlKey,
|
||||
Detail = args.Detail,
|
||||
MetaKey = args.MetaKey,
|
||||
OffsetX = args.OffsetX,
|
||||
OffsetY = args.OffsetY,
|
||||
ScreenX = args.ScreenX,
|
||||
ScreenY = args.ScreenY,
|
||||
ShiftKey = args.ShiftKey,
|
||||
Type = args.Type
|
||||
});
|
||||
#else
|
||||
await OnRowDblClick(new DataGridRowMouseEventArgs<TItem>
|
||||
{
|
||||
Data = Item,
|
||||
AltKey = args.AltKey,
|
||||
Button = args.Button,
|
||||
Buttons = args.Buttons,
|
||||
ClientX = args.ClientX,
|
||||
ClientY = args.ClientY,
|
||||
CtrlKey = args.CtrlKey,
|
||||
Detail = args.Detail,
|
||||
MetaKey = args.MetaKey,
|
||||
ScreenX = args.ScreenX,
|
||||
ScreenY = args.ScreenY,
|
||||
ShiftKey = args.ShiftKey,
|
||||
Type = args.Type
|
||||
});
|
||||
#endif
|
||||
}
|
||||
|
||||
static string getExpandIconStyle(RadzenDataGrid<TItem> Grid, TItem Item, bool expandable)
|
||||
{
|
||||
var rules = new List<string>();
|
||||
|
||||
if (!expandable)
|
||||
{
|
||||
rules.Add("visibility:hidden");
|
||||
}
|
||||
|
||||
var child = Grid.childData.Any() ? Grid.childData.Where(c => c.Value?.Data?.Contains(Item) == true).FirstOrDefault() :
|
||||
default(KeyValuePair<TItem, DataGridChildData<TItem>>);
|
||||
|
||||
var level = !object.Equals(child, default(KeyValuePair<TItem, DataGridChildData<TItem>>)) ? child.Value.Level : 0;
|
||||
if (level > 0)
|
||||
{
|
||||
rules.Add($"margin-left: {level}rem");
|
||||
}
|
||||
|
||||
return string.Join(';', rules);
|
||||
}
|
||||
|
||||
static string getExpandIconCssClass(RadzenDataGrid<TItem> Grid, TItem Item)
|
||||
{
|
||||
var child = Grid.childData.Any() ? Grid.childData.Where(c => c.Value?.Data?.Contains(Item) == true).FirstOrDefault() :
|
||||
default(KeyValuePair<TItem, DataGridChildData<TItem>>);
|
||||
|
||||
var level = !object.Equals(child, default(KeyValuePair<TItem, DataGridChildData<TItem>>)) ? child.Value.Level : 0;
|
||||
|
||||
return $"rz-cell-toggle-level{level}";
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,239 +0,0 @@
|
||||
@typeparam TItem
|
||||
@using Microsoft.AspNetCore.Components.Forms
|
||||
<CascadingValue Value=@EditContext>
|
||||
<CascadingValue Value=Row>
|
||||
@if (Grid.AllowCompositeDataCells ? RowIndex == Column.GetLevel() : (Column.Parent != null && RowIndex == Column.GetLevel() || Column.Columns == null))
|
||||
{
|
||||
<td rowspan="@(Column.GetRowSpan(true))" colspan="@(Column.GetColSpan(true))" @attributes="@Attributes" style="@GetStyle()" class="@GetCssClass()" @onclick="@OnClick" @ondblclick="@OnDblClick" @oncontextmenu="@OnContextMenu" @oncontextmenu:preventDefault="@Grid.CellContextMenu.HasDelegate">
|
||||
<CascadingValue Value=this>
|
||||
@ChildContent
|
||||
</CascadingValue>
|
||||
</td>
|
||||
}
|
||||
else
|
||||
{
|
||||
@foreach(var column in Grid.childColumns.Where(c => c.GetVisible() && c.Parent == Column))
|
||||
{
|
||||
<RadzenDataGridCell Row=@Row EditContext=EditContext RowIndex="@RowIndex" Grid="@Grid" Column="@column" Item="@Item"
|
||||
Style="@column.GetStyle(true)" CssClass="@(column.CssClass + " " + Grid.getFrozenColumnClass(column, Grid.ColumnsCollection) + " " + (column.Columns != null || column.Parent != null ? "rz-composite-cell" : ""))" Attributes="@(Grid.CellAttributes(Item, column))">
|
||||
@if (Grid.Responsive)
|
||||
{
|
||||
<span class="rz-column-title">
|
||||
@if (column.HeaderTemplate != null)
|
||||
{
|
||||
@column.HeaderTemplate
|
||||
}
|
||||
else
|
||||
{
|
||||
@column.Title
|
||||
}
|
||||
</span>
|
||||
}
|
||||
<span class="rz-cell-data" title="@(column.Template == null ? column.GetValue(Item) : "")">
|
||||
@if (Item != null)
|
||||
{
|
||||
@if (Grid.IsRowInEditMode(Item) && column.EditTemplate != null)
|
||||
{
|
||||
@column.EditTemplate(Item)
|
||||
}
|
||||
else if (column.Template != null)
|
||||
{
|
||||
@column.Template(Item)
|
||||
}
|
||||
else
|
||||
{
|
||||
@column.GetValue(Item)
|
||||
}
|
||||
}
|
||||
</span>
|
||||
</RadzenDataGridCell>
|
||||
}
|
||||
}
|
||||
</CascadingValue>
|
||||
</CascadingValue>
|
||||
@code {
|
||||
[Parameter(CaptureUnmatchedValues = true)]
|
||||
public IReadOnlyDictionary<string, object> Attributes { get; set; }
|
||||
|
||||
[Parameter]
|
||||
public int RowIndex { get; set; }
|
||||
|
||||
[Parameter]
|
||||
public RadzenDataGridRow<TItem> Row { get; set; }
|
||||
|
||||
[Parameter]
|
||||
public EditContext EditContext { get; set; }
|
||||
|
||||
[Parameter]
|
||||
public RenderFragment ChildContent { get; set; }
|
||||
|
||||
[Parameter]
|
||||
public string CssClass { get; set; }
|
||||
|
||||
[Parameter]
|
||||
public string Style { get; set; }
|
||||
|
||||
[Parameter]
|
||||
public TItem Item { get; set; }
|
||||
|
||||
[Parameter]
|
||||
public RadzenDataGridColumn<TItem> Column { get; set; }
|
||||
|
||||
[Parameter]
|
||||
public RadzenDataGrid<TItem> Grid { get; set; }
|
||||
|
||||
async Task OnContextMenu(MouseEventArgs args)
|
||||
{
|
||||
if (Grid != null)
|
||||
{
|
||||
#if NET5
|
||||
await Grid.OnCellContextMenu(new DataGridCellMouseEventArgs<TItem>
|
||||
{
|
||||
Data = Item,
|
||||
AltKey = args.AltKey,
|
||||
Button = args.Button,
|
||||
Buttons = args.Buttons,
|
||||
ClientX = args.ClientX,
|
||||
ClientY = args.ClientY,
|
||||
CtrlKey = args.CtrlKey,
|
||||
Detail = args.Detail,
|
||||
MetaKey = args.MetaKey,
|
||||
OffsetX = args.OffsetX,
|
||||
OffsetY = args.OffsetY,
|
||||
ScreenX = args.ScreenX,
|
||||
ScreenY = args.ScreenY,
|
||||
ShiftKey = args.ShiftKey,
|
||||
Type = args.Type,
|
||||
Column = Column
|
||||
});
|
||||
#else
|
||||
await Grid.OnCellContextMenu(new DataGridCellMouseEventArgs<TItem>
|
||||
{
|
||||
Data = Item,
|
||||
AltKey = args.AltKey,
|
||||
Button = args.Button,
|
||||
Buttons = args.Buttons,
|
||||
ClientX = args.ClientX,
|
||||
ClientY = args.ClientY,
|
||||
CtrlKey = args.CtrlKey,
|
||||
Detail = args.Detail,
|
||||
MetaKey = args.MetaKey,
|
||||
ScreenX = args.ScreenX,
|
||||
ScreenY = args.ScreenY,
|
||||
ShiftKey = args.ShiftKey,
|
||||
Type = args.Type,
|
||||
Column = Column
|
||||
});
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
async Task OnClick(MouseEventArgs args)
|
||||
{
|
||||
if (Grid != null)
|
||||
{
|
||||
#if NET5
|
||||
await Grid.OnRowClick(new DataGridRowMouseEventArgs<TItem>
|
||||
{
|
||||
Data = Item,
|
||||
AltKey = args.AltKey,
|
||||
Button = args.Button,
|
||||
Buttons = args.Buttons,
|
||||
ClientX = args.ClientX,
|
||||
ClientY = args.ClientY,
|
||||
CtrlKey = args.CtrlKey,
|
||||
Detail = args.Detail,
|
||||
MetaKey = args.MetaKey,
|
||||
OffsetX = args.OffsetX,
|
||||
OffsetY = args.OffsetY,
|
||||
ScreenX = args.ScreenX,
|
||||
ScreenY = args.ScreenY,
|
||||
ShiftKey = args.ShiftKey,
|
||||
Type = args.Type
|
||||
});
|
||||
#else
|
||||
await Grid.OnRowClick(new DataGridRowMouseEventArgs<TItem>
|
||||
{
|
||||
Data = Item,
|
||||
AltKey = args.AltKey,
|
||||
Button = args.Button,
|
||||
Buttons = args.Buttons,
|
||||
ClientX = args.ClientX,
|
||||
ClientY = args.ClientY,
|
||||
CtrlKey = args.CtrlKey,
|
||||
Detail = args.Detail,
|
||||
MetaKey = args.MetaKey,
|
||||
ScreenX = args.ScreenX,
|
||||
ScreenY = args.ScreenY,
|
||||
ShiftKey = args.ShiftKey,
|
||||
Type = args.Type
|
||||
});
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
async Task OnDblClick(MouseEventArgs args)
|
||||
{
|
||||
if (Grid != null)
|
||||
{
|
||||
#if NET5
|
||||
await Grid.OnRowDblClick(new DataGridRowMouseEventArgs<TItem>
|
||||
{
|
||||
Data = Item,
|
||||
AltKey = args.AltKey,
|
||||
Button = args.Button,
|
||||
Buttons = args.Buttons,
|
||||
ClientX = args.ClientX,
|
||||
ClientY = args.ClientY,
|
||||
CtrlKey = args.CtrlKey,
|
||||
Detail = args.Detail,
|
||||
MetaKey = args.MetaKey,
|
||||
OffsetX = args.OffsetX,
|
||||
OffsetY = args.OffsetY,
|
||||
ScreenX = args.ScreenX,
|
||||
ScreenY = args.ScreenY,
|
||||
ShiftKey = args.ShiftKey,
|
||||
Type = args.Type
|
||||
});
|
||||
#else
|
||||
await Grid.OnRowDblClick(new DataGridRowMouseEventArgs<TItem>
|
||||
{
|
||||
Data = Item,
|
||||
AltKey = args.AltKey,
|
||||
Button = args.Button,
|
||||
Buttons = args.Buttons,
|
||||
ClientX = args.ClientX,
|
||||
ClientY = args.ClientY,
|
||||
CtrlKey = args.CtrlKey,
|
||||
Detail = args.Detail,
|
||||
MetaKey = args.MetaKey,
|
||||
ScreenX = args.ScreenX,
|
||||
ScreenY = args.ScreenY,
|
||||
ShiftKey = args.ShiftKey,
|
||||
Type = args.Type
|
||||
});
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
string GetCssClass()
|
||||
{
|
||||
if (Attributes != null && Attributes.TryGetValue("class", out var @class) && !string.IsNullOrEmpty(Convert.ToString(@class)))
|
||||
{
|
||||
return $"{CssClass} {@class}".Trim();
|
||||
}
|
||||
|
||||
return String.IsNullOrWhiteSpace(CssClass) ? null : CssClass;
|
||||
}
|
||||
|
||||
string GetStyle()
|
||||
{
|
||||
if (Attributes != null && Attributes.TryGetValue("style", out var style) == true && !string.IsNullOrEmpty(Convert.ToString(style)))
|
||||
{
|
||||
return String.IsNullOrEmpty(Style) ? $"{style}" : $"{Style.TrimEnd(';')};{style}";
|
||||
}
|
||||
|
||||
return Style;
|
||||
}
|
||||
}
|
||||
@@ -49,6 +49,18 @@ namespace Radzen.Blazor
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the child columns.
|
||||
/// </summary>
|
||||
/// <value>The child columns.</value>
|
||||
public IList<RadzenDataGridColumn<TItem>> ColumnsCollection
|
||||
{
|
||||
get
|
||||
{
|
||||
return Grid.childColumns.Where(c => c.Parent == this).ToList();
|
||||
}
|
||||
}
|
||||
|
||||
internal int GetLevel()
|
||||
{
|
||||
int i = 0;
|
||||
@@ -91,6 +103,16 @@ namespace Radzen.Blazor
|
||||
return Columns == null && Parent == null ? Grid.deepestChildColumnLevel + 1 : 1;
|
||||
}
|
||||
|
||||
Type _propertyType;
|
||||
internal Type PropertyType => _propertyType;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the unique identifier.
|
||||
/// </summary>
|
||||
/// <value>The unique identifier.</value>
|
||||
[Parameter]
|
||||
public string UniqueID { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Called when initialized.
|
||||
/// </summary>
|
||||
@@ -100,14 +122,16 @@ namespace Radzen.Blazor
|
||||
{
|
||||
Grid.AddColumn(this);
|
||||
|
||||
if (!string.IsNullOrEmpty(FilterProperty) || Type == null)
|
||||
{
|
||||
var property = GetFilterProperty();
|
||||
var property = GetFilterProperty();
|
||||
|
||||
if (!string.IsNullOrEmpty(property))
|
||||
{
|
||||
_filterPropertyType = PropertyAccess.GetPropertyType(typeof(TItem), property);
|
||||
}
|
||||
if (!string.IsNullOrEmpty(property))
|
||||
{
|
||||
_propertyType = PropertyAccess.GetPropertyType(typeof(TItem), property);
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(property) && Type == null)
|
||||
{
|
||||
_filterPropertyType = _propertyType;
|
||||
}
|
||||
|
||||
if (_filterPropertyType == null)
|
||||
@@ -135,7 +159,10 @@ namespace Radzen.Blazor
|
||||
[Parameter]
|
||||
public int? OrderIndex { get; set; }
|
||||
|
||||
internal int? GetOrderIndex()
|
||||
/// <summary>
|
||||
/// Gets the order index.
|
||||
/// </summary>
|
||||
public int? GetOrderIndex()
|
||||
{
|
||||
return orderIndex ?? OrderIndex;
|
||||
}
|
||||
@@ -152,12 +179,32 @@ namespace Radzen.Blazor
|
||||
[Parameter]
|
||||
public SortOrder? SortOrder { get; set; }
|
||||
|
||||
bool visible = true;
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether this <see cref="RadzenDataGridColumn{TItem}"/> is visible.
|
||||
/// </summary>
|
||||
/// <value><c>true</c> if visible; otherwise, <c>false</c>.</value>
|
||||
[Parameter]
|
||||
public bool Visible { get; set; } = true;
|
||||
public bool Visible
|
||||
{
|
||||
get
|
||||
{
|
||||
return visible;
|
||||
}
|
||||
set
|
||||
{
|
||||
if (visible != value)
|
||||
{
|
||||
visible = value;
|
||||
_visible = visible;
|
||||
if (Grid != null)
|
||||
{
|
||||
Grid.UpdatePickableColumn(this, visible);
|
||||
InvokeAsync(Grid.ChangeState);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool? _visible;
|
||||
|
||||
@@ -173,6 +220,11 @@ namespace Radzen.Blazor
|
||||
internal void SetVisible(bool? value)
|
||||
{
|
||||
_visible = value;
|
||||
|
||||
if (Grid != null && Pickable)
|
||||
{
|
||||
Grid.UpdatePickableColumn(this, _visible == true);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -182,6 +234,39 @@ namespace Radzen.Blazor
|
||||
[Parameter]
|
||||
public string Title { get; set; }
|
||||
|
||||
string _title;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the column title.
|
||||
/// </summary>
|
||||
/// <returns>System.String.</returns>
|
||||
public string GetTitle()
|
||||
{
|
||||
return _title ?? Title;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the column title.
|
||||
/// </summary>
|
||||
public void SetTitle(string value)
|
||||
{
|
||||
_title = value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the title in column picker.
|
||||
/// Value of Title is used when ColumnPickerTitle is not set
|
||||
/// </summary>
|
||||
/// <value>The column picker title.</value>
|
||||
[Parameter]
|
||||
public string ColumnPickerTitle
|
||||
{
|
||||
get => _columnPickerTitle ?? Title;
|
||||
set => _columnPickerTitle = value;
|
||||
}
|
||||
|
||||
string _columnPickerTitle;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the property name.
|
||||
/// </summary>
|
||||
@@ -217,6 +302,22 @@ namespace Radzen.Blazor
|
||||
[Parameter]
|
||||
public object FilterValue { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the filter placeholder.
|
||||
/// </summary>
|
||||
/// <value>The filter placeholder value.</value>
|
||||
[Parameter]
|
||||
public string FilterPlaceholder { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the filter placeholder.
|
||||
/// </summary>
|
||||
/// <returns>System.String.</returns>
|
||||
public string GetFilterPlaceholder()
|
||||
{
|
||||
return FilterPlaceholder ?? string.Empty;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the second filter value.
|
||||
/// </summary>
|
||||
@@ -290,10 +391,17 @@ namespace Radzen.Blazor
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether this <see cref="RadzenDataGridColumn{TItem}"/> is frozen.
|
||||
/// </summary>
|
||||
/// <value><c>true</c> if frozen; otherwise, <c>false</c>.</value>
|
||||
/// <value><c>true</c> if frozen will disable horizontal scroll for the column; otherwise, <c>false</c>.</value>
|
||||
[Parameter]
|
||||
public bool Frozen { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the frozen position this <see cref="RadzenDataGridColumn{TItem}"/>
|
||||
/// </summary>
|
||||
/// <value><see cref="FrozenColumnPosition.Left"/> or <see cref="FrozenColumnPosition.Right"/>.</value>
|
||||
[Parameter]
|
||||
public FrozenColumnPosition FrozenPosition { get; set; } = FrozenColumnPosition.Left;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether this <see cref="RadzenDataGridColumn{TItem}"/> is resizable.
|
||||
/// </summary>
|
||||
@@ -371,6 +479,20 @@ namespace Radzen.Blazor
|
||||
[Parameter]
|
||||
public RenderFragment<RadzenDataGridColumn<TItem>> FilterTemplate { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the filter value template.
|
||||
/// </summary>
|
||||
/// <value>The filter value template.</value>
|
||||
[Parameter]
|
||||
public RenderFragment<RadzenDataGridColumn<TItem>> FilterValueTemplate { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the second filter value template.
|
||||
/// </summary>
|
||||
/// <value>The second filter value template.</value>
|
||||
[Parameter]
|
||||
public RenderFragment<RadzenDataGridColumn<TItem>> SecondFilterValueTemplate { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the logical filter operator.
|
||||
/// </summary>
|
||||
@@ -392,11 +514,20 @@ namespace Radzen.Blazor
|
||||
/// </summary>
|
||||
/// <param name="item">The item.</param>
|
||||
/// <returns>System.Object.</returns>
|
||||
public object GetValue(TItem item)
|
||||
public virtual object GetValue(TItem item)
|
||||
{
|
||||
var value = propertyValueGetter != null && !string.IsNullOrEmpty(Property) && !Property.Contains('.') ? propertyValueGetter(item) : !string.IsNullOrEmpty(Property) ? PropertyAccess.GetValue(item, Property) : "";
|
||||
|
||||
return !string.IsNullOrEmpty(FormatString) ? string.Format(FormatString, value, Grid?.Culture ?? CultureInfo.CurrentCulture) : Convert.ToString(value, Grid?.Culture ?? CultureInfo.CurrentCulture);
|
||||
if ((PropertyAccess.IsEnum(FilterPropertyType) || PropertyAccess.IsNullableEnum(FilterPropertyType)) && value != null)
|
||||
{
|
||||
var enumValue = value as Enum;
|
||||
if (enumValue != null)
|
||||
{
|
||||
value = EnumExtensions.GetDisplayDescription(enumValue);
|
||||
}
|
||||
}
|
||||
|
||||
return !string.IsNullOrEmpty(FormatString) ? string.Format(Grid?.Culture ?? CultureInfo.CurrentCulture, FormatString, value) : Convert.ToString(value, Grid?.Culture ?? CultureInfo.CurrentCulture);
|
||||
}
|
||||
|
||||
internal object GetHeader()
|
||||
@@ -405,9 +536,9 @@ namespace Radzen.Blazor
|
||||
{
|
||||
return HeaderTemplate;
|
||||
}
|
||||
else if (!string.IsNullOrEmpty(Title))
|
||||
else if (!string.IsNullOrEmpty(GetTitle()))
|
||||
{
|
||||
return Title;
|
||||
return GetTitle();
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -421,20 +552,15 @@ namespace Radzen.Blazor
|
||||
/// <param name="forCell">if set to <c>true</c> [for cell].</param>
|
||||
/// <param name="isHeaderOrFooterCell">if set to <c>true</c> [is header or footer cell].</param>
|
||||
/// <returns>System.String.</returns>
|
||||
public string GetStyle(bool forCell = false, bool isHeaderOrFooterCell = false)
|
||||
public virtual string GetStyle(bool forCell = false, bool isHeaderOrFooterCell = false)
|
||||
{
|
||||
var style = new List<string>();
|
||||
|
||||
var width = GetWidth();
|
||||
|
||||
if (width != null)
|
||||
var width = GetWidthOrGridSetting()?.Trim();
|
||||
if (!string.IsNullOrEmpty(width))
|
||||
{
|
||||
style.Add($"width:{width}");
|
||||
}
|
||||
else if (Grid != null && Grid.ColumnWidth != null)
|
||||
{
|
||||
style.Add($"width:{Grid.ColumnWidth}");
|
||||
}
|
||||
|
||||
if (forCell && TextAlign != TextAlign.Left)
|
||||
{
|
||||
@@ -443,23 +569,10 @@ namespace Radzen.Blazor
|
||||
|
||||
if (forCell && IsFrozen())
|
||||
{
|
||||
var visibleColumns = Grid.ColumnsCollection.Where(c => c.GetVisible()).ToList();
|
||||
var left = visibleColumns
|
||||
.TakeWhile((c, i) => visibleColumns.IndexOf(this) > i && c.IsFrozen())
|
||||
.Sum(c => {
|
||||
var w = !string.IsNullOrEmpty(c.GetWidth()) ? c.GetWidth() : Grid.ColumnWidth;
|
||||
var cw = 200;
|
||||
if (!string.IsNullOrEmpty(w) && w.Contains("px"))
|
||||
{
|
||||
int.TryParse(w.Replace("px", ""), out cw);
|
||||
}
|
||||
return cw;
|
||||
});
|
||||
|
||||
style.Add($"left:{left}px");
|
||||
style.Add(GetStackedStyleForFrozen());
|
||||
}
|
||||
|
||||
if ((isHeaderOrFooterCell && IsFrozen() || isHeaderOrFooterCell && !IsFrozen() || !isHeaderOrFooterCell && IsFrozen()) && Grid.ColumnsCollection.Where(c => c.GetVisible() && c.IsFrozen()).Any())
|
||||
if (!isHeaderOrFooterCell && IsFrozen() || (isHeaderOrFooterCell && Grid.ColumnsCollection.Where(c => c.GetVisible() && c.IsFrozen()).Any()))
|
||||
{
|
||||
style.Add($"z-index:{(isHeaderOrFooterCell && IsFrozen() ? 2 : 1)}");
|
||||
}
|
||||
@@ -472,6 +585,59 @@ namespace Radzen.Blazor
|
||||
return string.Join(";", style);
|
||||
}
|
||||
|
||||
private string GetStackedStyleForFrozen()
|
||||
{
|
||||
var visibleFrozenColumns = Grid.ColumnsCollection.Where(c => c.GetVisible() && c.IsFrozen() && c.FrozenPosition == FrozenPosition).ToList();
|
||||
if (FrozenPosition == FrozenColumnPosition.Left)
|
||||
{
|
||||
var stackColumns = visibleFrozenColumns.Where((c, i) => visibleFrozenColumns.IndexOf(this) > i);
|
||||
|
||||
return GetStackedStyleForFrozen(stackColumns, "left");
|
||||
}
|
||||
else
|
||||
{
|
||||
var stackColumns = visibleFrozenColumns.Where((c, i) => visibleFrozenColumns.IndexOf(this) < i);
|
||||
|
||||
return GetStackedStyleForFrozen(stackColumns, "right");
|
||||
}
|
||||
}
|
||||
|
||||
private static string GetStackedStyleForFrozen(IEnumerable<RadzenDataGridColumn<TItem>> stackColumns, string position)
|
||||
{
|
||||
if (!stackColumns.Any())
|
||||
{
|
||||
return $"{position}:0";
|
||||
}
|
||||
|
||||
var widths = new List<string>();
|
||||
foreach (var column in stackColumns)
|
||||
{
|
||||
var w = column.GetWidthOrGridSetting()?.Trim();
|
||||
|
||||
if (string.IsNullOrEmpty(w))
|
||||
{
|
||||
widths.Add("200px");
|
||||
continue;
|
||||
}
|
||||
|
||||
if (w.StartsWith("calc(") && w.EndsWith(")"))
|
||||
{
|
||||
var calcExpression = w.Remove(w.Length - 1).Substring("calc(".Length);
|
||||
widths.Add(calcExpression);
|
||||
continue;
|
||||
}
|
||||
|
||||
widths.Add(w);
|
||||
}
|
||||
|
||||
if (widths.Count == 1)
|
||||
{
|
||||
return $"{position}:{widths.First()}";
|
||||
}
|
||||
|
||||
return $"{position}:calc({string.Join(" + ", widths)})";
|
||||
}
|
||||
|
||||
internal bool IsFrozen()
|
||||
{
|
||||
return Frozen && Parent == null && Columns == null;
|
||||
@@ -503,6 +669,37 @@ namespace Radzen.Blazor
|
||||
}
|
||||
|
||||
internal void SetSortOrder(SortOrder? order)
|
||||
{
|
||||
var descriptor = Grid.sorts.Where(d => d.Property == GetSortProperty()).FirstOrDefault();
|
||||
if (descriptor == null)
|
||||
{
|
||||
descriptor = new SortDescriptor() { Property = GetSortProperty() };
|
||||
}
|
||||
|
||||
if (order.HasValue)
|
||||
{
|
||||
SetSortOrderInternal(order.Value);
|
||||
descriptor.SortOrder = order.Value;
|
||||
}
|
||||
else
|
||||
{
|
||||
SetSortOrderInternal(null);
|
||||
if (Grid.sorts.Where(d => d.Property == GetSortProperty()).Any())
|
||||
{
|
||||
Grid.sorts.Remove(descriptor);
|
||||
}
|
||||
descriptor = null;
|
||||
}
|
||||
|
||||
if (descriptor != null && !Grid.sorts.Where(d => d.Property == GetSortProperty()).Any())
|
||||
{
|
||||
Grid.sorts.Add(descriptor);
|
||||
}
|
||||
|
||||
sortOrder = new SortOrder?[] { order };
|
||||
}
|
||||
|
||||
internal void SetSortOrderInternal(SortOrder? order)
|
||||
{
|
||||
sortOrder = new SortOrder?[] { order };
|
||||
}
|
||||
@@ -546,7 +743,10 @@ namespace Radzen.Blazor
|
||||
|
||||
Type _filterPropertyType;
|
||||
|
||||
internal Type FilterPropertyType
|
||||
/// <summary>
|
||||
/// Gets the filter property type.
|
||||
/// </summary>
|
||||
public Type FilterPropertyType
|
||||
{
|
||||
get
|
||||
{
|
||||
@@ -593,9 +793,32 @@ namespace Radzen.Blazor
|
||||
}
|
||||
}
|
||||
|
||||
if (parameters.DidParameterChange(nameof(Pickable), Pickable))
|
||||
{
|
||||
var newPickable = parameters.GetValueOrDefault<bool>(nameof(Pickable));
|
||||
|
||||
Pickable = newPickable;
|
||||
|
||||
if (Grid != null)
|
||||
{
|
||||
Grid.UpdatePickableColumns();
|
||||
await Grid.ChangeState();
|
||||
}
|
||||
}
|
||||
|
||||
if (parameters.DidParameterChange(nameof(SortOrder), SortOrder))
|
||||
{
|
||||
sortOrder = new SortOrder?[] { parameters.GetValueOrDefault<SortOrder?>(nameof(SortOrder)) };
|
||||
|
||||
if (Grid != null)
|
||||
{
|
||||
var descriptor = Grid.sorts.Where(d => d.Property == GetSortProperty()).FirstOrDefault();
|
||||
if (descriptor == null)
|
||||
{
|
||||
Grid.sorts.Add(new SortDescriptor() { Property = GetSortProperty(), SortOrder = sortOrder.FirstOrDefault() });
|
||||
Grid._view = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (parameters.DidParameterChange(nameof(FilterValue), FilterValue))
|
||||
@@ -605,9 +828,36 @@ namespace Radzen.Blazor
|
||||
if (FilterTemplate != null)
|
||||
{
|
||||
FilterValue = filterValue;
|
||||
Grid.SaveSettings();
|
||||
if (Grid.IsVirtualizationAllowed())
|
||||
{
|
||||
#if NET5
|
||||
#if NET5_0_OR_GREATER
|
||||
if (Grid.virtualize != null)
|
||||
{
|
||||
await Grid.virtualize.RefreshDataAsync();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
await Grid.Reload();
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (parameters.DidParameterChange(nameof(SecondFilterValue), SecondFilterValue))
|
||||
{
|
||||
secondFilterValue = parameters.GetValueOrDefault<object>(nameof(SecondFilterValue));
|
||||
|
||||
if (FilterTemplate != null)
|
||||
{
|
||||
SecondFilterValue = secondFilterValue;
|
||||
Grid.SaveSettings();
|
||||
if (Grid.IsVirtualizationAllowed())
|
||||
{
|
||||
#if NET5_0_OR_GREATER
|
||||
if (Grid.virtualize != null)
|
||||
{
|
||||
await Grid.virtualize.RefreshDataAsync();
|
||||
@@ -646,37 +896,58 @@ namespace Radzen.Blazor
|
||||
await base.SetParametersAsync(parameters);
|
||||
}
|
||||
|
||||
internal SortOrder? GetSortOrder()
|
||||
/// <summary>
|
||||
/// Get column sort order.
|
||||
/// </summary>
|
||||
public SortOrder? GetSortOrder()
|
||||
{
|
||||
return sortOrder.Any() ? sortOrder.FirstOrDefault() : SortOrder;
|
||||
}
|
||||
|
||||
internal object GetFilterValue()
|
||||
/// <summary>
|
||||
/// Get column filter value.
|
||||
/// </summary>
|
||||
public object GetFilterValue()
|
||||
{
|
||||
return filterValue ?? FilterValue;
|
||||
}
|
||||
|
||||
internal FilterOperator GetFilterOperator()
|
||||
/// <summary>
|
||||
/// Get column filter operator.
|
||||
/// </summary>
|
||||
public FilterOperator GetFilterOperator()
|
||||
{
|
||||
return filterOperator ?? FilterOperator;
|
||||
}
|
||||
|
||||
internal object GetSecondFilterValue()
|
||||
/// <summary>
|
||||
/// Get column second filter value.
|
||||
/// </summary>
|
||||
public object GetSecondFilterValue()
|
||||
{
|
||||
return secondFilterValue ?? SecondFilterValue;
|
||||
}
|
||||
|
||||
internal FilterOperator GetSecondFilterOperator()
|
||||
/// <summary>
|
||||
/// Get column second filter operator.
|
||||
/// </summary>
|
||||
public FilterOperator GetSecondFilterOperator()
|
||||
{
|
||||
return secondFilterOperator ?? SecondFilterOperator;
|
||||
}
|
||||
|
||||
internal LogicalFilterOperator GetLogicalFilterOperator()
|
||||
/// <summary>
|
||||
/// Get column logical filter operator.
|
||||
/// </summary>
|
||||
public LogicalFilterOperator GetLogicalFilterOperator()
|
||||
{
|
||||
return logicalFilterOperator ?? LogicalFilterOperator;
|
||||
}
|
||||
|
||||
internal void SetFilterValue(object value, bool isFirst = true)
|
||||
/// <summary>
|
||||
/// Set column filter value.
|
||||
/// </summary>
|
||||
public void SetFilterValue(object value, bool isFirst = true)
|
||||
{
|
||||
if ((FilterPropertyType == typeof(DateTimeOffset) || FilterPropertyType == typeof(DateTimeOffset?)) && value != null && value is DateTime?)
|
||||
{
|
||||
@@ -694,12 +965,30 @@ namespace Radzen.Blazor
|
||||
}
|
||||
}
|
||||
|
||||
internal bool CanSetFilterValue()
|
||||
{
|
||||
return GetFilterOperator() == FilterOperator.IsNull || GetFilterOperator() == FilterOperator.IsNotNull;
|
||||
/// <summary>
|
||||
/// Set column filter value and reload grid.
|
||||
/// </summary>
|
||||
/// <param name="value">Filter value.</param>
|
||||
/// <param name="isFirst"><c>true</c> if FilterValue; <c>false</c> for SecondFilterValue</param>
|
||||
public async Task SetFilterValueAsync(object value, bool isFirst = true)
|
||||
{
|
||||
SetFilterValue(value, isFirst);
|
||||
Grid.SaveSettings();
|
||||
await Grid.FirstPage(true);
|
||||
}
|
||||
|
||||
internal void ClearFilters()
|
||||
internal bool CanSetFilterValue()
|
||||
{
|
||||
return GetFilterOperator() == FilterOperator.IsNull
|
||||
|| GetFilterOperator() == FilterOperator.IsNotNull
|
||||
|| GetFilterOperator() == FilterOperator.IsEmpty
|
||||
|| GetFilterOperator() == FilterOperator.IsNotEmpty;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets to default column filter values and operators.
|
||||
/// </summary>
|
||||
public void ClearFilters()
|
||||
{
|
||||
SetFilterValue(null);
|
||||
SetFilterValue(null, false);
|
||||
@@ -708,7 +997,11 @@ namespace Radzen.Blazor
|
||||
|
||||
FilterValue = null;
|
||||
SecondFilterValue = null;
|
||||
FilterOperator = default(FilterOperator);
|
||||
FilterOperator = FilterOperator == FilterOperator.Custom
|
||||
? FilterOperator.Custom
|
||||
: typeof(System.Collections.IEnumerable).IsAssignableFrom(FilterPropertyType)
|
||||
? FilterOperator.Contains
|
||||
: default(FilterOperator);
|
||||
SecondFilterOperator = default(FilterOperator);
|
||||
LogicalFilterOperator = default(LogicalFilterOperator);
|
||||
}
|
||||
@@ -727,17 +1020,36 @@ namespace Radzen.Blazor
|
||||
[Parameter]
|
||||
public FilterOperator SecondFilterOperator { get; set; }
|
||||
|
||||
internal void SetFilterOperator(FilterOperator? value)
|
||||
/// <summary>
|
||||
/// Set column filter operator.
|
||||
/// </summary>
|
||||
public void SetFilterOperator(FilterOperator? value)
|
||||
{
|
||||
if (value == FilterOperator.IsEmpty || value == FilterOperator.IsNotEmpty || value == FilterOperator.IsNull || value == FilterOperator.IsNotNull)
|
||||
{
|
||||
filterValue = value == FilterOperator.IsEmpty || value == FilterOperator.IsNotEmpty ? string.Empty : null;
|
||||
}
|
||||
|
||||
filterOperator = value;
|
||||
}
|
||||
|
||||
internal void SetSecondFilterOperator(FilterOperator? value)
|
||||
/// <summary>
|
||||
/// Set column second filter operator.
|
||||
/// </summary>
|
||||
public void SetSecondFilterOperator(FilterOperator? value)
|
||||
{
|
||||
if (value == FilterOperator.IsEmpty || value == FilterOperator.IsNotEmpty || value == FilterOperator.IsNull || value == FilterOperator.IsNotNull)
|
||||
{
|
||||
secondFilterValue = value == FilterOperator.IsEmpty || value == FilterOperator.IsNotEmpty ? string.Empty : null;
|
||||
}
|
||||
|
||||
secondFilterOperator = value;
|
||||
}
|
||||
|
||||
internal void SetLogicalFilterOperator(LogicalFilterOperator value)
|
||||
/// <summary>
|
||||
/// Set column second logical operator.
|
||||
/// </summary>
|
||||
public void SetLogicalFilterOperator(LogicalFilterOperator value)
|
||||
{
|
||||
LogicalFilterOperator = value;
|
||||
}
|
||||
@@ -748,38 +1060,75 @@ namespace Radzen.Blazor
|
||||
/// </summary>
|
||||
public async Task CloseFilter()
|
||||
{
|
||||
if (Grid.FilterPopupRenderMode == PopupRenderMode.OnDemand && headerCell != null)
|
||||
{
|
||||
await headerCell.CloseFilter();
|
||||
}
|
||||
await Grid.GetJSRuntime().InvokeVoidAsync("Radzen.closePopup", $"{Grid.PopupID}{GetFilterProperty()}");
|
||||
}
|
||||
|
||||
string runtimeWidth;
|
||||
|
||||
internal void SetWidth(string value)
|
||||
/// <summary>
|
||||
/// Set column width.
|
||||
/// </summary>
|
||||
public void SetWidth(string value)
|
||||
{
|
||||
runtimeWidth = value;
|
||||
|
||||
if (IsFrozen())
|
||||
{
|
||||
InvokeAsync(() => Grid.ChangeState());
|
||||
}
|
||||
}
|
||||
|
||||
internal string GetWidth()
|
||||
/// <summary>
|
||||
/// Get column width.
|
||||
/// </summary>
|
||||
public string GetWidth()
|
||||
{
|
||||
return !string.IsNullOrEmpty(runtimeWidth) ? runtimeWidth : Width;
|
||||
}
|
||||
|
||||
internal IEnumerable<FilterOperator> GetFilterOperators()
|
||||
/// <summary>
|
||||
/// Get column width if it's set, otherwise get a column width set on the grid.
|
||||
/// </summary>
|
||||
internal string GetWidthOrGridSetting()
|
||||
{
|
||||
var internalWidth = GetWidth();
|
||||
return !string.IsNullOrWhiteSpace(internalWidth) ? internalWidth : Grid?.ColumnWidth;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get possible column filter operators.
|
||||
/// </summary>
|
||||
public virtual IEnumerable<FilterOperator> GetFilterOperators()
|
||||
{
|
||||
if (PropertyAccess.IsEnum(FilterPropertyType))
|
||||
return new FilterOperator[] { FilterOperator.Equals, FilterOperator.NotEquals };
|
||||
|
||||
|
||||
if (PropertyAccess.IsNullableEnum(FilterPropertyType))
|
||||
return new FilterOperator[] { FilterOperator.Equals, FilterOperator.NotEquals, FilterOperator.IsNull, FilterOperator.IsNotNull };
|
||||
|
||||
return Enum.GetValues(typeof(FilterOperator)).Cast<FilterOperator>().Where(o => {
|
||||
var isStringOperator = o == FilterOperator.Contains || o == FilterOperator.DoesNotContain || o == FilterOperator.StartsWith || o == FilterOperator.EndsWith;
|
||||
return FilterPropertyType == typeof(string) ? isStringOperator
|
||||
|| o == FilterOperator.Equals || o == FilterOperator.NotEquals || o == FilterOperator.IsNull || o == FilterOperator.IsNotNull
|
||||
: !isStringOperator;
|
||||
return Enum.GetValues(typeof(FilterOperator)).Cast<FilterOperator>().Where(o =>
|
||||
{
|
||||
var isStringOperator = o == FilterOperator.Contains || o == FilterOperator.DoesNotContain
|
||||
|| o == FilterOperator.StartsWith || o == FilterOperator.EndsWith || o == FilterOperator.IsEmpty || o == FilterOperator.IsNotEmpty;
|
||||
|
||||
if ((FilterPropertyType == typeof(string) || !QueryableExtension.IsEnumerable(FilterPropertyType)) &&
|
||||
(o == FilterOperator.In || o == FilterOperator.NotIn)) return false;
|
||||
|
||||
return FilterPropertyType == typeof(string) || QueryableExtension.IsEnumerable(FilterPropertyType) ? isStringOperator
|
||||
|| o == FilterOperator.Equals || o == FilterOperator.NotEquals
|
||||
|| o == FilterOperator.IsNull || o == FilterOperator.IsNotNull
|
||||
: !isStringOperator;
|
||||
});
|
||||
}
|
||||
|
||||
internal string GetFilterOperatorText(FilterOperator filterOperator)
|
||||
/// <summary>
|
||||
/// Get filter operator text
|
||||
/// </summary>
|
||||
public string GetFilterOperatorText(FilterOperator filterOperator)
|
||||
{
|
||||
switch (filterOperator)
|
||||
{
|
||||
@@ -793,7 +1142,7 @@ namespace Radzen.Blazor
|
||||
return Grid?.EqualsText;
|
||||
case FilterOperator.GreaterThan:
|
||||
return Grid?.GreaterThanText;
|
||||
case FilterOperator. GreaterThanOrEquals:
|
||||
case FilterOperator.GreaterThanOrEquals:
|
||||
return Grid?.GreaterThanOrEqualsText;
|
||||
case FilterOperator.LessThan:
|
||||
return Grid?.LessThanText;
|
||||
@@ -805,8 +1154,12 @@ namespace Radzen.Blazor
|
||||
return Grid?.NotEqualsText;
|
||||
case FilterOperator.IsNull:
|
||||
return Grid?.IsNullText;
|
||||
case FilterOperator.IsEmpty:
|
||||
return Grid?.IsEmptyText;
|
||||
case FilterOperator.IsNotNull:
|
||||
return Grid?.IsNotNullText;
|
||||
case FilterOperator.IsNotEmpty:
|
||||
return Grid?.IsNotEmptyText;
|
||||
default:
|
||||
return $"{filterOperator}";
|
||||
}
|
||||
@@ -841,11 +1194,52 @@ namespace Radzen.Blazor
|
||||
return "∅";
|
||||
case FilterOperator.IsNotNull:
|
||||
return "!∅";
|
||||
case FilterOperator.IsEmpty:
|
||||
return "= ''";
|
||||
case FilterOperator.IsNotEmpty:
|
||||
return "≠ ''";
|
||||
default:
|
||||
return $"{filterOperator}";
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets value indicating if the user can specify time in DateTime column filter.
|
||||
/// </summary>
|
||||
public virtual bool ShowTimeForDateTimeFilter()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets value indicating if up and down buttons are displayed in numeric column filter.
|
||||
/// </summary>
|
||||
public virtual bool ShowUpDownForNumericFilter()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets an OData expression to filter by this column.
|
||||
/// </summary>
|
||||
/// <param name="second">Whether to use <see cref="SecondFilterValue"/> instead of <see cref="FilterValue"/></param>
|
||||
/// <returns>An OData expression to filter by this column.</returns>
|
||||
public string GetColumnODataFilter(bool second = false)
|
||||
{
|
||||
return GetColumnODataFilter(second ? GetSecondFilterValue() : GetFilterValue(), second ? GetSecondFilterOperator() : GetFilterOperator());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets an OData expression to filter by this column.
|
||||
/// </summary>
|
||||
/// <param name="filterValue">The specific value to filter by</param>
|
||||
/// <param name="filterOperator">The operator used to compare to <paramref name="filterValue"/></param>
|
||||
/// <returns>An OData expression to filter by this column.</returns>
|
||||
protected virtual string GetColumnODataFilter(object filterValue, FilterOperator filterOperator)
|
||||
{
|
||||
return QueryableExtension.GetColumnODataFilter(this, filterValue, filterOperator);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Disposes this instance.
|
||||
/// </summary>
|
||||
@@ -853,5 +1247,24 @@ namespace Radzen.Blazor
|
||||
{
|
||||
Grid?.RemoveColumn(this);
|
||||
}
|
||||
|
||||
internal int? getSortIndex()
|
||||
{
|
||||
var descriptor = Grid.sorts.Where(s => s.Property == GetSortProperty()).FirstOrDefault();
|
||||
if (descriptor != null)
|
||||
{
|
||||
return Grid.sorts.IndexOf(descriptor);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
internal string getSortIndexAsString()
|
||||
{
|
||||
var index = getSortIndex();
|
||||
return index != null ? $"{getSortIndex() + 1}" : "";
|
||||
}
|
||||
|
||||
internal RadzenDataGridHeaderCell<TItem> headerCell;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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">filter_alt</i>
|
||||
<i class="rzi">@Grid.FilterIcon</i>
|
||||
@if (Column.GetFilterOperator() == FilterOperator.DoesNotContain)
|
||||
{
|
||||
<s>@Column.GetFilterOperatorSymbol(Column.GetFilterOperator())</s>
|
||||
@@ -16,46 +16,97 @@
|
||||
<div id="@($"{Grid.PopupID}{Column.GetFilterProperty()}")" class="rz-overlaypanel"
|
||||
style="display:none;" tabindex="0">
|
||||
<div class="rz-overlaypanel-content">
|
||||
<ul class="rz-listbox-list" style="margin:5px">
|
||||
<ul class="rz-listbox-list">
|
||||
@if (Column.FilterPropertyType == typeof(string))
|
||||
{
|
||||
@if (Column.GetFilterOperators().Contains(FilterOperator.Contains))
|
||||
{
|
||||
<li class="@(FilterOperatorStyle(Column, FilterOperator.Contains))" @onclick="@(args => ApplyFilter(FilterOperator.Contains))" style="display: block;">
|
||||
<span class="rz-filter-menu-symbol">@Column.GetFilterOperatorSymbol(FilterOperator.Contains)</span><span>@Grid.ContainsText</span>
|
||||
</li>
|
||||
}
|
||||
@if (Column.GetFilterOperators().Contains(FilterOperator.DoesNotContain))
|
||||
{
|
||||
<li class="@(FilterOperatorStyle(Column, FilterOperator.DoesNotContain))" @onclick="@(args => ApplyFilter(FilterOperator.DoesNotContain))" style="display: block;">
|
||||
<span class="rz-filter-menu-symbol"><s>@Column.GetFilterOperatorSymbol(FilterOperator.DoesNotContain)</s></span><span>@Grid.DoesNotContainText</span>
|
||||
</li>
|
||||
}
|
||||
@if (Column.GetFilterOperators().Contains(FilterOperator.StartsWith))
|
||||
{
|
||||
<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))
|
||||
{
|
||||
<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))
|
||||
{
|
||||
<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))
|
||||
{
|
||||
<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>
|
||||
</li>
|
||||
}
|
||||
}
|
||||
@if (Column.GetFilterOperators().Contains(FilterOperator.Equals))
|
||||
{
|
||||
<li class="@(FilterOperatorStyle(Column, FilterOperator.Equals))" @onclick="@(args => ApplyFilter(FilterOperator.Equals))" style="display: block;">
|
||||
<span class="rz-filter-menu-symbol">@Column.GetFilterOperatorSymbol(FilterOperator.Equals)</span><span>@Grid.EqualsText</span>
|
||||
</li>
|
||||
}
|
||||
@if (Column.GetFilterOperators().Contains(FilterOperator.NotEquals))
|
||||
{
|
||||
<li class="@(FilterOperatorStyle(Column, FilterOperator.NotEquals))" @onclick="@(args => ApplyFilter(FilterOperator.NotEquals))" style="display: block;">
|
||||
<span class="rz-filter-menu-symbol">@Column.GetFilterOperatorSymbol(FilterOperator.NotEquals)</span><span>@Grid.NotEqualsText</span>
|
||||
</li>
|
||||
}
|
||||
@if (Column.GetFilterOperators().Contains(FilterOperator.LessThan))
|
||||
{
|
||||
<li class="@(FilterOperatorStyle(Column, FilterOperator.LessThan))" @onclick="@(args => ApplyFilter(FilterOperator.LessThan))" style="display: block;">
|
||||
<span class="rz-filter-menu-symbol">@Column.GetFilterOperatorSymbol(FilterOperator.LessThan)</span><span>@Grid.LessThanText</span>
|
||||
</li>
|
||||
}
|
||||
@if (Column.GetFilterOperators().Contains(FilterOperator.LessThanOrEquals))
|
||||
{
|
||||
<li class="@(FilterOperatorStyle(Column, FilterOperator.LessThanOrEquals))" @onclick="@(args => ApplyFilter(FilterOperator.LessThanOrEquals))" style="display: block;">
|
||||
<span class="rz-filter-menu-symbol">@Column.GetFilterOperatorSymbol(FilterOperator.LessThanOrEquals)</span><span>@Grid.LessThanOrEqualsText</span>
|
||||
</li>
|
||||
}
|
||||
@if (Column.GetFilterOperators().Contains(FilterOperator.GreaterThan))
|
||||
{
|
||||
<li class="@(FilterOperatorStyle(Column, FilterOperator.GreaterThan))" @onclick="@(args => ApplyFilter(FilterOperator.GreaterThan))" style="display: block;">
|
||||
<span class="rz-filter-menu-symbol">@Column.GetFilterOperatorSymbol(FilterOperator.GreaterThan)</span><span>@Grid.GreaterThanText</span>
|
||||
</li>
|
||||
}
|
||||
@if (Column.GetFilterOperators().Contains(FilterOperator.GreaterThanOrEquals))
|
||||
{
|
||||
<li class="@(FilterOperatorStyle(Column, FilterOperator.GreaterThanOrEquals))" @onclick="@(args => ApplyFilter(FilterOperator.GreaterThanOrEquals))" style="display: block;">
|
||||
<span class="rz-filter-menu-symbol">@Column.GetFilterOperatorSymbol(FilterOperator.GreaterThanOrEquals)</span><span>@Grid.GreaterThanOrEqualsText</span>
|
||||
</li>
|
||||
}
|
||||
@if (Column.GetFilterOperators().Contains(FilterOperator.IsNull))
|
||||
{
|
||||
<li class="@(FilterOperatorStyle(Column, FilterOperator.IsNull))" @onclick="@(args => ApplyFilter(FilterOperator.IsNull))" style="display: block;">
|
||||
<span class="rz-filter-menu-symbol">@Column.GetFilterOperatorSymbol(FilterOperator.IsNull)</span><span>@Grid.IsNullText</span>
|
||||
</li>
|
||||
}
|
||||
@if (Column.GetFilterOperators().Contains(FilterOperator.IsNotNull))
|
||||
{
|
||||
<li class="@(FilterOperatorStyle(Column, FilterOperator.IsNotNull))" @onclick="@(args => ApplyFilter(FilterOperator.IsNotNull))" style="display: block;">
|
||||
<span class="rz-filter-menu-symbol">@Column.GetFilterOperatorSymbol(FilterOperator.IsNotNull)</span><span>@Grid.IsNotNullText</span>
|
||||
</li>
|
||||
}
|
||||
<li class="rz-multiselect-item" @onclick="@(args => ClearFilter())" style="display:block;">
|
||||
<span class="rz-filter-menu-symbol">x</span><span>@Grid.ClearFilterText</span>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
@@ -76,21 +127,25 @@
|
||||
protected string FilterIconStyle()
|
||||
{
|
||||
var additionalStyle = Column.GetFilterValue() != null || Column.GetSecondFilterValue() != null ||
|
||||
Column.GetFilterOperator() == FilterOperator.IsNotNull || Column.GetFilterOperator() == FilterOperator.IsNull
|
||||
? "rz-grid-filter-active" : "";
|
||||
return $"rz-filter-button rz-button rz-button-md rz-button-icon-only btn-light {additionalStyle}";
|
||||
Column.GetFilterOperator() == FilterOperator.IsNotNull || Column.GetFilterOperator() == FilterOperator.IsNull
|
||||
|| Column.GetFilterOperator() == FilterOperator.IsEmpty || Column.GetFilterOperator() == FilterOperator.IsNotEmpty
|
||||
? "rz-grid-filter-active" : "";
|
||||
return $"rz-filter-button rz-button rz-button-md rz-button-icon-only rz-variant-flat rz-light {additionalStyle}";
|
||||
}
|
||||
|
||||
protected async Task ApplyFilter(FilterOperator value)
|
||||
{
|
||||
if (value == FilterOperator.IsNull || value == FilterOperator.IsNotNull)
|
||||
if (value == FilterOperator.IsNull || value == FilterOperator.IsNotNull
|
||||
|| value == FilterOperator.IsEmpty || value == FilterOperator.IsNotEmpty)
|
||||
{
|
||||
Column.SetFilterValue(null);
|
||||
Column.SetFilterValue(value == FilterOperator.IsEmpty || value == FilterOperator.IsNotEmpty ? string.Empty : null);
|
||||
Column.SetFilterValue(null, false);
|
||||
}
|
||||
|
||||
Column.SetFilterOperator(value);
|
||||
|
||||
Grid.SaveSettings();
|
||||
|
||||
await Grid.Filter.InvokeAsync(new DataGridColumnFilterEventArgs<TItem>()
|
||||
{
|
||||
Column = Column,
|
||||
@@ -102,6 +157,27 @@
|
||||
});
|
||||
|
||||
await JSRuntime.InvokeVoidAsync("Radzen.closePopup", $"{Grid.PopupID}{Column.GetFilterProperty()}");
|
||||
await Grid.Reload();
|
||||
await Grid.ReloadInternal();
|
||||
}
|
||||
}
|
||||
|
||||
protected async Task ClearFilter()
|
||||
{
|
||||
Column.ClearFilters();
|
||||
|
||||
Grid.SaveSettings();
|
||||
|
||||
await JSRuntime.InvokeVoidAsync("Radzen.closePopup", $"{Grid.PopupID}{Column.GetFilterProperty()}");
|
||||
|
||||
await Grid.FilterCleared.InvokeAsync(new DataGridColumnFilterEventArgs<TItem>()
|
||||
{
|
||||
Column = Column,
|
||||
FilterValue = Column.GetFilterValue(),
|
||||
SecondFilterValue = Column.GetSecondFilterValue(),
|
||||
FilterOperator = Column.GetFilterOperator(),
|
||||
SecondFilterOperator = Column.GetSecondFilterOperator(),
|
||||
LogicalFilterOperator = Column.GetLogicalFilterOperator()
|
||||
});
|
||||
|
||||
await Grid.ReloadInternal();
|
||||
}
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user