mirror of
https://github.com/radzenhq/radzen-blazor.git
synced 2026-02-04 05:35:44 +00:00
Compare commits
1338 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
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 | ||
|
|
1959c009fd | ||
|
|
35f5bdd483 | ||
|
|
ff422bae19 | ||
|
|
f2e4d5cc1b | ||
|
|
5fba69cad3 | ||
|
|
a1385956aa | ||
|
|
9493cbc6ff | ||
|
|
0762841ef0 | ||
|
|
e94fb73fd2 | ||
|
|
6cb5f738d4 | ||
|
|
1b66d6fe4d | ||
|
|
3a9511a6b2 | ||
|
|
70cfcda727 | ||
|
|
ef7ab11078 | ||
|
|
14ad9618d3 | ||
|
|
41ce3d862c | ||
|
|
2ae9e8bb6f | ||
|
|
8ebdaee97f | ||
|
|
9dab0f0c03 | ||
|
|
3144a6b5fd | ||
|
|
f6ed045b8f | ||
|
|
b31c29b440 | ||
|
|
0bf4181056 | ||
|
|
ff3fc84563 | ||
|
|
644af53193 | ||
|
|
b52eb24e85 | ||
|
|
b0ee04fab2 | ||
|
|
0b01f5ec1c | ||
|
|
310a2f5443 | ||
|
|
9c7de1a8fe | ||
|
|
2ff2d55f25 | ||
|
|
3d5e7be6b6 | ||
|
|
4bce655cb6 | ||
|
|
f2aa01d23c | ||
|
|
37907ed7f6 | ||
|
|
17d34ae443 | ||
|
|
5e442d43aa | ||
|
|
3594c81b17 | ||
|
|
221c830d60 | ||
|
|
962c2db587 | ||
|
|
e22d3367ba | ||
|
|
27df815529 | ||
|
|
64ad14ae80 | ||
|
|
3de09dc8db | ||
|
|
170aede49f | ||
|
|
9ab740e53b | ||
|
|
ddd4a806e1 | ||
|
|
5b4b427589 | ||
|
|
67900764f0 | ||
|
|
df3995f0bb | ||
|
|
96278eb6d4 | ||
|
|
b012abbffb | ||
|
|
cd52110e95 | ||
|
|
eba00e0e26 | ||
|
|
baab38c7f6 | ||
|
|
539530bcb9 | ||
|
|
829cdec53c | ||
|
|
1bbe89f962 | ||
|
|
1ae9724d34 | ||
|
|
d71142a253 | ||
|
|
ca0437d765 | ||
|
|
7e4619c2ae | ||
|
|
65dd9e26e9 | ||
|
|
fe788ca5dc | ||
|
|
4e3fd87481 | ||
|
|
6244663e80 | ||
|
|
3bce988e12 | ||
|
|
0fcc9e112a | ||
|
|
d083ae6d0e | ||
|
|
ddffc72e76 | ||
|
|
20d22fa036 | ||
|
|
ccb923ecc4 | ||
|
|
90f98c69c5 | ||
|
|
2f273777b2 | ||
|
|
3936960caf | ||
|
|
e32262a3b3 | ||
|
|
bc9d7f7c2a | ||
|
|
71fe870b1d | ||
|
|
28a0456fa7 | ||
|
|
ad7e00add5 | ||
|
|
6e5749063c | ||
|
|
048de253a9 | ||
|
|
c6c9578691 | ||
|
|
b052c04749 | ||
|
|
5085255f61 | ||
|
|
cd306135ad | ||
|
|
fbb9cac178 | ||
|
|
291210aadf | ||
|
|
458a9b9907 | ||
|
|
d210feab0d | ||
|
|
c3aaf78161 | ||
|
|
a86c7c6c1e | ||
|
|
8f79204fbc | ||
|
|
c21823c84e | ||
|
|
c40f64a193 | ||
|
|
f42cd221cc | ||
|
|
a8dc2a07db | ||
|
|
93e27f318d | ||
|
|
7ecb3ccf46 | ||
|
|
1dd48aa3f1 | ||
|
|
9ee7c6809a | ||
|
|
4eec46012a | ||
|
|
455edff025 | ||
|
|
79a43fe897 | ||
|
|
34306f023c | ||
|
|
e42baf816c | ||
|
|
f4cf76bc8f | ||
|
|
d7ef57a24e | ||
|
|
a349a3390c | ||
|
|
eae6e6ed8d | ||
|
|
14d87875ae | ||
|
|
62d997c85a | ||
|
|
02f37b2eeb | ||
|
|
636e6b82be | ||
|
|
72c544a512 | ||
|
|
97c7a4db17 | ||
|
|
aa8b4881ce | ||
|
|
c6d37a4281 | ||
|
|
05b269c0cf | ||
|
|
07d14cee67 | ||
|
|
70fb35bd25 | ||
|
|
574f4f90da | ||
|
|
6a951e1325 | ||
|
|
4a1abadd09 | ||
|
|
84bd0af02e | ||
|
|
115b838d3c | ||
|
|
13032e726b | ||
|
|
cf6efbaa2d | ||
|
|
580db415d6 | ||
|
|
30b2d1d913 | ||
|
|
510b2bcdd5 | ||
|
|
30856325be | ||
|
|
a5ab34b707 | ||
|
|
90ee139265 | ||
|
|
1e298edbdd | ||
|
|
925afb70c3 | ||
|
|
c399b850c5 | ||
|
|
8cf03e3ee3 | ||
|
|
e6ba1fc61b | ||
|
|
a2a434d6fd | ||
|
|
fe00182efd | ||
|
|
b00fcc25ea | ||
|
|
e9624ab6d6 | ||
|
|
c2d129aaa6 | ||
|
|
6b3b7d6945 | ||
|
|
1889b840b1 | ||
|
|
bfb1a4ef23 | ||
|
|
f178f31248 | ||
|
|
9c13832307 | ||
|
|
1c3f87165e | ||
|
|
c6ce339d40 | ||
|
|
5a90b00e19 | ||
|
|
e6bf8b5321 | ||
|
|
156e493a90 | ||
|
|
2cf073495c | ||
|
|
43b193e965 | ||
|
|
b4b8dfb217 | ||
|
|
99051af886 | ||
|
|
768926fec3 | ||
|
|
a73042abc1 | ||
|
|
da36e3c1fa | ||
|
|
0024e3e74d | ||
|
|
9b14caf300 | ||
|
|
adee153190 | ||
|
|
c476cd7f25 | ||
|
|
d4da6b02a8 | ||
|
|
1d3f651846 | ||
|
|
d6af0ffc95 | ||
|
|
c1ba96d395 | ||
|
|
52f53e3410 | ||
|
|
aba4875cf3 | ||
|
|
f5057c2ac7 | ||
|
|
cfd5558765 | ||
|
|
77bbeb6de0 | ||
|
|
bf3e22bf4c | ||
|
|
a5596ac8f6 | ||
|
|
a3dddfa7f8 | ||
|
|
922abe8ba3 | ||
|
|
9b85f8673c | ||
|
|
b8e0bf92c2 | ||
|
|
05c7adbfee | ||
|
|
4081802dc8 | ||
|
|
45fb1cd801 | ||
|
|
50ed4a6988 | ||
|
|
96997e95a0 | ||
|
|
9029a64a19 | ||
|
|
cb6c9dd374 | ||
|
|
5b1e9d3f16 | ||
|
|
ceb1f954ff | ||
|
|
f67e4f953f | ||
|
|
76c071da14 | ||
|
|
c8dafae31d | ||
|
|
1924056c02 | ||
|
|
257dd22345 | ||
|
|
4211259874 | ||
|
|
9fa7d0182d | ||
|
|
8a00736c8f | ||
|
|
f1fd6b6d8b | ||
|
|
b1adad5866 | ||
|
|
f8aaa21b39 | ||
|
|
6b207e29fc | ||
|
|
4effb7cfdd | ||
|
|
83f48ac009 | ||
|
|
6788612ab5 | ||
|
|
8329c38894 | ||
|
|
5e96f69c52 | ||
|
|
f4c6b4f08d | ||
|
|
95fef77042 | ||
|
|
9814f44ead | ||
|
|
13189c6c6c | ||
|
|
aed16dfec6 | ||
|
|
3167399da9 | ||
|
|
c6b77fe861 | ||
|
|
aa1e4ecb7d | ||
|
|
1b677770b6 | ||
|
|
c707f20b3f | ||
|
|
c368e065b6 | ||
|
|
90eab0573f | ||
|
|
35d7286eec | ||
|
|
b68fe58a23 | ||
|
|
ea133a96cd | ||
|
|
69e48c77a9 | ||
|
|
606fb38ae6 | ||
|
|
b29955d191 | ||
|
|
7539fb3699 | ||
|
|
2d8911947a | ||
|
|
2044042973 | ||
|
|
dd02f890c2 | ||
|
|
45ca2eaaca | ||
|
|
aaf535c33f | ||
|
|
e9c6da2c11 | ||
|
|
e2c8efe29f | ||
|
|
e76b789eb7 | ||
|
|
75d1431e50 | ||
|
|
8a9da8a3ae | ||
|
|
3b718b0461 | ||
|
|
65b0d1fc23 | ||
|
|
c56ed37f7a | ||
|
|
340754d062 | ||
|
|
db85c34e61 | ||
|
|
807995fe8b | ||
|
|
111120edaa | ||
|
|
0bac8d6ae3 | ||
|
|
2ba17d8d5b | ||
|
|
a61633194d | ||
|
|
caa86bb931 | ||
|
|
cfe08bc542 | ||
|
|
4e55742219 | ||
|
|
f98ed62045 | ||
|
|
03653fb653 | ||
|
|
240a89da2c | ||
|
|
cfacd05578 | ||
|
|
c0ab5f955d | ||
|
|
f2346c5709 | ||
|
|
798bfc964c | ||
|
|
2af9014962 | ||
|
|
f8759278bc | ||
|
|
abed1b0645 | ||
|
|
8999fc8fd6 | ||
|
|
a1f9db4114 | ||
|
|
2336f1dc79 | ||
|
|
335e177578 | ||
|
|
a4434b16de | ||
|
|
9b3624e818 | ||
|
|
120a95f94d | ||
|
|
db0a658be2 | ||
|
|
822a8afcb1 | ||
|
|
eed371130f | ||
|
|
dd19c1040c | ||
|
|
54130e5ee7 | ||
|
|
827128d048 | ||
|
|
26c18562c4 | ||
|
|
0a847c8427 | ||
|
|
27a976fc53 | ||
|
|
73a3a881ca | ||
|
|
f07545285b | ||
|
|
4d02883a48 | ||
|
|
4eb9f0a0a4 | ||
|
|
1f630181d7 | ||
|
|
71a9b79527 | ||
|
|
b32d098d3b | ||
|
|
9118c1d64f | ||
|
|
8e4f7b0f08 | ||
|
|
3acc0592b4 | ||
|
|
dc5e24201c | ||
|
|
eda8f9ac86 | ||
|
|
ed19c9c534 | ||
|
|
c0ee0195e9 | ||
|
|
ffa35bed94 | ||
|
|
9442be13f1 | ||
|
|
a017803429 | ||
|
|
951e88f1c8 | ||
|
|
de93247c5c | ||
|
|
06038bc105 | ||
|
|
43c5975524 | ||
|
|
891f183f80 | ||
|
|
c126c28fa3 | ||
|
|
fc99e46e0f | ||
|
|
9543e10241 | ||
|
|
327bc47017 | ||
|
|
96ccc5d4f5 | ||
|
|
eef2b4eb58 | ||
|
|
26346c8acb | ||
|
|
565e77ef6d | ||
|
|
84506a9340 | ||
|
|
25298012f9 | ||
|
|
236e2f6d48 | ||
|
|
483283fdd1 | ||
|
|
776c2f38f8 | ||
|
|
c20cc09959 | ||
|
|
ce7d3f0324 | ||
|
|
55e85dbd74 | ||
|
|
4c6f6d8b1c | ||
|
|
651381c9d7 | ||
|
|
146af5cf2d | ||
|
|
49a7c80423 | ||
|
|
e770eb147a | ||
|
|
a08802df0a | ||
|
|
61eba87de6 | ||
|
|
0e0a56ac38 | ||
|
|
36e6c2fa25 | ||
|
|
0c157eee69 | ||
|
|
ba2ac37f6c | ||
|
|
9a29db8c62 | ||
|
|
212ec834c8 | ||
|
|
bd70d80f81 | ||
|
|
55e2e3463d | ||
|
|
2e16eba739 | ||
|
|
35bf66ccf4 | ||
|
|
ec4679d85c | ||
|
|
15c4b0e5eb | ||
|
|
5f170f0953 | ||
|
|
07a1e9311b | ||
|
|
7d1274af4b | ||
|
|
9d096aed5d | ||
|
|
8477ad810a | ||
|
|
60e3fb6f45 | ||
|
|
7efb9ec1de | ||
|
|
70c0a4b9e6 | ||
|
|
d9b3474846 | ||
|
|
97cb7fc2eb | ||
|
|
6394612630 | ||
|
|
a78df50826 | ||
|
|
59c1948e14 | ||
|
|
e92fa3d615 | ||
|
|
faee5d0276 | ||
|
|
f2b1e7becc | ||
|
|
5352d55589 | ||
|
|
75386e55af | ||
|
|
fe2a28d013 | ||
|
|
aa2e07d163 | ||
|
|
23c1c41415 | ||
|
|
8be6988e5b | ||
|
|
262ccc2f11 | ||
|
|
09c3952a0a | ||
|
|
ea9c4df4bc | ||
|
|
43c95c24fe | ||
|
|
21a19dcf89 | ||
|
|
2b6cc3e52d | ||
|
|
f639704d6d | ||
|
|
b93995081e | ||
|
|
0dc68b830c | ||
|
|
5521b90aec | ||
|
|
7f0a13b434 | ||
|
|
c0e2445439 | ||
|
|
6037b87b52 | ||
|
|
b80c5d43e9 | ||
|
|
ed258e624d | ||
|
|
e1fd87b251 | ||
|
|
092cf6be4f | ||
|
|
a4286ea2de | ||
|
|
7ada2de54c | ||
|
|
0f01f513eb | ||
|
|
4bebcec778 | ||
|
|
6d2bf8402b | ||
|
|
674f99d738 | ||
|
|
f12c2d3a7c | ||
|
|
8748b1e122 | ||
|
|
b6e4206772 | ||
|
|
2c6224d45e | ||
|
|
a0c764d87c |
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
|
||||
@@ -5,23 +5,21 @@
|
||||
This is a set of guidelines for contributing to Radzen.Blazor.
|
||||
|
||||
## Asking questions
|
||||
|
||||
Please don't open an issue to ask a question about using Radzen.Blazor components. You can check the following resources instead:
|
||||
|
||||
- [Online demos](https://blazor.radzen.com)
|
||||
|
||||
### [Online demos](https://blazor.radzen.com)
|
||||
A showcase application that demonstrates all Radzen.Blazor components. You will find various use cases that demonstrate the component features and API. The source
|
||||
of the demos is available [here](https://github.com/radzenhq/radzen-blazor/tree/master/RadzenBlazorDemos).
|
||||
- [Documentation](https://www.radzen.com/documentation/blazor/accordion/)
|
||||
|
||||
### [Documentation](https://blazor.radzen.com/docs/)
|
||||
Technical documentation and API reference.
|
||||
- [Online forum](https://forum.radzen.com)
|
||||
|
||||
### [Community forum](https://forum.radzen.com)
|
||||
You can ask your question here. Please use the [Radzen.Blazor Components](https://forum.radzen.com/c/blazor-components/10) category.
|
||||
|
||||
- Dedicated technical support
|
||||
### 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?
|
||||
|
||||
@@ -67,7 +65,8 @@ Explain the enhancement and include additional details:
|
||||
If you want to contribute a new feature of fix a bug you can open a pull request.
|
||||
|
||||
Make sure you follow this procedure:
|
||||
|
||||
* **Important!!!** if you itent to make a lot of changes in a pull request open an issue to discuss this with us first. The Radzen Blazor Components have a lot of
|
||||
moving parts and making big changes should be done with extra precautions.
|
||||
* **Be sure that none of the existing tests** breaks after your changes. The test project is available [here](https://github.com/radzenhq/radzen-blazor/tree/master/Radzen.Blazor.Tests).
|
||||
* **If possible add new tests that verify your fix or new feature**.
|
||||
* **Follow the existing coding style** (to be described in detail later).
|
||||
|
||||
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-2021 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
|
||||
|
||||
116
README.md
116
README.md
@@ -1,43 +1,118 @@
|
||||
# Radzen Blazor Components
|
||||

|
||||
|
||||
The home of the [Radzen Blazor components](https://blazor.radzen.com)
|
||||
<h1 align="center">
|
||||
Radzen Blazor Components
|
||||
</h1>
|
||||
|
||||
## Commercial support
|
||||
<p align="center">
|
||||
A set of <strong>70+ free and open source</strong> native Blazor UI controls.
|
||||
</p>
|
||||
|
||||
Paid support for the Radzen Blazor Components is available as part of the [Radzen Professional subscription](https://www.radzen.com/pricing/).
|
||||
<div align="center">
|
||||
|
||||
Our flagship product Radzen provides tons of productivity features for Blazor developers:
|
||||
- The first in the industry WYSIWYG Blazor design time canvas
|
||||
[See Online Demos](https://blazor.radzen.com) or [Read the Docs](https://blazor.radzen.com/docs/)
|
||||
|
||||
</div>
|
||||
|
||||
---
|
||||
|
||||
<p align="center">
|
||||
<a href="https://github.com/radzenhq/radzen-blazor/blob/master/LICENSE">
|
||||
<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" />
|
||||
</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">
|
||||
<img alt="Github Contributors" src="https://img.shields.io/github/contributors/radzenhq/radzen-blazor?logo=github&style=for-the-badge" />
|
||||
</a>
|
||||
<a href="https://blazor.radzen.com">
|
||||
<img alt="Radzen Blazor Components - Online Demos" src="https://img.shields.io/badge/demos-online-brightgreen?color=%232694F9&logo=blazor&style=for-the-badge" />
|
||||
</a>
|
||||
<a href="https://blazor.radzen.com/docs">
|
||||
<img alt="Radzen Blazor Components - Documentation" src="https://img.shields.io/badge/docs-online-brightgreen?color=%232694F9&logo=blazor&style=for-the-badge" />
|
||||
</a>
|
||||
</p>
|
||||
|
||||
## 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
|
||||
- Active community forum
|
||||
|
||||
## Get started with the Radzen Blazor Components
|
||||
## Get started with Radzen Blazor Components
|
||||
|
||||
### Install
|
||||
### 1. Install
|
||||
|
||||
Radzen Blazor Components are distributed as the Radzen.Blazor nuget package. 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
|
||||
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
|
||||
|
||||
### Import the namespace
|
||||
### 2. Import the namespace
|
||||
|
||||
Open the `_Imports.razor` file of your Blazor application and add this line `@using Radzen.Blazor`.
|
||||
|
||||
### Include a theme
|
||||
### 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 `<link rel="stylesheet" href="_content/Radzen.Blazor/css/default.css">` or `<link rel="stylesheet" href="_content/Radzen.Blazor/css/default-base.css">` if you either include Bootstrap manually or don't use it at all.
|
||||
Radzen Blazor components come with five free themes: Material, Standard, Default, Dark, Software and Humanistic.
|
||||
|
||||
### Include Radzen.Blazor.js
|
||||
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">
|
||||
```
|
||||
|
||||
Open the `_Host.cshtml` file (server-side Blazor) or `wwwroot/index.html` (client-side Blazor) and include this snippet `<script src="_content/Radzen.Blazor/Radzen.Blazor.js"></script>`
|
||||
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">
|
||||
```
|
||||
|
||||
### Use a component
|
||||
Use any Radzen Blazor component by typing its tag name in a Blazor page e.g.
|
||||
### 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>
|
||||
```
|
||||
@@ -62,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.
|
||||
77
Radzen.Blazor.Tests/BreadCrumbTests.cs
Normal file
77
Radzen.Blazor.Tests/BreadCrumbTests.cs
Normal file
@@ -0,0 +1,77 @@
|
||||
using Bunit;
|
||||
using Xunit;
|
||||
|
||||
namespace Radzen.Blazor.Tests
|
||||
{
|
||||
public class BreadCrumbTests
|
||||
{
|
||||
[Fact]
|
||||
public void BreadCrumb_Renders_Items()
|
||||
{
|
||||
using var ctx = new TestContext();
|
||||
|
||||
var component = ctx.RenderComponent<RadzenBreadCrumb>();
|
||||
|
||||
component.SetParametersAndRender(parameters =>
|
||||
{
|
||||
parameters.Add(c => c.ChildContent, builder =>
|
||||
{
|
||||
builder.OpenComponent<RadzenBreadCrumbItem>(0);
|
||||
builder.AddAttribute(1, nameof(RadzenBreadCrumbItem.Text), "Test");
|
||||
builder.CloseComponent();
|
||||
});
|
||||
});
|
||||
//@"<RadzenBreadCrumbItem Text=""Test"" />"
|
||||
Assert.Contains(@"class=""rz-breadcrumb-item", component.Markup);
|
||||
Assert.Contains(">Test</", component.Markup);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void BreadCrumb_Renders_Icon()
|
||||
{
|
||||
using var ctx = new TestContext();
|
||||
|
||||
var component = ctx.RenderComponent<RadzenBreadCrumb>();
|
||||
|
||||
component.SetParametersAndRender(parameters =>
|
||||
{
|
||||
parameters.Add(c => c.ChildContent, builder =>
|
||||
{
|
||||
builder.OpenComponent<RadzenBreadCrumbItem>(0);
|
||||
builder.AddAttribute(1, nameof(RadzenBreadCrumbItem.Text), "Test");
|
||||
builder.AddAttribute(2, nameof(RadzenBreadCrumbItem.Icon), "add");
|
||||
builder.CloseComponent();
|
||||
});
|
||||
});
|
||||
|
||||
//@"<RadzenBreadCrumbItem Text=""Test"" />"
|
||||
Assert.Contains("<i", component.Markup);
|
||||
Assert.Contains(">add</i>", component.Markup);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void BreadCrumb_Renders_Link()
|
||||
{
|
||||
using var ctx = new TestContext();
|
||||
|
||||
var component = ctx.RenderComponent<RadzenBreadCrumb>();
|
||||
|
||||
component.SetParametersAndRender(parameters =>
|
||||
{
|
||||
parameters.Add(c => c.ChildContent, builder =>
|
||||
{
|
||||
builder.OpenComponent<RadzenBreadCrumbItem>(0);
|
||||
builder.AddAttribute(1, nameof(RadzenBreadCrumbItem.Text), "Test");
|
||||
builder.AddAttribute(2, nameof(RadzenBreadCrumbItem.Icon), "add");
|
||||
builder.AddAttribute(3, nameof(RadzenBreadCrumbItem.Path), "/badge");
|
||||
builder.CloseComponent();
|
||||
});
|
||||
});
|
||||
|
||||
//@"<RadzenBreadCrumbItem Text=""Test"" />"
|
||||
Assert.Contains("<i", component.Markup);
|
||||
Assert.Contains(">add</i>", component.Markup);
|
||||
Assert.Contains("<a href=\"/badge", component.Markup);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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]
|
||||
|
||||
44
Radzen.Blazor.Tests/ChartTests.cs
Normal file
44
Radzen.Blazor.Tests/ChartTests.cs
Normal file
@@ -0,0 +1,44 @@
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Bunit;
|
||||
using Radzen.Blazor.Rendering;
|
||||
using Xunit;
|
||||
|
||||
namespace Radzen.Blazor.Tests;
|
||||
|
||||
public class ChartTests
|
||||
{
|
||||
[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}";
|
||||
})));
|
||||
|
||||
foreach (var _ in Enumerable.Range(0, 10))
|
||||
{
|
||||
await chart.InvokeAsync(() => chart.Instance.MouseMove(100, 100));
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -110,7 +110,7 @@ namespace Radzen.Blazor.Tests
|
||||
|
||||
component.SetParametersAndRender(parameters => parameters.Add(p => p.Change, args => { raised = true; }));
|
||||
|
||||
component.Find("div").MouseUp();
|
||||
component.Find("div.rz-chkbox-box").Click();
|
||||
|
||||
Assert.True(raised);
|
||||
}
|
||||
@@ -126,7 +126,7 @@ namespace Radzen.Blazor.Tests
|
||||
|
||||
component.SetParametersAndRender(parameters => parameters.Add(p => p.ValueChanged, args => { raised = true; }));
|
||||
|
||||
component.Find("div").MouseUp();
|
||||
component.Find("div.rz-chkbox-box").Click();
|
||||
|
||||
Assert.True(raised);
|
||||
}
|
||||
@@ -141,21 +141,21 @@ namespace Radzen.Blazor.Tests
|
||||
component.SetParametersAndRender(parameters => parameters.Add<bool>(p => p.TriState, true));
|
||||
|
||||
|
||||
component.Find("div").MouseUp();
|
||||
component.Find("div.rz-chkbox-box").Click();
|
||||
|
||||
component.Render();
|
||||
|
||||
Assert.Contains(@$"rz-state-active", component.Markup);
|
||||
Assert.Contains(@$"rzi-check", component.Markup);
|
||||
|
||||
component.Find("div").MouseUp();
|
||||
component.Find("div.rz-chkbox-box").Click();
|
||||
|
||||
component.Render();
|
||||
|
||||
Assert.DoesNotContain(@$"rz-state-active", component.Markup);
|
||||
Assert.DoesNotContain(@$"rzi-check", component.Markup);
|
||||
|
||||
component.Find("div").MouseUp();
|
||||
component.Find("div.rz-chkbox-box").Click();
|
||||
|
||||
Assert.Contains(@$"rz-state-active", component.Markup);
|
||||
Assert.Contains(@$"rzi-times", 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"));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,98 +0,0 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using Xunit;
|
||||
|
||||
namespace Radzen.Blazor.Tests
|
||||
{
|
||||
public class DataGridColumnTests
|
||||
{
|
||||
class TestModel
|
||||
{
|
||||
public Guid Id { get; set; }
|
||||
public string Name { get; set; }
|
||||
public int Age { get; set; }
|
||||
}
|
||||
class Testable : RadzenDataGridColumn<TestModel>
|
||||
{
|
||||
public Testable()
|
||||
{
|
||||
Grid = new RadzenDataGrid<TestModel>();
|
||||
}
|
||||
public void PublicMorozov_OnInitialized()
|
||||
{
|
||||
OnInitialized();
|
||||
}
|
||||
public Type PublicMorozov_FilterPropertyType()
|
||||
{
|
||||
var propertyInfo = this.GetType()
|
||||
.GetProperties(System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance)
|
||||
.FirstOrDefault(x => x.Name == "FilterPropertyType");
|
||||
|
||||
return propertyInfo?.GetValue(this) as Type;
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void FilterPropertyType_Assigned_From_Type_Parameter()
|
||||
{
|
||||
var column = new Testable()
|
||||
{
|
||||
Property = nameof(TestModel.Id),
|
||||
Type = typeof(string),
|
||||
FilterProperty = null
|
||||
};
|
||||
|
||||
column.PublicMorozov_OnInitialized();
|
||||
|
||||
Assert.Equal(typeof(string), column.PublicMorozov_FilterPropertyType());
|
||||
Assert.Equal(FilterOperator.Contains, column.FilterOperator);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void FilterPropertyType_Assigned_From_FilterProperty_Parameter()
|
||||
{
|
||||
var column = new Testable()
|
||||
{
|
||||
Property = nameof(TestModel.Id),
|
||||
Type = null,
|
||||
FilterProperty = nameof(TestModel.Name)
|
||||
};
|
||||
|
||||
column.PublicMorozov_OnInitialized();
|
||||
|
||||
Assert.Equal(typeof(string), column.PublicMorozov_FilterPropertyType());
|
||||
Assert.Equal(FilterOperator.Contains, column.FilterOperator);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void FilterPropertyType_Assigned_From_ColumnType()
|
||||
{
|
||||
var column = new Testable()
|
||||
{
|
||||
Property = nameof(TestModel.Id),
|
||||
Type = null,
|
||||
FilterProperty = null
|
||||
};
|
||||
|
||||
column.PublicMorozov_OnInitialized();
|
||||
|
||||
Assert.Equal(typeof(Guid), column.PublicMorozov_FilterPropertyType());
|
||||
Assert.Equal(FilterOperator.Equals, column.FilterOperator);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void FilterPropertyType_Assigned_From_Type_If_FilterProperty_Is_Fake_Field()
|
||||
{
|
||||
var column = new Testable()
|
||||
{
|
||||
Property = nameof(TestModel.Id),
|
||||
Type = typeof(decimal),
|
||||
FilterProperty = "NotExistsField"
|
||||
};
|
||||
|
||||
column.PublicMorozov_OnInitialized();
|
||||
|
||||
Assert.Equal(typeof(decimal), column.PublicMorozov_FilterPropertyType());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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,8 @@ namespace Radzen.Blazor.Tests
|
||||
});
|
||||
});
|
||||
|
||||
var markup = new Regex(@"\s\s+").Replace(component.Markup, "").Trim();
|
||||
|
||||
Assert.Contains(@$"<span class=""rz-column-title"">MyId</span>", markup);
|
||||
var title = component.Find(".rz-column-title");
|
||||
Assert.Equal("MyId", title.TextContent.Trim());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
using Bunit;
|
||||
using Radzen.Blazor.Rendering;
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using Xunit;
|
||||
|
||||
@@ -50,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);
|
||||
});
|
||||
@@ -94,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);
|
||||
@@ -147,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);
|
||||
@@ -231,7 +230,7 @@ namespace Radzen.Blazor.Tests
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void DatePicker_Raises_ChangeEventOnNextMonth()
|
||||
public void DatePicker_NotRaises_ChangeEventOnNextMonth()
|
||||
{
|
||||
using var ctx = new TestContext();
|
||||
ctx.JSInterop.Mode = JSRuntimeMode.Loose;
|
||||
@@ -248,12 +247,11 @@ namespace Radzen.Blazor.Tests
|
||||
|
||||
component.Find(".rz-datepicker-next-icon").Click();
|
||||
|
||||
Assert.True(raised);
|
||||
Assert.True(((DateTime)newValue) > DateTime.Now);
|
||||
Assert.False(raised);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void DatePicker_Raises_ValueChangedEventOnNextMonth()
|
||||
public void DatePicker_NotRaises_ValueChangedEventOnNextMonth()
|
||||
{
|
||||
using var ctx = new TestContext();
|
||||
ctx.JSInterop.Mode = JSRuntimeMode.Loose;
|
||||
@@ -270,12 +268,11 @@ namespace Radzen.Blazor.Tests
|
||||
|
||||
component.Find(".rz-datepicker-next-icon").Click();
|
||||
|
||||
Assert.True(raised);
|
||||
Assert.True(((DateTime)newValue) > DateTime.Now);
|
||||
Assert.False(raised);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void DatePicker_Raises_ChangeEventOnPrevMonth()
|
||||
public void DatePicker_NotRaises_ChangeEventOnPrevMonth()
|
||||
{
|
||||
using var ctx = new TestContext();
|
||||
ctx.JSInterop.Mode = JSRuntimeMode.Loose;
|
||||
@@ -292,12 +289,11 @@ namespace Radzen.Blazor.Tests
|
||||
|
||||
component.Find(".rz-datepicker-prev-icon").Click();
|
||||
|
||||
Assert.True(raised);
|
||||
Assert.True(((DateTime)newValue) < DateTime.Now);
|
||||
Assert.False(raised);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void DatePicker_Raises_ValueChangedEventOnPrevMonth()
|
||||
public void DatePicker_NotRaises_ValueChangedEventOnPrevMonth()
|
||||
{
|
||||
using var ctx = new TestContext();
|
||||
ctx.JSInterop.Mode = JSRuntimeMode.Loose;
|
||||
@@ -314,8 +310,7 @@ namespace Radzen.Blazor.Tests
|
||||
|
||||
component.Find(".rz-datepicker-prev-icon").Click();
|
||||
|
||||
Assert.True(raised);
|
||||
Assert.True(((DateTime)newValue) < DateTime.Now);
|
||||
Assert.False(raised);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
@@ -325,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; })
|
||||
@@ -383,7 +378,45 @@ namespace Radzen.Blazor.Tests
|
||||
Assert.True(raised);
|
||||
Assert.Null(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);
|
||||
});
|
||||
|
||||
Assert.Contains(DateTime.MaxValue.ToString(component.Instance.DateFormat), component.Markup);
|
||||
|
||||
var exception = Record.Exception(() => component.Find(".rz-datepicker-next-icon")
|
||||
.Click());
|
||||
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)]
|
||||
@@ -414,5 +447,63 @@ namespace Radzen.Blazor.Tests
|
||||
Assert.True(raised);
|
||||
Assert.Equal(kind, ((DateTime)newValue).Kind);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void DatePicker_Renders_FooterTemplate()
|
||||
{
|
||||
using var ctx = new TestContext();
|
||||
ctx.JSInterop.Mode = JSRuntimeMode.Loose;
|
||||
ctx.JSInterop.SetupModule("_content/Radzen.Blazor/Radzen.Blazor.js");
|
||||
|
||||
string actionsTemplate = "<input type=\"button\" value=\"Test\" />";
|
||||
|
||||
var component = ctx.RenderComponent<RadzenDatePicker<DateTime>>(parameters =>
|
||||
{
|
||||
parameters.Add(p => p.Value, DateTime.MinValue);
|
||||
parameters.Add(p => p.FooterTemplate, actionsTemplate);
|
||||
});
|
||||
|
||||
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));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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(@$"<i class=""rzi""", component.Markup);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
@@ -45,5 +45,29 @@ namespace Radzen.Blazor.Tests
|
||||
|
||||
Assert.Contains(@$"autofocus", component.Markup);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Icon_Renders_IconStyleClass()
|
||||
{
|
||||
using var ctx = new TestContext();
|
||||
|
||||
var component = ctx.RenderComponent<RadzenIcon>();
|
||||
|
||||
component.SetParametersAndRender(parameters => parameters.Add(icon => icon.IconStyle, IconStyle.Primary));
|
||||
|
||||
Assert.Contains(@$"rzi-primary", component.Markup);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Icon_NotRenders_IconStyleClass_WhenNull()
|
||||
{
|
||||
using var ctx = new TestContext();
|
||||
|
||||
var component = ctx.RenderComponent<RadzenIcon>();
|
||||
|
||||
component.SetParametersAndRender(parameters => parameters.Add(icon => icon.IconStyle, null));
|
||||
|
||||
Assert.DoesNotContain(@$"rzi-primary", 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);
|
||||
}
|
||||
@@ -216,7 +221,7 @@ namespace Radzen.Blazor.Tests
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Login_NotRaises_ResetPasswordEvent_WhenEmptyUsername()
|
||||
public void Login_Raises_ResetPasswordEvent_WhenEmptyUsername()
|
||||
{
|
||||
using var ctx = new TestContext();
|
||||
|
||||
@@ -231,7 +236,7 @@ namespace Radzen.Blazor.Tests
|
||||
|
||||
component.Find("a").Click();
|
||||
|
||||
Assert.True(!clicked);
|
||||
Assert.True(clicked);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
139
Radzen.Blazor.Tests/NumericRangeValidatorTests.cs
Normal file
139
Radzen.Blazor.Tests/NumericRangeValidatorTests.cs
Normal file
@@ -0,0 +1,139 @@
|
||||
using System;
|
||||
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 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_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));
|
||||
}
|
||||
}
|
||||
}
|
||||
98
Radzen.Blazor.Tests/PanelMenuTests.cs
Normal file
98
Radzen.Blazor.Tests/PanelMenuTests.cs
Normal file
@@ -0,0 +1,98 @@
|
||||
using Bunit;
|
||||
using Bunit.TestDoubles;
|
||||
using Microsoft.AspNetCore.Components;
|
||||
using Microsoft.AspNetCore.Components.Routing;
|
||||
using Microsoft.Extensions.DependencyInjection.Extensions;
|
||||
using Xunit;
|
||||
|
||||
namespace Radzen.Blazor.Tests
|
||||
{
|
||||
public class PanelMenuTests
|
||||
{
|
||||
class TestNavigationManager : NavigationManager
|
||||
{
|
||||
public TestNavigationManager(string uri)
|
||||
{
|
||||
Initialize("http://www.example.com/", uri);
|
||||
}
|
||||
|
||||
protected override void NavigateToCore(string uri, bool forceLoad)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
private static string CreatePanelMenu(string currentAbsoluteUrl, NavLinkMatch match, params string[] urls)
|
||||
{
|
||||
using var ctx = new TestContext();
|
||||
|
||||
ctx.Services.RemoveAll<NavigationManager>();
|
||||
ctx.Services.TryAddSingleton<NavigationManager>(new TestNavigationManager(currentAbsoluteUrl));
|
||||
|
||||
var component = ctx.RenderComponent<RadzenPanelMenu>();
|
||||
|
||||
component.SetParametersAndRender(parameters => parameters.Add(p => p.Match, match).AddChildContent(builder =>
|
||||
{
|
||||
foreach (var url in urls)
|
||||
{
|
||||
builder.OpenComponent<RadzenPanelMenuItem>(0);
|
||||
builder.AddAttribute(1, nameof(RadzenPanelMenuItem.Path), url);
|
||||
builder.CloseComponent();
|
||||
}
|
||||
}));
|
||||
|
||||
return component.Markup;
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void RadzenPanelMenu_SetsOneActiveMenuItem()
|
||||
{
|
||||
var component = CreatePanelMenu("http://www.example.com/datagrid-dynamic", NavLinkMatch.All, "/datagrid", "/datagrid-dynamic");
|
||||
|
||||
var firstIndex = component.IndexOf("rz-navigation-item-wrapper-active");
|
||||
var lastIndex = component.LastIndexOf("rz-navigation-item-wrapper-active");
|
||||
|
||||
Assert.NotEqual(-1, firstIndex);
|
||||
Assert.Equal(firstIndex, lastIndex);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void RadzenPanelMenu_MatchesQueryStringParameters()
|
||||
{
|
||||
var component = CreatePanelMenu("http://www.example.com/foo?bar", NavLinkMatch.Prefix, "/foo");
|
||||
|
||||
Assert.Contains("rz-navigation-item-wrapper-active", component);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void RadzenPanelMenu_DoesNotMatchQueryStringParametersWhenExactMatchIsSpecified()
|
||||
{
|
||||
var component = CreatePanelMenu("http://www.example.com/foo?bar", NavLinkMatch.All, "/foo");
|
||||
|
||||
Assert.DoesNotContain("rz-navigation-item-wrapper-active", component);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void RadzenPanelMenu_DoesNotMatchRootWithEverything()
|
||||
{
|
||||
var component = CreatePanelMenu("http://www.example.com/foo", NavLinkMatch.Prefix, "/");
|
||||
|
||||
Assert.DoesNotContain("rz-navigation-item-wrapper-active", component);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void RadzenPanelMenu_MatchesRoot()
|
||||
{
|
||||
var component = CreatePanelMenu("http://www.example.com/", NavLinkMatch.Prefix, "/");
|
||||
|
||||
Assert.Contains("rz-navigation-item-wrapper-active", component);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void RadzenPanelMenu_MatchesRootWithoutTrailingSlash()
|
||||
{
|
||||
var component = CreatePanelMenu("http://www.example.com", NavLinkMatch.Prefix, "/");
|
||||
|
||||
Assert.Contains("rz-navigation-item-wrapper-active", component);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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-determinate-success", component.Markup);
|
||||
|
||||
component.SetParametersAndRender(parameters => parameters.Add(p => p.ProgressBarStyle, ProgressBarStyle.Info));
|
||||
Assert.Contains(@$"rz-progressbar-determinate-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-indeterminate-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-indeterminate-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>net5.0</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);
|
||||
}
|
||||
}
|
||||
@@ -38,8 +38,8 @@ namespace Radzen.Blazor.Tests
|
||||
|
||||
component.SetParametersAndRender(parameters => parameters.Add<int>(p => p.Value, value));
|
||||
|
||||
Assert.Contains(@$"style=""width: {(value / max * 100).ToInvariantString()}%;""", component.Markup);
|
||||
Assert.Contains(@$"style=""left: {(value / max * 100).ToInvariantString()}%;""", component.Markup);
|
||||
Assert.Contains(@$"style=""width: {Math.Round((value / max * 100)).ToInvariantString()}%;""", component.Markup);
|
||||
Assert.Contains(@$"style=""left: {Math.Round((value / max * 100)).ToInvariantString()}%;""", component.Markup);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
@@ -55,9 +55,9 @@ namespace Radzen.Blazor.Tests
|
||||
parameters.Add<IEnumerable<int>>(p => p.Value, new int[] { 4, 30 });
|
||||
});
|
||||
|
||||
Assert.Contains(@$"left: 4.00%", component.Markup);
|
||||
Assert.Contains(@$"left: 30.0%", component.Markup);
|
||||
Assert.Contains(@$"left: 4.00%; width: 26.00%;", component.Markup);
|
||||
Assert.Contains(@$"left: 4%", component.Markup);
|
||||
Assert.Contains(@$"left: 30%", component.Markup);
|
||||
Assert.Contains(@$"left: 4%; width: 26%;", component.Markup);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
||||
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>();
|
||||
|
||||
|
||||
@@ -110,7 +110,7 @@ namespace Radzen.Blazor.Tests
|
||||
|
||||
component.SetParametersAndRender(parameters => parameters.Add(p => p.Change, args => { raised = true; newValue = args; }));
|
||||
|
||||
component.Find("div").MouseUp();
|
||||
component.Find("div").Click();
|
||||
|
||||
Assert.True(raised);
|
||||
Assert.True(object.Equals(value, !(bool)newValue));
|
||||
@@ -129,7 +129,7 @@ namespace Radzen.Blazor.Tests
|
||||
|
||||
component.SetParametersAndRender(parameters => parameters.Add(p => p.ValueChanged, args => { raised = true; newValue = args; }));
|
||||
|
||||
component.Find("div").MouseUp();
|
||||
component.Find("div").Click();
|
||||
|
||||
Assert.True(raised);
|
||||
Assert.True(object.Equals(value, !(bool)newValue));
|
||||
|
||||
@@ -1,12 +0,0 @@
|
||||
{
|
||||
"version": 1,
|
||||
"isRoot": true,
|
||||
"tools": {
|
||||
"excubo.webcompiler": {
|
||||
"version": "2.6.0",
|
||||
"commands": [
|
||||
"webcompiler"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
{
|
||||
@@ -18,7 +20,7 @@ namespace Radzen.Blazor
|
||||
/// 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 (IsNumeric(CategoryProperty))
|
||||
{
|
||||
@@ -122,6 +124,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>
|
||||
@@ -130,11 +144,22 @@ namespace Radzen.Blazor
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether this <see cref="CartesianSeries{TItem}"/> is visible.
|
||||
/// Invisible series do not appear in the legend and cannot be shown by the user.
|
||||
/// Use the <c>Visible</c> property to programatically show or hide a series.
|
||||
/// </summary>
|
||||
/// <value><c>true</c> if visible; otherwise, <c>false</c>.</value>
|
||||
[Parameter]
|
||||
public bool Visible { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether this <see cref="CartesianSeries{TItem}"/> is hidden.
|
||||
/// Hidden series are initially invisible and the user can show them by clicking on their label in the legend.
|
||||
/// Use the <c>Hidden</c> property to hide certain series from your users but still allow them to see them.
|
||||
/// </summary>
|
||||
/// <value><c>true</c> if hidden; otherwise, <c>false</c>.</value>
|
||||
[Parameter]
|
||||
public bool Hidden { get; set; }
|
||||
|
||||
bool IsVisible { get; set; } = true;
|
||||
|
||||
bool IChartSeries.Visible
|
||||
@@ -163,7 +188,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
|
||||
{
|
||||
@@ -217,6 +242,16 @@ namespace Radzen.Blazor
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the category values
|
||||
/// </summary>
|
||||
protected virtual IList<object> GetCategories()
|
||||
{
|
||||
Func<TItem, object> category = String.IsNullOrEmpty(CategoryProperty) ? (item) => string.Empty : PropertyAccess.Getter<TItem, object>(CategoryProperty);
|
||||
|
||||
return Items.Select(category).ToList();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public virtual ScaleBase TransformCategoryScale(ScaleBase scale)
|
||||
{
|
||||
@@ -244,9 +279,7 @@ namespace Radzen.Blazor
|
||||
};
|
||||
}
|
||||
|
||||
Func<TItem, object> category = String.IsNullOrEmpty(CategoryProperty) ? (item) => string.Empty : PropertyAccess.Getter<TItem, object>(CategoryProperty);
|
||||
|
||||
var data = Items.Select(category).ToList();
|
||||
var data = GetCategories();
|
||||
|
||||
if (scale is OrdinalScale ordinal)
|
||||
{
|
||||
@@ -292,6 +325,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; }
|
||||
|
||||
@@ -300,9 +350,16 @@ namespace Radzen.Blazor
|
||||
{
|
||||
var shouldRefresh = parameters.DidParameterChange(nameof(Data), Data);
|
||||
var visibleChanged = parameters.DidParameterChange(nameof(Visible), Visible);
|
||||
var hiddenChanged = parameters.DidParameterChange(nameof(Hidden), Hidden);
|
||||
|
||||
await base.SetParametersAsync(parameters);
|
||||
|
||||
if (hiddenChanged)
|
||||
{
|
||||
IsVisible = !Hidden;
|
||||
shouldRefresh = true;
|
||||
}
|
||||
|
||||
if (visibleChanged)
|
||||
{
|
||||
IsVisible = Visible;
|
||||
@@ -410,10 +467,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));
|
||||
@@ -482,9 +536,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();
|
||||
}
|
||||
|
||||
@@ -527,7 +653,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);
|
||||
@@ -537,7 +663,7 @@ 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);
|
||||
}
|
||||
@@ -545,18 +671,34 @@ namespace Radzen.Blazor
|
||||
/// <inheritdoc />
|
||||
public virtual object DataAt(double x, double y)
|
||||
{
|
||||
var first = Items.FirstOrDefault();
|
||||
var last = Items.LastOrDefault();
|
||||
if (Items.Any())
|
||||
{
|
||||
return 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 null;
|
||||
}
|
||||
|
||||
var startX = Chart.CategoryScale.Scale(category(first), true);
|
||||
var endX = Chart.CategoryScale.Scale(category(last), true);
|
||||
/// <inheritdoc />
|
||||
public virtual 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, Y = TooltipY(d) + offsetY },
|
||||
TextAnchor = "middle",
|
||||
Text = Chart.ValueAxis.Format(Chart.ValueScale, Value(d))
|
||||
});
|
||||
}
|
||||
|
||||
var count = Math.Max(Items.Count() - 1, 1);
|
||||
var index = Convert.ToInt32((x - startX) / ((endX - startX) / count));
|
||||
|
||||
return Items.ElementAtOrDefault(index);
|
||||
return list;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -96,11 +96,8 @@ namespace Radzen
|
||||
}
|
||||
set
|
||||
{
|
||||
if (_form != value && value != null)
|
||||
{
|
||||
_form = value;
|
||||
_form.AddComponent(this);
|
||||
}
|
||||
_form = value;
|
||||
_form?.AddComponent(this);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -150,7 +147,7 @@ namespace Radzen
|
||||
/// Gets a value indicating whether this instance has value.
|
||||
/// </summary>
|
||||
/// <value><c>true</c> if this instance has value; otherwise, <c>false</c>.</value>
|
||||
public bool HasValue
|
||||
public virtual bool HasValue
|
||||
{
|
||||
get
|
||||
{
|
||||
@@ -219,7 +216,7 @@ namespace Radzen
|
||||
/// <summary>
|
||||
/// The search text
|
||||
/// </summary>
|
||||
protected string searchText;
|
||||
internal string searchText;
|
||||
|
||||
/// <summary>
|
||||
/// The view
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using Microsoft.AspNetCore.Components;
|
||||
using Microsoft.JSInterop;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
@@ -36,19 +37,36 @@ namespace Radzen
|
||||
/// </example>
|
||||
public class DialogService : IDisposable
|
||||
{
|
||||
private DotNetObjectReference<DialogService> reference;
|
||||
internal DotNetObjectReference<DialogService> Reference
|
||||
{
|
||||
get
|
||||
{
|
||||
if (reference == null)
|
||||
{
|
||||
reference = DotNetObjectReference.Create(this);
|
||||
}
|
||||
|
||||
return reference;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the URI helper.
|
||||
/// </summary>
|
||||
/// <value>The URI helper.</value>
|
||||
NavigationManager UriHelper { get; set; }
|
||||
IJSRuntime JSRuntime { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="DialogService"/> class.
|
||||
/// </summary>
|
||||
/// <param name="uriHelper">The URI helper.</param>
|
||||
public DialogService(NavigationManager uriHelper)
|
||||
/// <param name="jsRuntime">IJSRuntime instance.</param>
|
||||
public DialogService(NavigationManager uriHelper, IJSRuntime jsRuntime)
|
||||
{
|
||||
UriHelper = uriHelper;
|
||||
JSRuntime = jsRuntime;
|
||||
|
||||
if (UriHelper != null)
|
||||
{
|
||||
@@ -62,6 +80,11 @@ namespace Radzen
|
||||
{
|
||||
Close();
|
||||
}
|
||||
|
||||
if (_sideDialogTask?.Task.IsCompleted == false)
|
||||
{
|
||||
CloseSide();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -79,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>
|
||||
@@ -103,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.
|
||||
@@ -122,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>
|
||||
@@ -171,6 +241,7 @@ namespace Radzen
|
||||
Width = options != null && !string.IsNullOrEmpty(options.Width) ? options.Width : "600px",
|
||||
Left = options != null && !string.IsNullOrEmpty(options.Left) ? options.Left : "",
|
||||
Top = options != null && !string.IsNullOrEmpty(options.Top) ? options.Top : "",
|
||||
Bottom = options != null && !string.IsNullOrEmpty(options.Bottom) ? options.Bottom : "",
|
||||
Height = options != null && !string.IsNullOrEmpty(options.Height) ? options.Height : "",
|
||||
ShowTitle = options != null ? options.ShowTitle : true,
|
||||
ShowClose = options != null ? options.ShowClose : true,
|
||||
@@ -180,6 +251,8 @@ namespace Radzen
|
||||
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 ? options.CssClass : "",
|
||||
});
|
||||
}
|
||||
|
||||
@@ -187,7 +260,8 @@ namespace Radzen
|
||||
/// Closes the last opened dialog with optional result.
|
||||
/// </summary>
|
||||
/// <param name="result">The result.</param>
|
||||
public void Close(dynamic result = null)
|
||||
[JSInvokable("DialogService.Close")]
|
||||
public virtual void Close(dynamic result = null)
|
||||
{
|
||||
var dialog = dialogs.LastOrDefault();
|
||||
|
||||
@@ -208,6 +282,9 @@ namespace Radzen
|
||||
/// <inheritdoc />
|
||||
public void Dispose()
|
||||
{
|
||||
reference?.Dispose();
|
||||
reference = null;
|
||||
|
||||
UriHelper.LocationChanged -= UriHelper_OnLocationChanged;
|
||||
}
|
||||
|
||||
@@ -218,59 +295,114 @@ 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) => 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.CloseElement();
|
||||
|
||||
b.OpenElement(i++, "div");
|
||||
b.AddAttribute(i++, "class", "row");
|
||||
b.OpenElement(i++, "div");
|
||||
b.AddAttribute(i++, "class", "col-md-12");
|
||||
|
||||
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();
|
||||
b.CloseElement();
|
||||
b.CloseElement();
|
||||
};
|
||||
return content;
|
||||
}, new DialogOptions()
|
||||
public async Task<bool?> Confirm(string message = "Confirm?", string title = "Confirm", ConfirmOptions options = null)
|
||||
{
|
||||
Width = options != null ? !string.IsNullOrEmpty(options.Width) ? options.Width : "355px" : "355px",
|
||||
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 : "",
|
||||
});
|
||||
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-confirm {options.CssClass}" : "rz-dialog-confirm",
|
||||
};
|
||||
|
||||
return await OpenAsync(title, ds =>
|
||||
{
|
||||
RenderFragment content = b =>
|
||||
{
|
||||
var i = 0;
|
||||
b.OpenElement(i++, "p");
|
||||
b.AddAttribute(i++, "class", "rz-dialog-confirm-message");
|
||||
b.AddContent(i++, message);
|
||||
b.CloseElement();
|
||||
|
||||
b.OpenElement(i++, "div");
|
||||
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++, "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++, "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 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",
|
||||
};
|
||||
|
||||
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++, 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;
|
||||
}, dialogOptions);
|
||||
}
|
||||
}
|
||||
|
||||
/// <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.
|
||||
@@ -283,7 +415,83 @@ 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>
|
||||
/// 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>
|
||||
@@ -310,21 +518,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>
|
||||
@@ -333,23 +526,29 @@ 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.
|
||||
/// Gets or sets a value indicating whether the dialog should be closed on ESC key press.
|
||||
/// </summary>
|
||||
/// <value><c>true</c> if closeable; otherwise, <c>false</c>.</value>
|
||||
public bool CloseDialogOnOverlayClick { get; set; } = false;
|
||||
public bool CloseDialogOnEsc { get; set; } = true;
|
||||
}
|
||||
|
||||
/// <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>
|
||||
|
||||
@@ -16,7 +16,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,19 +36,28 @@ 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>();
|
||||
var view = (LoadData.HasDelegate ? data : View).Cast<object>().AsQueryable();
|
||||
var totalItemsCount = LoadData.HasDelegate ? Count : view.Count();
|
||||
var top = Math.Min(request.Count, totalItemsCount - request.StartIndex);
|
||||
var top = request.Count;
|
||||
|
||||
if(top <= 0)
|
||||
{
|
||||
top = PageSize;
|
||||
}
|
||||
|
||||
if (LoadData.HasDelegate)
|
||||
{
|
||||
await LoadData.InvokeAsync(new Radzen.LoadDataArgs() { Skip = request.StartIndex, Top = request.Count, Filter = await JSRuntime.InvokeAsync<string>("Radzen.getInputValue", search) });
|
||||
}
|
||||
|
||||
return new Microsoft.AspNetCore.Components.Web.Virtualization.ItemsProviderResult<object>(LoadData.HasDelegate ? Data.Cast<object>() : view.Skip(request.StartIndex).Take(top), 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>
|
||||
@@ -69,13 +84,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>
|
||||
@@ -84,7 +108,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>));
|
||||
@@ -97,6 +121,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();
|
||||
@@ -117,6 +146,26 @@ namespace Radzen
|
||||
});
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override bool HasValue
|
||||
{
|
||||
get
|
||||
{
|
||||
if (typeof(T) == typeof(string))
|
||||
{
|
||||
return !string.IsNullOrEmpty($"{internalValue}");
|
||||
}
|
||||
else if (typeof(IEnumerable).IsAssignableFrom(typeof(T)))
|
||||
{
|
||||
return internalValue != null && ((IEnumerable)internalValue).Cast<object>().Any();
|
||||
}
|
||||
else
|
||||
{
|
||||
return internalValue != null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Renders the item.
|
||||
/// </summary>
|
||||
@@ -127,6 +176,23 @@ namespace Radzen
|
||||
//
|
||||
}
|
||||
|
||||
System.Collections.Generic.HashSet<object> keys = new System.Collections.Generic.HashSet<object>();
|
||||
|
||||
internal object GetKey(object item)
|
||||
{
|
||||
var value = GetItemOrValueFromProperty(item, ValueProperty);
|
||||
|
||||
if (!keys.Contains(value))
|
||||
{
|
||||
keys.Add(value);
|
||||
return value;
|
||||
}
|
||||
else
|
||||
{
|
||||
return item;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether filtering is allowed. Set to <c>false</c> by default.
|
||||
/// </summary>
|
||||
@@ -148,6 +214,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>
|
||||
@@ -162,6 +235,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>
|
||||
@@ -172,7 +252,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>
|
||||
@@ -188,10 +268,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
|
||||
{
|
||||
@@ -201,21 +281,46 @@ namespace Radzen
|
||||
if (!string.IsNullOrEmpty(ValueProperty))
|
||||
{
|
||||
System.Reflection.PropertyInfo pi = PropertyAccess.GetElementType(Data.GetType()).GetProperty(ValueProperty);
|
||||
Value = selectedItems.Select(i => PropertyAccess.GetItemOrValueFromProperty(i, ValueProperty)).AsQueryable().Cast(pi.PropertyType);
|
||||
internalValue = selectedItems.Select(i => GetItemOrValueFromProperty(i, ValueProperty)).AsQueryable().Cast(pi.PropertyType);
|
||||
}
|
||||
else
|
||||
{
|
||||
var type = typeof(T).IsGenericType ? typeof(T).GetGenericArguments()[0] : typeof(T);
|
||||
Value = selectedItems.AsQueryable().Cast(type);
|
||||
internalValue = selectedItems.AsQueryable().Cast(type);
|
||||
}
|
||||
|
||||
await ValueChanged.InvokeAsync((T)Value);
|
||||
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
|
||||
{
|
||||
await ValueChanged.InvokeAsync((T)internalValue);
|
||||
}
|
||||
if (FieldIdentifier.FieldName != null) { EditContext?.NotifyFieldChanged(FieldIdentifier); }
|
||||
await Change.InvokeAsync(Value);
|
||||
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>
|
||||
@@ -236,16 +341,16 @@ namespace Radzen
|
||||
searchText = null;
|
||||
await JSRuntime.InvokeAsync<string>("Radzen.setInputValue", search, "");
|
||||
|
||||
Value = default(T);
|
||||
internalValue = default(T);
|
||||
selectedItem = null;
|
||||
|
||||
selectedItems.Clear();
|
||||
|
||||
selectedIndex = -1;
|
||||
|
||||
await ValueChanged.InvokeAsync((T)Value);
|
||||
await ValueChanged.InvokeAsync((T)internalValue);
|
||||
if (FieldIdentifier.FieldName != null) { EditContext?.NotifyFieldChanged(FieldIdentifier); }
|
||||
await Change.InvokeAsync(Value);
|
||||
await Change.InvokeAsync(internalValue);
|
||||
|
||||
await OnFilter(new ChangeEventArgs());
|
||||
|
||||
@@ -281,15 +386,94 @@ namespace Radzen
|
||||
selectedItems.Clear();
|
||||
}
|
||||
|
||||
SelectItemFromValue(Value);
|
||||
|
||||
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>
|
||||
@@ -298,7 +482,7 @@ namespace Radzen
|
||||
{
|
||||
get
|
||||
{
|
||||
return $"popup{UniqueID}";
|
||||
return $"popup-{GetId()}";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -310,7 +494,7 @@ namespace Radzen
|
||||
{
|
||||
get
|
||||
{
|
||||
return $"search{UniqueID}";
|
||||
return $"search-{GetId()}";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -356,7 +540,7 @@ namespace Radzen
|
||||
/// <summary>
|
||||
/// The list
|
||||
/// </summary>
|
||||
protected ElementReference list;
|
||||
protected ElementReference? list;
|
||||
/// <summary>
|
||||
/// The selected index
|
||||
/// </summary>
|
||||
@@ -376,7 +560,10 @@ namespace Radzen
|
||||
await JSRuntime.InvokeVoidAsync("Radzen.togglePopup", Element, PopupID, true);
|
||||
await JSRuntime.InvokeVoidAsync("Radzen.focusElement", isFilter ? UniqueID : SearchID);
|
||||
|
||||
await JSRuntime.InvokeVoidAsync("Radzen.selectListItem", search, list, selectedIndex);
|
||||
if (list != null)
|
||||
{
|
||||
await JSRuntime.InvokeVoidAsync("Radzen.selectListItem", search, list, selectedIndex);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -389,7 +576,28 @@ namespace Radzen
|
||||
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;
|
||||
|
||||
@@ -397,11 +605,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);
|
||||
@@ -409,7 +619,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)
|
||||
@@ -417,7 +627,7 @@ namespace Radzen
|
||||
//
|
||||
}
|
||||
}
|
||||
else if (Multiple && key == "Space")
|
||||
else if (Multiple && key == "Enter")
|
||||
{
|
||||
if (selectedIndex >= 0 && selectedIndex <= items.Count() - 1)
|
||||
{
|
||||
@@ -433,7 +643,7 @@ namespace Radzen
|
||||
{
|
||||
await JSRuntime.InvokeVoidAsync("Radzen.closePopup", PopupID);
|
||||
}
|
||||
else if (key == "Delete")
|
||||
else if (key == "Delete" && AllowClear)
|
||||
{
|
||||
if (!Multiple && selectedItem != null)
|
||||
{
|
||||
@@ -446,7 +656,7 @@ namespace Radzen
|
||||
Debounce(DebounceFilter, FilterDelay);
|
||||
}
|
||||
}
|
||||
else if(AllowFiltering && isFilter)
|
||||
else if (AllowFiltering && isFilter)
|
||||
{
|
||||
Debounce(DebounceFilter, FilterDelay);
|
||||
}
|
||||
@@ -472,13 +682,13 @@ namespace Radzen
|
||||
_view = null;
|
||||
if (IsVirtualizationAllowed())
|
||||
{
|
||||
#if NET5
|
||||
#if NET5_0_OR_GREATER
|
||||
if (virtualize != null)
|
||||
{
|
||||
await virtualize.RefreshDataAsync();
|
||||
}
|
||||
await InvokeAsync(() => { StateHasChanged(); });
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -489,20 +699,23 @@ 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);
|
||||
}
|
||||
|
||||
@@ -540,7 +753,7 @@ 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) };
|
||||
@@ -571,6 +784,14 @@ namespace Radzen
|
||||
return base.OnAfterRenderAsync(firstRender);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void OnInitialized()
|
||||
{
|
||||
internalValue = Value;
|
||||
|
||||
base.OnInitialized();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Set parameters as an asynchronous operation.
|
||||
/// </summary>
|
||||
@@ -578,7 +799,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))
|
||||
{
|
||||
@@ -599,6 +820,11 @@ namespace Radzen
|
||||
shouldClose = !visible;
|
||||
}
|
||||
|
||||
if (parameters.DidParameterChange(nameof(Value), Value))
|
||||
{
|
||||
internalValue = parameters.GetValueOrDefault<object>(nameof(Value));
|
||||
}
|
||||
|
||||
await base.SetParametersAsync(parameters);
|
||||
|
||||
if (shouldClose && !firstRender)
|
||||
@@ -613,7 +839,7 @@ namespace Radzen
|
||||
/// <returns>Task.</returns>
|
||||
protected override Task OnParametersSetAsync()
|
||||
{
|
||||
var valueAsEnumerable = Value as IEnumerable;
|
||||
var valueAsEnumerable = internalValue as IEnumerable;
|
||||
|
||||
if (valueAsEnumerable != null)
|
||||
{
|
||||
@@ -623,7 +849,7 @@ namespace Radzen
|
||||
}
|
||||
}
|
||||
|
||||
SelectItemFromValue(Value);
|
||||
SelectItemFromValue(internalValue);
|
||||
|
||||
return base.OnParametersSetAsync();
|
||||
}
|
||||
@@ -634,7 +860,7 @@ namespace Radzen
|
||||
/// <param name="args">The <see cref="ChangeEventArgs"/> instance containing the event data.</param>
|
||||
protected void OnChange(ChangeEventArgs args)
|
||||
{
|
||||
Value = args.Value;
|
||||
internalValue = args.Value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -642,15 +868,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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -674,6 +907,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>
|
||||
@@ -729,7 +969,7 @@ namespace Radzen
|
||||
}
|
||||
else
|
||||
{
|
||||
_view = (typeof(IQueryable).IsAssignableFrom(Data.GetType())) ? Query.Cast<object>().ToList().AsQueryable() : Query;
|
||||
_view = (typeof(IQueryable).IsAssignableFrom(Data.GetType())) ? (Query as IEnumerable).Cast<object>().ToList().AsQueryable() : Query;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -770,13 +1010,20 @@ namespace Radzen
|
||||
await SelectItem(item, raiseChange);
|
||||
}
|
||||
|
||||
internal object internalValue;
|
||||
|
||||
/// <summary>
|
||||
/// Selects the item.
|
||||
/// </summary>
|
||||
/// <param name="item">The item.</param>
|
||||
/// <param name="raiseChange">if set to <c>true</c> [raise change].</param>
|
||||
protected async System.Threading.Tasks.Task SelectItem(object item, bool raiseChange = true)
|
||||
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))
|
||||
@@ -785,11 +1032,11 @@ namespace Radzen
|
||||
selectedItem = item;
|
||||
if (!string.IsNullOrEmpty(ValueProperty))
|
||||
{
|
||||
Value = PropertyAccess.GetItemOrValueFromProperty(item, ValueProperty);
|
||||
internalValue = PropertyAccess.GetItemOrValueFromProperty(item, ValueProperty);
|
||||
}
|
||||
else
|
||||
{
|
||||
Value = item;
|
||||
internalValue = item;
|
||||
}
|
||||
|
||||
SetSelectedIndexFromSelectedItem();
|
||||
@@ -798,43 +1045,94 @@ 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);
|
||||
Value = 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)
|
||||
{
|
||||
Value = selectedItems.AsQueryable().Cast(elementType);
|
||||
internalValue = selectedItems.AsQueryable().Cast(elementType);
|
||||
}
|
||||
else
|
||||
{
|
||||
Value = selectedItems;
|
||||
internalValue = selectedItems;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (raiseChange)
|
||||
{
|
||||
await ValueChanged.InvokeAsync(object.Equals(Value, null) ? default(T) : (T)Value);
|
||||
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
|
||||
{
|
||||
await ValueChanged.InvokeAsync(object.Equals(internalValue, null) ? default(T) : (T)internalValue);
|
||||
}
|
||||
}
|
||||
|
||||
if (FieldIdentifier.FieldName != null) { EditContext?.NotifyFieldChanged(FieldIdentifier); }
|
||||
await Change.InvokeAsync(Value);
|
||||
|
||||
await Change.InvokeAsync(internalValue);
|
||||
}
|
||||
StateHasChanged();
|
||||
}
|
||||
|
||||
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>
|
||||
@@ -849,7 +1147,7 @@ namespace Radzen
|
||||
{
|
||||
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
|
||||
{
|
||||
@@ -858,7 +1156,7 @@ namespace Radzen
|
||||
}
|
||||
else
|
||||
{
|
||||
selectedItem = Value;
|
||||
selectedItem = internalValue;
|
||||
}
|
||||
|
||||
SetSelectedIndexFromSelectedItem();
|
||||
@@ -867,25 +1165,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()))
|
||||
{
|
||||
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();
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
@@ -904,5 +1202,28 @@ namespace Radzen
|
||||
selectedItem = null;
|
||||
}
|
||||
}
|
||||
|
||||
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()
|
||||
{
|
||||
base.Dispose();
|
||||
|
||||
keys.Clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
35
Radzen.Blazor/Extensions.cs
Normal file
35
Radzen.Blazor/Extensions.cs
Normal file
@@ -0,0 +1,35 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
|
||||
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() });
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -72,11 +72,8 @@ namespace Radzen
|
||||
}
|
||||
set
|
||||
{
|
||||
if (_form != value && value != null)
|
||||
{
|
||||
_form = value;
|
||||
_form.AddComponent(this);
|
||||
}
|
||||
_form = value;
|
||||
_form?.AddComponent(this);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -170,6 +167,7 @@ namespace Radzen
|
||||
if (EditContext != null && ValueExpression != null && FieldIdentifier.Model != EditContext.Model)
|
||||
{
|
||||
FieldIdentifier = FieldIdentifier.Create(ValueExpression);
|
||||
EditContext.OnValidationStateChanged -= ValidationStateChanged;
|
||||
EditContext.OnValidationStateChanged += ValidationStateChanged;
|
||||
}
|
||||
|
||||
|
||||
@@ -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,6 +44,13 @@ 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>
|
||||
@@ -87,6 +98,34 @@ namespace Radzen.Blazor
|
||||
/// <param name="y">The y.</param>
|
||||
object 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>
|
||||
/// <value>The title.</value>
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
@@ -8,6 +8,10 @@ namespace Radzen.Blazor
|
||||
/// </summary>
|
||||
public interface ISchedulerView
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the icon of the view. It is displayed in the view switching UI.
|
||||
/// </summary>
|
||||
string Icon { get; }
|
||||
/// <summary>
|
||||
/// Gets the title of the view. It is displayed in the RadzenScheduler title area.
|
||||
/// </summary>
|
||||
|
||||
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-2021 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,10 @@ namespace Radzen
|
||||
Severity = message.Severity,
|
||||
Summary = message.Summary,
|
||||
Detail = message.Detail,
|
||||
Style = message.Style
|
||||
Style = message.Style,
|
||||
Click = message.Click,
|
||||
CloseOnClick = message.CloseOnClick,
|
||||
Payload = message.Payload
|
||||
};
|
||||
|
||||
if (!Messages.Contains(newMessage))
|
||||
@@ -44,21 +49,27 @@ namespace Radzen
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Notifies the specified severity.
|
||||
/// </summary>
|
||||
/// <param name="severity">The severity.</param>
|
||||
/// <param name="summary">The summary.</param>
|
||||
/// <param name="detail">The detail.</param>
|
||||
/// <param name="duration">The duration.</param>
|
||||
public void Notify(NotificationSeverity severity = NotificationSeverity.Info, string summary = "", string detail = "", double duration = 3000)
|
||||
/// <summary>
|
||||
/// Notifies the specified severity.
|
||||
/// </summary>
|
||||
/// <param name="severity">The severity.</param>
|
||||
/// <param name="summary">The summary.</param>
|
||||
/// <param name="detail">The detail.</param>
|
||||
/// <param name="duration">The duration.</param>
|
||||
/// <param name="click">The click event.</param>
|
||||
/// <param name="closeOnClick">If true, then the notification will be closed when clicked on.</param>
|
||||
/// <param name="payload">Used to store a custom payload that can be retreived later in the click event handler.</param>
|
||||
public void Notify(NotificationSeverity severity = NotificationSeverity.Info, string summary = "", string detail = "", double duration = 3000, Action<NotificationMessage> click = null, bool closeOnClick = false, object payload = null)
|
||||
{
|
||||
var newMessage = new NotificationMessage()
|
||||
{
|
||||
Duration = duration,
|
||||
Severity = severity,
|
||||
Summary = summary,
|
||||
Detail = detail
|
||||
Detail = detail,
|
||||
Click = click,
|
||||
CloseOnClick = closeOnClick,
|
||||
Payload = payload
|
||||
};
|
||||
|
||||
if (!Messages.Contains(newMessage))
|
||||
@@ -98,5 +109,20 @@ 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>
|
||||
/// 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; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,6 +21,20 @@ namespace Radzen
|
||||
[Parameter]
|
||||
public PagerPosition PagerPosition { get; set; } = PagerPosition.Bottom;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether pager is visible even when not enough data for paging.
|
||||
/// </summary>
|
||||
/// <value><c>true</c> if pager is visible even when not enough data for paging otherwise, <c>false</c>.</value>
|
||||
[Parameter]
|
||||
public bool PagerAlwaysVisible { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the horizontal align.
|
||||
/// </summary>
|
||||
/// <value>The horizontal align.</value>
|
||||
[Parameter]
|
||||
public HorizontalAlign PagerHorizontalAlign { get; set; } = HorizontalAlign.Justify;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether paging is allowed. Set to <c>false</c> by default.
|
||||
/// </summary>
|
||||
@@ -28,12 +42,23 @@ namespace Radzen
|
||||
[Parameter]
|
||||
public bool AllowPaging { get; set; }
|
||||
|
||||
int _PageSize = 10;
|
||||
/// <summary>
|
||||
/// Gets or sets the size of the page.
|
||||
/// </summary>
|
||||
/// <value>The size of the page.</value>
|
||||
[Parameter]
|
||||
public int PageSize { get; set; } = 10;
|
||||
public int PageSize
|
||||
{
|
||||
get
|
||||
{
|
||||
return pageSize ?? _PageSize;
|
||||
}
|
||||
set
|
||||
{
|
||||
_PageSize = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the page numbers count.
|
||||
@@ -93,26 +118,30 @@ namespace Radzen
|
||||
/// </summary>
|
||||
/// <value>The page size options.</value>
|
||||
[Parameter]
|
||||
public IEnumerable<int> PageSizeOptions { get; set; }
|
||||
public IEnumerable<int> PageSizeOptions { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the page size description text.
|
||||
/// </summary>
|
||||
/// <value>The page size description text.</value>
|
||||
[Parameter]
|
||||
public string PageSizeText { get; set; } = "items per page";
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the pager summary visibility.
|
||||
/// </summary>
|
||||
/// <value>The pager summary visibility.</value>
|
||||
[Parameter]
|
||||
public bool ShowPagingSummary { get; set; } = false;
|
||||
|
||||
public bool ShowPagingSummary { get; set; } = false;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the pager summary format.
|
||||
/// </summary>
|
||||
/// <value>The pager summary format.</value>
|
||||
[Parameter]
|
||||
/// <value>The pager summary format.</value>
|
||||
[Parameter]
|
||||
public string PagingSummaryFormat { get; set; } = "Page {0} of {1} ({2} items)";
|
||||
|
||||
/// <summary>
|
||||
/// The view
|
||||
/// </summary>
|
||||
protected IQueryable<T> _view = null;
|
||||
internal IQueryable<T> _view = null;
|
||||
/// <summary>
|
||||
/// Gets the paged view.
|
||||
/// </summary>
|
||||
@@ -185,7 +214,8 @@ namespace Radzen
|
||||
/// <returns>A Task representing the asynchronous operation.</returns>
|
||||
public override async Task SetParametersAsync(ParameterView parameters)
|
||||
{
|
||||
bool pageSizeChanged = parameters.DidParameterChange(nameof(PageSize), PageSize);
|
||||
bool pageSizeChanged = parameters.DidParameterChange(nameof(PageSize), PageSize) &&
|
||||
PageSize != pageSize;
|
||||
|
||||
await base.SetParametersAsync(parameters);
|
||||
|
||||
@@ -222,16 +252,25 @@ namespace Radzen
|
||||
/// </summary>
|
||||
/// <param name="firstRender">if set to <c>true</c> [first render].</param>
|
||||
/// <returns>Task.</returns>
|
||||
protected override Task OnAfterRenderAsync(bool firstRender)
|
||||
protected override async Task OnAfterRenderAsync(bool firstRender)
|
||||
{
|
||||
this.firstRender = firstRender;
|
||||
if (firstRender && Visible && (LoadData.HasDelegate && Data == null))
|
||||
|
||||
if (firstRender)
|
||||
{
|
||||
InvokeAsync(Reload);
|
||||
StateHasChanged();
|
||||
await ReloadOnFirstRender();
|
||||
}
|
||||
|
||||
return base.OnAfterRenderAsync(firstRender);
|
||||
await base.OnAfterRenderAsync(firstRender);
|
||||
}
|
||||
|
||||
internal virtual async Task ReloadOnFirstRender()
|
||||
{
|
||||
if (firstRender && Visible && (LoadData.HasDelegate && Data == null))
|
||||
{
|
||||
await InvokeAsync(Reload);
|
||||
StateHasChanged();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -248,6 +287,13 @@ namespace Radzen
|
||||
/// </summary>
|
||||
protected RadzenPager bottomPager;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the page callback.
|
||||
/// </summary>
|
||||
/// <value>The page callback.</value>
|
||||
[Parameter]
|
||||
public EventCallback<PagerEventArgs> Page { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Handles the <see cref="E:PageChanged" /> event.
|
||||
/// </summary>
|
||||
@@ -256,16 +302,21 @@ namespace Radzen
|
||||
{
|
||||
skip = args.Skip;
|
||||
CurrentPage = args.PageIndex;
|
||||
|
||||
await Page.InvokeAsync(args);
|
||||
|
||||
await InvokeAsync(Reload);
|
||||
}
|
||||
|
||||
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;
|
||||
pageSize = value;
|
||||
await InvokeAsync(Reload);
|
||||
}
|
||||
|
||||
@@ -291,16 +342,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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -310,14 +362,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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -45,7 +45,9 @@ namespace Radzen
|
||||
{FilterOperator.Contains, "Contains"},
|
||||
{FilterOperator.DoesNotContain, "DoesNotContain"},
|
||||
{FilterOperator.IsNull, "=="},
|
||||
{FilterOperator.IsNotNull, "!="}
|
||||
{FilterOperator.IsEmpty, "=="},
|
||||
{FilterOperator.IsNotNull, "!="},
|
||||
{FilterOperator.IsNotEmpty, "!="}
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
@@ -64,7 +66,9 @@ namespace Radzen
|
||||
{FilterOperator.Contains, "contains"},
|
||||
{FilterOperator.DoesNotContain, "DoesNotContain"},
|
||||
{FilterOperator.IsNull, "eq"},
|
||||
{FilterOperator.IsNotNull, "ne"}
|
||||
{FilterOperator.IsEmpty, "eq"},
|
||||
{FilterOperator.IsNotNull, "ne"},
|
||||
{FilterOperator.IsNotEmpty, "ne"}
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
@@ -140,8 +144,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())
|
||||
{
|
||||
@@ -168,7 +174,18 @@ namespace Radzen
|
||||
secondValue = sv is DateTime ? ((DateTime)sv).ToString("yyyy-MM-ddTHH:mm:ss.fffZ") : sv is DateTimeOffset ? ((DateTimeOffset)sv).UtcDateTime.ToString("yyyy-MM-ddTHH:mm:ss.fffZ") : "";
|
||||
}
|
||||
}
|
||||
else if (typeof(IEnumerable).IsAssignableFrom(column.FilterPropertyType) && column.FilterPropertyType != typeof(string))
|
||||
else if (PropertyAccess.IsEnum(column.FilterPropertyType) || PropertyAccess.IsNullableEnum(column.FilterPropertyType))
|
||||
{
|
||||
if (v != null)
|
||||
{
|
||||
value = ((int)v).ToString();
|
||||
}
|
||||
if (sv != null)
|
||||
{
|
||||
secondValue = ((int)sv).ToString();
|
||||
}
|
||||
}
|
||||
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();
|
||||
@@ -221,7 +238,10 @@ namespace Radzen
|
||||
secondValue = (string)Convert.ChangeType(column.GetSecondFilterValue(), typeof(string));
|
||||
}
|
||||
|
||||
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)
|
||||
@@ -395,26 +415,49 @@ namespace Radzen
|
||||
}
|
||||
else if (columnFilterOperator == FilterOperator.IsNull)
|
||||
{
|
||||
return $@"({property} == null ? """" : {property}) == null";
|
||||
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 $@"({property} == null ? """" : {property}) != null";
|
||||
return $@"np({property}) != null";
|
||||
}
|
||||
}
|
||||
else if (PropertyAccess.IsNumeric(column.FilterPropertyType))
|
||||
{
|
||||
return $"{property} {linqOperator} {value}";
|
||||
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) ||
|
||||
column.FilterPropertyType == typeof(DateTime?) ||
|
||||
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);
|
||||
@@ -431,10 +474,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}"")";
|
||||
@@ -545,7 +592,7 @@ namespace Radzen
|
||||
var columnFilterOperator = !second ? column.GetFilterOperator() : column.GetSecondFilterOperator();
|
||||
var odataFilterOperator = ODataFilterOperators[columnFilterOperator];
|
||||
|
||||
var value = typeof(IEnumerable).IsAssignableFrom(column.FilterPropertyType) && column.FilterPropertyType != typeof(string) ? null :
|
||||
var value = IsEnumerable(column.FilterPropertyType) && column.FilterPropertyType != typeof(string) ? null :
|
||||
!second ? (string)Convert.ChangeType(column.GetFilterValue(), typeof(string)) :
|
||||
(string)Convert.ChangeType(column.GetSecondFilterValue(), typeof(string));
|
||||
|
||||
@@ -596,8 +643,12 @@ 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();
|
||||
|
||||
@@ -625,6 +676,10 @@ namespace Radzen
|
||||
{
|
||||
return $"{property} {odataFilterOperator} null";
|
||||
}
|
||||
else if (columnFilterOperator == FilterOperator.IsEmpty || columnFilterOperator == FilterOperator.IsNotEmpty)
|
||||
{
|
||||
return $"{property} {odataFilterOperator} ''";
|
||||
}
|
||||
else
|
||||
{
|
||||
return $"{property} eq {value.ToLower()}";
|
||||
@@ -639,6 +694,10 @@ 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")}";
|
||||
@@ -715,8 +774,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())
|
||||
{
|
||||
@@ -731,7 +792,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)
|
||||
@@ -841,6 +903,11 @@ namespace Radzen
|
||||
return source;
|
||||
}
|
||||
|
||||
private static bool IsEnumerable(Type type)
|
||||
{
|
||||
return typeof(IEnumerable).IsAssignableFrom(type) || typeof(IEnumerable<>).IsAssignableFrom(type);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Wheres the specified columns.
|
||||
/// </summary>
|
||||
@@ -851,8 +918,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())
|
||||
{
|
||||
@@ -870,14 +939,18 @@ namespace Radzen
|
||||
property = $"({property})";
|
||||
}
|
||||
|
||||
if (column.FilterPropertyType == typeof(string))
|
||||
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()" : "";
|
||||
&& 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()];
|
||||
|
||||
@@ -887,7 +960,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() });
|
||||
}
|
||||
@@ -900,7 +973,7 @@ namespace Radzen
|
||||
}
|
||||
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() });
|
||||
}
|
||||
@@ -911,7 +984,7 @@ namespace Radzen
|
||||
|
||||
index++;
|
||||
}
|
||||
else
|
||||
else if (!(IsEnumerable(column.FilterPropertyType) && column.FilterPropertyType != typeof(string)))
|
||||
{
|
||||
whereList.Add($@"{property}{filterCaseSensitivityOperator} {comparison} @{index}{filterCaseSensitivityOperator}", new object[] { column.GetFilterValue() });
|
||||
index++;
|
||||
@@ -921,7 +994,7 @@ namespace Radzen
|
||||
{
|
||||
var secondComparison = LinqFilterOperators[column.GetSecondFilterOperator()];
|
||||
|
||||
if (typeof(IEnumerable).IsAssignableFrom(column.FilterPropertyType) && column.FilterPropertyType != typeof(string) &&
|
||||
if (IsEnumerable(column.FilterPropertyType) && column.FilterPropertyType != typeof(string) &&
|
||||
(comparison == "Contains" || comparison == "DoesNotContain") &&
|
||||
(secondComparison == "Contains" || secondComparison == "DoesNotContain"))
|
||||
{
|
||||
@@ -952,12 +1025,277 @@ 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.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)))
|
||||
{
|
||||
filterExpressions.Add($@"{property}{filterCaseSensitivityOperator} {comparison} @{index}{filterCaseSensitivityOperator}");
|
||||
filterValues.Add(new object[] { filter.FilterValue });
|
||||
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.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 enumerableValueAsString = "(" + String.Join(",",
|
||||
(enumerableValue.ElementType == 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))
|
||||
{
|
||||
value = $"'{value}'";
|
||||
}
|
||||
else if (column.FilterPropertyType == typeof(DateTime) || column.FilterPropertyType == typeof(DateTime?))
|
||||
{
|
||||
value = $"{DateTime.Parse(value, null, System.Globalization.DateTimeStyles.RoundtripKind).ToString("yyyy-MM-ddTHH:mm:ss.fffZ")}";
|
||||
}
|
||||
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>
|
||||
<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.13.3</Version>
|
||||
<Version>4.7.0</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,59 +21,55 @@
|
||||
<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="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" />
|
||||
<PackageReference Include="System.Linq.Dynamic.Core" Version="1.2.22" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Include="LICENSE.txt" Pack="true" PackagePath="" />
|
||||
<None Include="icon.png" Pack="true" PackagePath="" />
|
||||
<None Include="LICENSE.txt" Pack="true" PackagePath="" />
|
||||
<None Include="icon.png" Pack="true" PackagePath="" />
|
||||
<None Include="README.md" Pack="true" PackagePath="\"/>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Include="LinkerConfig.xml">
|
||||
<LogicalName>$(MSBuildProjectName).xml</LogicalName>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Include="LinkerConfig.xml">
|
||||
<LogicalName>$(MSBuildProjectName).xml</LogicalName>
|
||||
</EmbeddedResource>
|
||||
</ItemGroup>
|
||||
|
||||
<UsingTask TaskName="RemoveSourceMap" TaskFactory="RoslynCodeTaskFactory" AssemblyFile="$(MSBuildToolsPath)\Microsoft.Build.Tasks.Core.dll">
|
||||
<Task>
|
||||
<Using Namespace="System" />
|
||||
<Using Namespace="System.IO" />
|
||||
<Using Namespace="System.Text" />
|
||||
<Code Type="Fragment" Language="cs">
|
||||
<![CDATA[
|
||||
foreach (var file in Directory.EnumerateFiles("./wwwroot/css", "*.css"))
|
||||
{
|
||||
File.WriteAllText(file, File.ReadAllText(file).Replace("/*# sourceMappingURL=themes" + Path.DirectorySeparatorChar + Path.GetFileName(file) + ".map */", ""), Encoding.UTF8);
|
||||
}
|
||||
]]>
|
||||
</Code>
|
||||
</Task>
|
||||
</UsingTask>
|
||||
|
||||
<Target Name="ToolRestore" BeforeTargets="PreBuildEvent">
|
||||
<Exec Command="dotnet tool restore" StandardOutputImportance="high" />
|
||||
|
||||
<PropertyGroup>
|
||||
<LibSassOutputStyle>expanded</LibSassOutputStyle>
|
||||
<EnableDefaultSassItems>false</EnableDefaultSassItems>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Sass Include="$(MSBuildProjectDirectory)/themes/*.scss" Exclude="$(MSBuildProjectDirectory)/themes/_*.scss" Condition="'$(TargetFramework)' == 'net6.0'" />
|
||||
</ItemGroup>
|
||||
|
||||
<Target Name="Sass" BeforeTargets="BeforeBuild" Condition="'$(TargetFramework)' == 'net6.0'">
|
||||
<PropertyGroup>
|
||||
<_SassFileList>@(Sass->'"%(FullPath)"', ' ')</_SassFileList>
|
||||
<LibSassBuilderArgs>files $(_SassFileList) --outputstyle $(LibSassOutputStyle) --level $(LibSassOutputLevel)</LibSassBuilderArgs>
|
||||
</PropertyGroup>
|
||||
<Message Text="$(LibSassBuilderArgs)" Importance="$(LibSassMessageLevel)" />
|
||||
<Message Text="Converted SassFile list to argument" Importance="$(LibSassMessageLevel)" />
|
||||
</Target>
|
||||
<Target Name="PreBuild" AfterTargets="ToolRestore">
|
||||
<Exec Command="dotnet webcompiler -r themes -o wwwroot/css -z disable -m disable -p disable" StandardOutputImportance="high" />
|
||||
|
||||
<Target Name="MoveCss" AfterTargets="AfterCompile" Condition="'$(TargetFramework)' == 'net6.0'" >
|
||||
<ItemGroup>
|
||||
<CssFiles Include="$(MSBuildProjectDirectory)\themes\*.css" />
|
||||
<CssFile Include="$(MSBuildProjectDirectory)/themes/*.css" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<BootstrapFiles Include="$(MSBuildProjectDirectory)\wwwroot\css\bootstrap\**\*.*" />
|
||||
</ItemGroup>
|
||||
<Delete Files="@(CssFiles)" />
|
||||
<Delete Files="@(BootstrapFiles)" />
|
||||
<RemoveDir Directories="$(MSBuildProjectDirectory)\wwwroot\css\bootstrap" />
|
||||
<RemoveSourceMap />
|
||||
<Move SourceFiles="@(CssFile)" DestinationFolder="$(MSBuildProjectDirectory)/wwwroot/css/" />
|
||||
</Target>
|
||||
|
||||
</Project>
|
||||
@@ -10,14 +10,14 @@
|
||||
}
|
||||
@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];
|
||||
if (!item.Visible)
|
||||
continue;
|
||||
|
||||
<div class="rz-accordion-header" @attributes="item.Attributes" style="@item.Style">
|
||||
<div @ref="@item.Element" id="@item.GetItemId()" @attributes="item.Attributes" class="@item.GetItemCssClass()" style="@item.Style">
|
||||
<a @onclick="@((args) => SelectItem(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))
|
||||
@@ -34,7 +34,7 @@
|
||||
}
|
||||
@if (!string.IsNullOrEmpty(item.Text))
|
||||
{
|
||||
<span>@item.Text</span>
|
||||
<span>@((MarkupString)item.Text)</span>
|
||||
}
|
||||
</a>
|
||||
</div>
|
||||
|
||||
@@ -102,7 +102,10 @@ namespace Radzen.Blazor
|
||||
if (items.Contains(item))
|
||||
{
|
||||
items.Remove(item);
|
||||
try { InvokeAsync(StateHasChanged); } catch { }
|
||||
if (!disposed)
|
||||
{
|
||||
try { InvokeAsync(StateHasChanged); } catch { }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -54,7 +54,10 @@ namespace Radzen.Blazor
|
||||
if (_visible != value)
|
||||
{
|
||||
_visible = value;
|
||||
Accordion.Refresh();
|
||||
if (Accordion != null)
|
||||
{
|
||||
Accordion.Refresh();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -106,5 +109,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()" 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.Lighter)
|
||||
{
|
||||
if (AlertStyle == AlertStyle.Primary)
|
||||
{
|
||||
<RadzenButton Click=@Close Icon="close" Variant="Variant.Text" ButtonStyle="ButtonStyle.Primary" Shade="Shade.Dark" Size="@getCloseButtonSize()" />
|
||||
}
|
||||
else if (AlertStyle == AlertStyle.Secondary)
|
||||
{
|
||||
<RadzenButton Click=@Close Icon="close" Variant="Variant.Text" ButtonStyle="ButtonStyle.Secondary" Shade="Shade.Dark" Size="@getCloseButtonSize()" />
|
||||
}
|
||||
else if (AlertStyle == AlertStyle.Light)
|
||||
{
|
||||
<RadzenButton Click=@Close Icon="close" Variant="Variant.Text" ButtonStyle="ButtonStyle.Dark" Shade="Shade.Dark" Size="@getCloseButtonSize()" />
|
||||
}
|
||||
else if (AlertStyle == AlertStyle.Base)
|
||||
{
|
||||
<RadzenButton Click=@Close Icon="close" Variant="Variant.Text" ButtonStyle="ButtonStyle.Dark" Shade="Shade.Dark" Size="@getCloseButtonSize()" />
|
||||
}
|
||||
else if (AlertStyle == AlertStyle.Dark)
|
||||
{
|
||||
<RadzenButton Click=@Close Icon="close" Variant="Variant.Text" ButtonStyle="ButtonStyle.Light" Shade="Shade.Dark" Size="@getCloseButtonSize()" />
|
||||
}
|
||||
else if (AlertStyle == AlertStyle.Success)
|
||||
{
|
||||
<RadzenButton Click=@Close Icon="close" Variant="Variant.Text" ButtonStyle="ButtonStyle.Success" Shade="Shade.Dark" Size="@getCloseButtonSize()" />
|
||||
}
|
||||
else if (AlertStyle == AlertStyle.Danger)
|
||||
{
|
||||
<RadzenButton Click=@Close Icon="close" Variant="Variant.Text" ButtonStyle="ButtonStyle.Danger" Shade="Shade.Dark" Size="@getCloseButtonSize()" />
|
||||
}
|
||||
else if (AlertStyle == AlertStyle.Warning)
|
||||
{
|
||||
<RadzenButton Click=@Close Icon="close" Variant="Variant.Text" ButtonStyle="ButtonStyle.Warning" Shade="Shade.Dark" Size="@getCloseButtonSize()" />
|
||||
}
|
||||
else if (AlertStyle == AlertStyle.Info)
|
||||
{
|
||||
<RadzenButton Click=@Close Icon="close" Variant="Variant.Text" ButtonStyle="ButtonStyle.Info" Shade="Shade.Dark" 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>
|
||||
}
|
||||
158
Radzen.Blazor/RadzenAlert.razor.cs
Normal file
158
Radzen.Blazor/RadzenAlert.razor.cs
Normal file
@@ -0,0 +1,158 @@
|
||||
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="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 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,16 +12,7 @@
|
||||
|
||||
var value = ComposeValue(valueScale);
|
||||
|
||||
IPathGenerator pathGenerator;
|
||||
|
||||
if (Smooth)
|
||||
{
|
||||
pathGenerator = new SplineGenerator();
|
||||
}
|
||||
else
|
||||
{
|
||||
pathGenerator = new LineGenerator();
|
||||
}
|
||||
var pathGenerator = GetPathGenerator();
|
||||
|
||||
var data = Items.Select(item =>
|
||||
{
|
||||
|
||||
@@ -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
|
||||
@@ -51,6 +63,26 @@ namespace Radzen.Blazor
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override string TooltipStyle(TItem item)
|
||||
{
|
||||
var style = base.TooltipStyle(item);
|
||||
|
||||
var index = Items.IndexOf(item);
|
||||
|
||||
if (index >= 0)
|
||||
{
|
||||
var color = Fill;
|
||||
|
||||
if (color != null)
|
||||
{
|
||||
style = $"{style}; border-color: {color};";
|
||||
}
|
||||
}
|
||||
|
||||
return style;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override bool Contains(double x, double y, double tolerance)
|
||||
{
|
||||
@@ -62,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))
|
||||
@@ -82,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,20 +10,39 @@
|
||||
@if (Visible)
|
||||
{
|
||||
<div @ref="@Element" style="@($"{Style};display:inline-block;")" @attributes="Attributes" class="@GetCssClass()" id="@GetId()">
|
||||
<span class="rz-autocomplete" style="width:100%">
|
||||
@if (Multiline)
|
||||
{
|
||||
<textarea @ref="@search" @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"
|
||||
id="@Name" aria-expanded="true" placeholder="@Placeholder" />
|
||||
}
|
||||
else
|
||||
{
|
||||
<input @ref="@search" @onkeydown="@OnFilterKeyPress" value="@Value" disabled="@Disabled"
|
||||
onfocus="@OpenScript()" onkeypress="@OpenScript()" tabindex="@TabIndex" @onchange="@OnChange"
|
||||
aria-autocomplete="list" aria-haspopup="true" autocomplete="off" role="combobox"
|
||||
class="@InputClassList"
|
||||
type="text" id="@Name" aria-expanded="true" placeholder="@Placeholder" />
|
||||
</span><div id="@PopupID" class="rz-autocomplete-panel" style="display:none; transform: none; box-sizing: border-box; max-height: 200px;">
|
||||
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="@Placeholder" />
|
||||
}
|
||||
<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>
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,6 +22,27 @@ namespace Radzen.Blazor
|
||||
/// </example>
|
||||
public partial class RadzenAutoComplete : DataBoundFormComponent<string>
|
||||
{
|
||||
/// <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>
|
||||
@@ -78,11 +99,11 @@ namespace Radzen.Blazor
|
||||
selectedIndex = -1;
|
||||
}
|
||||
}
|
||||
else if (key == "Escape")
|
||||
else if (key == "Escape" || key == "Tab")
|
||||
{
|
||||
await JSRuntime.InvokeVoidAsync("Radzen.closePopup", PopupID);
|
||||
}
|
||||
else if(key != "Tab")
|
||||
else
|
||||
{
|
||||
selectedIndex = -1;
|
||||
|
||||
@@ -148,7 +169,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);
|
||||
}
|
||||
|
||||
@@ -203,7 +226,7 @@ namespace Radzen.Blazor
|
||||
/// <inheritdoc />
|
||||
protected override string GetComponentCssClass()
|
||||
{
|
||||
return GetClassList("").ToString();
|
||||
return GetClassList("rz-autocomplete").ToString();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
|
||||
@@ -19,7 +19,9 @@ namespace Radzen.Blazor
|
||||
var classList = new List<string>();
|
||||
|
||||
classList.Add("rz-badge");
|
||||
classList.Add($"rz-badge-{BadgeStyle.ToString().ToLower()}");
|
||||
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;
|
||||
@@ -9,7 +10,7 @@ namespace Radzen.Blazor
|
||||
/// Renders bar series in <see cref="RadzenChart" />.
|
||||
/// </summary>
|
||||
/// <typeparam name="TItem">The type of the series data item.</typeparam>
|
||||
public partial class RadzenBarSeries<TItem> : Radzen.Blazor.CartesianSeries<TItem>, IChartBarSeries
|
||||
public partial class RadzenBarSeries<TItem> : CartesianSeries<TItem>, IChartBarSeries
|
||||
{
|
||||
/// <summary>
|
||||
/// Specifies the fill (background color) of the bar series.
|
||||
@@ -74,6 +75,12 @@ namespace Radzen.Blazor
|
||||
return base.TransformCategoryScale(scale);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override IList<object> GetCategories()
|
||||
{
|
||||
return base.GetCategories().Reverse().ToList();
|
||||
}
|
||||
|
||||
private IList<IChartSeries> BarSeries
|
||||
{
|
||||
get
|
||||
@@ -90,13 +97,42 @@ namespace Radzen.Blazor
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override string TooltipStyle(TItem item)
|
||||
{
|
||||
var style = base.TooltipStyle(item);
|
||||
|
||||
var index = Items.IndexOf(item);
|
||||
|
||||
if (index >= 0)
|
||||
{
|
||||
var color = PickColor(index, Fills, Fill);
|
||||
|
||||
if (color != null)
|
||||
{
|
||||
style = $"{style}; border-color: {color};";
|
||||
}
|
||||
}
|
||||
|
||||
return style;
|
||||
}
|
||||
|
||||
private double BandHeight
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -115,7 +151,7 @@ namespace Radzen.Blazor
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override double TooltipX(TItem item)
|
||||
internal override double TooltipX(TItem item)
|
||||
{
|
||||
var value = Chart.CategoryScale.Compose(Value);
|
||||
var x = value(item);
|
||||
@@ -168,7 +204,7 @@ namespace Radzen.Blazor
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override double TooltipY(TItem item)
|
||||
internal override double TooltipY(TItem item)
|
||||
{
|
||||
var category = ComposeCategory(Chart.ValueScale);
|
||||
var barSeries = VisibleBarSeries;
|
||||
@@ -180,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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
using Microsoft.AspNetCore.Components;
|
||||
using System.Linq;
|
||||
using Radzen.Blazor.Rendering;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Components.Routing;
|
||||
using Microsoft.JSInterop;
|
||||
|
||||
namespace Radzen.Blazor
|
||||
{
|
||||
@@ -8,17 +12,23 @@ namespace Radzen.Blazor
|
||||
/// </summary>
|
||||
public partial class RadzenBody : RadzenComponentWithChildren
|
||||
{
|
||||
private const string DefaultStyle = "margin-top: 51px; margin-bottom: 57px; margin-left:250px;";
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the style.
|
||||
/// </summary>
|
||||
/// <value>The style.</value>
|
||||
[Parameter]
|
||||
public override string Style { get; set; } = "margin-top: 51px; margin-bottom: 57px; margin-left:250px;";
|
||||
public override string Style { get; set; } = DefaultStyle;
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override string GetComponentCssClass()
|
||||
{
|
||||
return Expanded ? "body body-expanded" : "body";
|
||||
var classList = ClassList.Create("rz-body")
|
||||
.Add("body")
|
||||
.Add("body-expanded", Expanded);
|
||||
|
||||
return classList.ToString();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -31,24 +41,45 @@ namespace Radzen.Blazor
|
||||
StateHasChanged();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The <see cref="RadzenLayout" /> this component is nested in.
|
||||
/// </summary>
|
||||
[CascadingParameter]
|
||||
public RadzenLayout Layout { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the style.
|
||||
/// </summary>
|
||||
/// <returns>System.String.</returns>
|
||||
protected string GetStyle()
|
||||
{
|
||||
var marginLeft = 250;
|
||||
|
||||
if (!string.IsNullOrEmpty(Style))
|
||||
if (Layout == null)
|
||||
{
|
||||
var marginLeftStyle = Style.Split(';').Where(i => i.Split(':')[0].Contains("margin-left")).FirstOrDefault();
|
||||
if (!string.IsNullOrEmpty(marginLeftStyle) && marginLeftStyle.Contains("px"))
|
||||
{
|
||||
marginLeft = int.Parse(marginLeftStyle.Split(':')[1].Trim().Replace("px", "").Split('.')[0].Trim());
|
||||
}
|
||||
}
|
||||
var marginLeft = 250;
|
||||
var style = Style;
|
||||
|
||||
return $"{Style}; margin-left: {(Expanded ? 0 : marginLeft)}px";
|
||||
if (!string.IsNullOrEmpty(Style))
|
||||
{
|
||||
var marginLeftStyle = Style.Split(';').Where(i => i.Split(':')[0].Contains("margin-left")).FirstOrDefault();
|
||||
if (!string.IsNullOrEmpty(marginLeftStyle) && marginLeftStyle.Contains("px"))
|
||||
{
|
||||
marginLeft = int.Parse(marginLeftStyle.Split(':')[1].Trim().Replace("px", "").Split('.')[0].Trim());
|
||||
}
|
||||
}
|
||||
|
||||
return $"{Style}; margin-left: {(Expanded ? 0 : marginLeft)}px";
|
||||
}
|
||||
else
|
||||
{
|
||||
var style = Style;
|
||||
|
||||
if (!string.IsNullOrEmpty(style))
|
||||
{
|
||||
style = style.Replace(DefaultStyle, "");
|
||||
}
|
||||
|
||||
return $"{style}";
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -64,5 +95,32 @@ namespace Radzen.Blazor
|
||||
/// <value>The expanded changed callback.</value>
|
||||
[Parameter]
|
||||
public EventCallback<bool> ExpandedChanged { get; set; }
|
||||
|
||||
[Inject]
|
||||
NavigationManager NavigationManager { get; set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override Task OnInitializedAsync()
|
||||
{
|
||||
NavigationManager.LocationChanged += OnLocationChanged;
|
||||
|
||||
return base.OnInitializedAsync();
|
||||
}
|
||||
|
||||
private void OnLocationChanged(object sender, LocationChangedEventArgs e)
|
||||
{
|
||||
if (IsJSRuntimeAvailable && Layout != null)
|
||||
{
|
||||
JSRuntime.InvokeVoidAsync("eval", $"document.getElementById('{GetId()}').scrollTop = 0");
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void Dispose()
|
||||
{
|
||||
NavigationManager.LocationChanged -= OnLocationChanged;
|
||||
|
||||
base.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
13
Radzen.Blazor/RadzenBreadCrumb.razor
Normal file
13
Radzen.Blazor/RadzenBreadCrumb.razor
Normal file
@@ -0,0 +1,13 @@
|
||||
@inherits RadzenComponentWithChildren
|
||||
|
||||
<CascadingValue Value="@Template">
|
||||
@if (Visible)
|
||||
{
|
||||
<div class="@GetCssClass()" style="@Style" @attributes="@Attributes" id="@GetId()">
|
||||
@if (ChildContent != null)
|
||||
{
|
||||
@ChildContent
|
||||
}
|
||||
</div>
|
||||
}
|
||||
</CascadingValue>
|
||||
23
Radzen.Blazor/RadzenBreadCrumb.razor.cs
Normal file
23
Radzen.Blazor/RadzenBreadCrumb.razor.cs
Normal file
@@ -0,0 +1,23 @@
|
||||
using Microsoft.AspNetCore.Components;
|
||||
|
||||
namespace Radzen.Blazor
|
||||
{
|
||||
/// <summary>
|
||||
/// A component to display a Bread Crumb style menu
|
||||
/// </summary>
|
||||
public partial class RadzenBreadCrumb : RadzenComponentWithChildren
|
||||
{
|
||||
/// <summary>
|
||||
/// An optional RenderFragment that is rendered per Item
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
public RenderFragment<RadzenBreadCrumbItem> Template { get; set; }
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override string GetComponentCssClass()
|
||||
{
|
||||
return "rz-breadcrumb";
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
30
Radzen.Blazor/RadzenBreadCrumbItem.razor
Normal file
30
Radzen.Blazor/RadzenBreadCrumbItem.razor
Normal file
@@ -0,0 +1,30 @@
|
||||
@inherits RadzenComponent
|
||||
|
||||
@if (Visible)
|
||||
{
|
||||
<div class="@GetCssClass()" id="@GetId()" style="@Style" @attributes="@Attributes">
|
||||
@if (ChildContent != null)
|
||||
{
|
||||
@ChildContent
|
||||
}
|
||||
else if (Template != null)
|
||||
{
|
||||
@Template(this)
|
||||
}
|
||||
else
|
||||
{
|
||||
@if (!string.IsNullOrWhiteSpace(Path))
|
||||
{
|
||||
<RadzenLink Icon="@Icon" Path="@Path" Text="@Text" />
|
||||
}
|
||||
else
|
||||
{
|
||||
@if (!string.IsNullOrWhiteSpace(Icon))
|
||||
{
|
||||
<RadzenIcon Icon="@Icon" />
|
||||
}
|
||||
<RadzenLabel Text="@Text" />
|
||||
}
|
||||
}
|
||||
</div>
|
||||
}
|
||||
47
Radzen.Blazor/RadzenBreadCrumbItem.razor.cs
Normal file
47
Radzen.Blazor/RadzenBreadCrumbItem.razor.cs
Normal file
@@ -0,0 +1,47 @@
|
||||
using Microsoft.AspNetCore.Components;
|
||||
|
||||
namespace Radzen.Blazor
|
||||
{
|
||||
/// <summary>
|
||||
/// Bread Crumb Item Component
|
||||
/// </summary>
|
||||
public partial class RadzenBreadCrumbItem : RadzenComponent
|
||||
{
|
||||
/// <summary>
|
||||
/// Cascaded Template Parameter from <see cref="RadzenBreadCrumb"/> Component
|
||||
/// </summary>
|
||||
[CascadingParameter]
|
||||
public RenderFragment<RadzenBreadCrumbItem> Template { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The Displayed Text
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
public string Text { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// An optional Link to be rendendered
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
public string Path { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// An optional Icon to be rendered
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
public string Icon { 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()
|
||||
{
|
||||
return "rz-breadcrumb-item";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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">@((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>
|
||||
}
|
||||
|
||||
@@ -17,7 +17,7 @@ namespace Radzen.Blazor
|
||||
{
|
||||
private string getButtonSize()
|
||||
{
|
||||
return Size == ButtonSize.Medium ? "md" : "sm";
|
||||
return Size == ButtonSize.Medium ? "md" : Size == ButtonSize.Large ? "lg" : Size == ButtonSize.Small ? "sm" : "xs";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -62,6 +62,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>
|
||||
@@ -131,7 +145,7 @@ namespace Radzen.Blazor
|
||||
/// <inheritdoc />
|
||||
protected override string GetComponentCssClass()
|
||||
{
|
||||
return $"rz-button rz-button-{getButtonSize()} btn-{Enum.GetName(typeof(ButtonStyle), ButtonStyle).ToLower()}{(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" : "")}";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@ namespace Radzen.Blazor
|
||||
/// <inheritdoc />
|
||||
protected override string GetComponentCssClass()
|
||||
{
|
||||
return "rz-card card";
|
||||
return "rz-card";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -47,6 +47,11 @@ namespace Radzen.Blazor
|
||||
[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;
|
||||
@@ -296,21 +297,39 @@ namespace Radzen.Blazor
|
||||
{
|
||||
if (Tooltip.Visible)
|
||||
{
|
||||
foreach (var series in Series)
|
||||
{
|
||||
if (series.Visible && series.Contains(mouseX - MarginLeft, mouseY - MarginTop, 25))
|
||||
{
|
||||
var data = series.DataAt(mouseX - MarginLeft, mouseY - MarginTop);
|
||||
var orderedSeries = Series.OrderBy(s => s.RenderingOrder).Reverse();
|
||||
|
||||
if (data != tooltipData)
|
||||
foreach (var series in orderedSeries)
|
||||
{
|
||||
if (series.Visible)
|
||||
{
|
||||
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, 25))
|
||||
{
|
||||
tooltipData = null;
|
||||
tooltip = overlay.RenderTooltip(mouseX, mouseY, MarginLeft, MarginTop);
|
||||
chartTooltipContainer.Refresh();
|
||||
await Task.Yield();
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
if (series.Contains(mouseX - MarginLeft, mouseY - MarginTop, 25))
|
||||
{
|
||||
var data = series.DataAt(mouseX - MarginLeft, mouseY - MarginTop);
|
||||
|
||||
if (data != tooltipData)
|
||||
{
|
||||
tooltipData = data;
|
||||
tooltip = series.RenderTooltip(data, MarginLeft, MarginTop);
|
||||
chartTooltipContainer.Refresh();
|
||||
await Task.Yield();
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -319,7 +338,7 @@ namespace Radzen.Blazor
|
||||
tooltipData = null;
|
||||
tooltip = null;
|
||||
|
||||
StateHasChanged();
|
||||
chartTooltipContainer.Refresh();
|
||||
await Task.Yield();
|
||||
}
|
||||
}
|
||||
@@ -466,7 +485,7 @@ namespace Radzen.Blazor
|
||||
/// <inheritdoc />
|
||||
protected override string GetComponentCssClass()
|
||||
{
|
||||
return $"rz-chart rz-scheme-{ColorScheme.ToString().ToLower()}";
|
||||
return $"rz-chart rz-scheme-{ColorScheme.ToString().ToLowerInvariant()}";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,13 +5,12 @@
|
||||
@inherits FormComponent<TValue>
|
||||
@if (Visible)
|
||||
{
|
||||
<div @ref="@Element" @attributes="Attributes" class="@GetCssClass()" @onmouseup=@Toggle @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 ? "-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">
|
||||
</div>
|
||||
<div class=@BoxClassList>
|
||||
<div class=@BoxClassList @onclick=@Toggle @onclick:preventDefault>
|
||||
<span class=@IconClassList></span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -15,10 +15,17 @@
|
||||
@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 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 || item.Disabled ? "-1" : $"{TabIndex}")">
|
||||
<div class="rz-helper-hidden-accessible">
|
||||
<input type="checkbox" name="@Name" value="@item.Value" disabled="@Disabled" tabindex="-1">
|
||||
</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;
|
||||
@@ -59,6 +60,59 @@ namespace Radzen.Blazor
|
||||
}
|
||||
}
|
||||
|
||||
/// <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)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (value == true)
|
||||
{
|
||||
Value = items.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 = items.All(predicate);
|
||||
var any = items.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.
|
||||
@@ -137,7 +191,10 @@ namespace Radzen.Blazor
|
||||
if (items.Contains(item))
|
||||
{
|
||||
items.Remove(item);
|
||||
try { InvokeAsync(StateHasChanged); } catch { }
|
||||
if (!disposed)
|
||||
{
|
||||
try { InvokeAsync(StateHasChanged); } catch { }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -70,5 +70,20 @@ namespace Radzen.Blazor
|
||||
{
|
||||
Value = value;
|
||||
}
|
||||
internal string GetItemId()
|
||||
{
|
||||
return GetId();
|
||||
}
|
||||
|
||||
internal string GetItemCssClass()
|
||||
{
|
||||
return GetCssClass();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override string GetComponentCssClass()
|
||||
{
|
||||
return "rz-checkbox";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
}
|
||||
<div class="rz-colorpicker-value" style="background-color: @Color" ></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=@Close Open=@Open>
|
||||
@if (ShowHSV)
|
||||
{
|
||||
<Draggable class="rz-saturation-picker rz-colorpicker-section" style=@($"background-color: {HSV.ToRGB().ToCSS()}") Drag=@OnSaturationMove>
|
||||
|
||||
@@ -321,6 +321,13 @@ namespace Radzen.Blazor
|
||||
[Parameter]
|
||||
public RenderFragment ChildContent { 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; }
|
||||
double HueHandleLeft { get; set; }
|
||||
double AlphaHandleLeft { get; set; } = 1;
|
||||
@@ -359,7 +366,8 @@ namespace Radzen.Blazor
|
||||
void Init()
|
||||
{
|
||||
var value = Value;
|
||||
if (String.IsNullOrEmpty(Value))
|
||||
|
||||
if (String.IsNullOrEmpty(Value) || RGB.Parse(Value) == null)
|
||||
{
|
||||
value = "rgb(255, 255, 255)";
|
||||
}
|
||||
|
||||
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;
|
||||
@@ -91,13 +92,42 @@ namespace Radzen.Blazor
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override string TooltipStyle(TItem item)
|
||||
{
|
||||
var style = base.TooltipStyle(item);
|
||||
|
||||
var index = Items.IndexOf(item);
|
||||
|
||||
if (index >= 0)
|
||||
{
|
||||
var color = PickColor(index, Fills, Fill);
|
||||
|
||||
if (color != null)
|
||||
{
|
||||
style = $"{style}; border-color: {color};";
|
||||
}
|
||||
}
|
||||
|
||||
return style;
|
||||
}
|
||||
|
||||
private double BandWidth
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -108,7 +138,7 @@ namespace Radzen.Blazor
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override double TooltipX(TItem item)
|
||||
internal override double TooltipX(TItem item)
|
||||
{
|
||||
var columnSeries = VisibleColumnSeries;
|
||||
var index = columnSeries.IndexOf(this);
|
||||
@@ -122,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);
|
||||
@@ -143,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)
|
||||
{
|
||||
@@ -161,5 +191,11 @@ namespace Radzen.Blazor
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override IEnumerable<ChartDataLabel> GetDataLabels(double offsetX, double offsetY)
|
||||
{
|
||||
return base.GetDataLabels(offsetX, offsetY - 16);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -286,11 +286,15 @@ namespace Radzen
|
||||
}
|
||||
}
|
||||
|
||||
internal bool disposed = false;
|
||||
|
||||
/// <summary>
|
||||
/// Detaches event handlers and disposes <see cref="Reference" />.
|
||||
/// </summary>
|
||||
public virtual void Dispose()
|
||||
{
|
||||
disposed = true;
|
||||
|
||||
reference?.Dispose();
|
||||
reference = null;
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
else if (menu.Options.Items != null && menu.Options.Items.Any())
|
||||
{
|
||||
<div class="rz-context-menu">
|
||||
<RadzenMenu Click="@(args => { if (menu.Options.Click != null) { menu.Options.Click(args); } })">
|
||||
<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>
|
||||
|
||||
@@ -35,7 +35,7 @@ namespace Radzen.Blazor
|
||||
/// }
|
||||
/// </code>
|
||||
/// </example>
|
||||
public partial class RadzenContextMenu
|
||||
public partial class RadzenContextMenu : IDisposable
|
||||
{
|
||||
/// <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,9 +117,21 @@ namespace Radzen.Blazor
|
||||
await InvokeAsync(() => { StateHasChanged(); });
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Closes this instance.
|
||||
/// </summary>
|
||||
[JSInvokable("RadzenContextMenu.CloseMenu")]
|
||||
public void CloseMenu()
|
||||
{
|
||||
Service.Close();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void Dispose()
|
||||
{
|
||||
reference?.Dispose();
|
||||
reference = null;
|
||||
|
||||
if (IsJSRuntimeAvailable)
|
||||
{
|
||||
JSRuntime.InvokeVoidAsync("Radzen.destroyPopup", UniqueID);
|
||||
|
||||
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">
|
||||
<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" 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 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>
|
||||
}
|
||||
378
Radzen.Blazor/RadzenDataFilter.razor.cs
Normal file
378
Radzen.Blazor/RadzenDataFilter.razor.cs
Normal file
@@ -0,0 +1,378 @@
|
||||
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";
|
||||
|
||||
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 (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>();
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
258
Radzen.Blazor/RadzenDataFilterItem.razor
Normal file
258
Radzen.Blazor/RadzenDataFilterItem.razor
Normal file
@@ -0,0 +1,258 @@
|
||||
@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)" ValueProperty="Property" TValue="string" Change="@OnPropertyChange">
|
||||
<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" />
|
||||
@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 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 @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 TriState="true" TValue="@object" @bind-Value=@Filter.FilterValue Change=@(args => InvokeAsync(ApplyFilter)) class="rz-datafilter-check" />
|
||||
}
|
||||
else
|
||||
{
|
||||
<RadzenTextBox 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)
|
||||
{
|
||||
property = (Filter.Property != null ? DataFilter.properties
|
||||
.Where(c => object.Equals(c.Property, Filter.Property)) : DataFilter.properties).FirstOrDefault();
|
||||
|
||||
if (property != null)
|
||||
{
|
||||
property.FilterValueChange -= OnFilterValueChange;
|
||||
property.FilterValueChange += OnFilterValueChange;
|
||||
|
||||
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 = DataFilter.properties.Where(c => object.Equals(c.Property, p)).FirstOrDefault();
|
||||
|
||||
property.FilterValueChange += OnFilterValueChange;
|
||||
|
||||
Filter.FilterValue = null;
|
||||
|
||||
var defaultOperator = typeof(System.Collections.IEnumerable).IsAssignableFrom(property.FilterPropertyType) ? FilterOperator.Contains : default(FilterOperator);
|
||||
Filter.FilterOperator = property.GetFilterOperators().Contains(defaultOperator) ? defaultOperator : property.GetFilterOperators().FirstOrDefault();
|
||||
|
||||
await ApplyFilter();
|
||||
}
|
||||
|
||||
async Task OnOperatorChange(object p)
|
||||
{
|
||||
await ApplyFilter();
|
||||
}
|
||||
|
||||
async Task AddFilter(bool isGroup)
|
||||
{
|
||||
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()
|
||||
{
|
||||
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");
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
405
Radzen.Blazor/RadzenDataFilterProperty.cs
Normal file
405
Radzen.Blazor/RadzenDataFilterProperty.cs
Normal file
@@ -0,0 +1,405 @@
|
||||
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 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;
|
||||
LogicalFilterOperator? logicalFilterOperator;
|
||||
|
||||
/// <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 => {
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -14,40 +14,59 @@
|
||||
|
||||
@if (Visible)
|
||||
{
|
||||
var visibleColumns = columns.Where(c => c.Visible).ToList();
|
||||
var visibleColumns = columns.Where(c => c.GetVisible()).ToList();
|
||||
|
||||
<div @ref=@Element style="@Style" @attributes="Attributes" class="rz-data-grid @GetCssClass()" id="@GetId()">
|
||||
@if(AllowGrouping)
|
||||
@if(AllowGrouping || AllowColumnPicking)
|
||||
{
|
||||
<div class="rz-group-header" @onmouseup=@(args => EndColumnDropToGroup())>
|
||||
@if(groups.Any())
|
||||
{
|
||||
@foreach(var gd in groups)
|
||||
@if(AllowGrouping)
|
||||
{
|
||||
<div class="rz-group-header-item">
|
||||
<span class="rz-group-header-item-title">@gd.GetTitle()</span>
|
||||
<a href="javascript:void(0)" @onclick=@(args => { groups.Remove(gd); _groupedPagedView = null; }) role="button" class="rz-dialog-titlebar-icon rz-dialog-titlebar-close">
|
||||
<span class="rzi rzi-times"></span>
|
||||
</a>
|
||||
@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=@(async args => await RemoveGroupAsync(gd)) role="button" class="rz-dialog-titlebar-icon rz-dialog-titlebar-close">
|
||||
<span class="rzi rzi-times"></span>
|
||||
</a>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
}
|
||||
else
|
||||
{
|
||||
<div class="rz-group-header-drop">@GroupPanelText</div>
|
||||
}
|
||||
}
|
||||
|
||||
@if(AllowColumnPicking)
|
||||
{
|
||||
<div class="rz-column-picker">
|
||||
<RadzenDropDown SelectAllText="@AllColumnsText" AllowSelectAll="@AllowPickAllColumns"
|
||||
MaxSelectedLabels="2"
|
||||
SelectedItemsText="@ColumnsShowingText" Change=@ToggleColumns
|
||||
@bind-Value="@selectedColumns"
|
||||
Multiple="true"
|
||||
Placeholder="@ColumnsText"
|
||||
Data="allPickableColumns"
|
||||
TextProperty="Title" />
|
||||
</div>
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
<div class="rz-group-header-drop">@GroupPanelText</div>
|
||||
}
|
||||
</div>
|
||||
}
|
||||
|
||||
@if (AllowPaging && (PagerPosition == PagerPosition.Top || PagerPosition == PagerPosition.TopAndBottom))
|
||||
{
|
||||
<RadzenPager @ref="topPager" Count="@Count" PageSize="@PageSize" PageNumbersCount="@PageNumbersCount" PageChanged="@OnPageChanged" PageSizeChanged="@OnPageSizeChanged" PageSizeOptions="@PageSizeOptions" ShowPagingSummary="@ShowPagingSummary" PagingSummaryFormat="@PagingSummaryFormat" />
|
||||
<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" />
|
||||
}
|
||||
|
||||
<div class="rz-data-grid-data">
|
||||
<table class="rz-grid-table rz-grid-table-fixed">
|
||||
<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)
|
||||
@foreach(var g in Groups)
|
||||
{
|
||||
<col>
|
||||
}
|
||||
@@ -61,154 +80,61 @@
|
||||
}
|
||||
</colgroup>
|
||||
<thead>
|
||||
@for(var i = 0; i < deepestChildColumnLevel + 1; i++)
|
||||
{
|
||||
<tr>
|
||||
@foreach(var g in groups)
|
||||
@foreach(var g in Groups)
|
||||
{
|
||||
<th class="rz-col-icon rz-unselectable-text" scope="col">
|
||||
<th class="rz-col-icon rz-unselectable-text" scope="col" rowspan=@(deepestChildColumnLevel + 1)>
|
||||
<span class="rz-column-title"></span>
|
||||
</th>
|
||||
}
|
||||
@if (Template != null && ShowExpandColumn)
|
||||
@if (Template != null && ShowExpandColumn && i == 0)
|
||||
{
|
||||
<th class="rz-col-icon rz-unselectable-text" scope="col">
|
||||
<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)
|
||||
@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)
|
||||
{
|
||||
j = j + (int)Convert.ChangeType(colspan, TypeCode.Int32) - 1;
|
||||
}
|
||||
|
||||
var columnIndex = visibleColumns.IndexOf(column);
|
||||
var sortableClass = AllowSorting && column.Sortable ? "rz-sortable-column" : "";
|
||||
<th class="@($"rz-unselectable-text {sortableClass} {column.HeaderCssClass} {getFrozenColumnClass(column, visibleColumns)}")" scope="col" style="@column.GetStyle(true, true)" @onmouseup=@(args => EndColumnReorder(args, columnIndex))>
|
||||
<div @onclick='@((args) => OnSort(args, column))' style="width:100%">
|
||||
@if (AllowColumnReorder && column.Reorderable || AllowGrouping && column.Groupable)
|
||||
{
|
||||
<span id="@getColumnResizerId(columnIndex)" class="rz-column-drag"
|
||||
@onclick:preventDefault="true" @onclick:stopPropagation="true"
|
||||
@onmousedown=@(args => StartColumnReorder(args, columnIndex))> </span>
|
||||
}
|
||||
<span class="rz-column-title">
|
||||
@if (column.HeaderTemplate != null)
|
||||
{
|
||||
@column.HeaderTemplate
|
||||
}
|
||||
else
|
||||
{
|
||||
@column.Title
|
||||
}
|
||||
</span>
|
||||
@if (AllowSorting && column.Sortable)
|
||||
{
|
||||
@if (column.GetSortOrder() == SortOrder.Ascending)
|
||||
{
|
||||
<span class="rz-sortable-column-icon rzi-grid-sort rzi-sort rzi-sort-asc"></span>
|
||||
}
|
||||
else if (column.GetSortOrder() == SortOrder.Descending)
|
||||
{
|
||||
<span class="rz-sortable-column-icon rzi-grid-sort rzi-sort rzi-sort-desc"></span>
|
||||
}
|
||||
else
|
||||
{
|
||||
<span class="rz-sortable-column-icon rzi-grid-sort rzi-sort"></span>
|
||||
}
|
||||
}
|
||||
@if (AllowColumnResize && column.Resizable)
|
||||
{
|
||||
<div id="@getColumnResizerId(columnIndex)" style="cursor:col-resize;float:right;"
|
||||
@onclick:preventDefault="true" @onclick:stopPropagation="true" class="rz-column-resizer"
|
||||
@onmousedown=@(args => StartColumnResize(args, columnIndex))> </div>
|
||||
}
|
||||
@if (AllowFiltering && column.Filterable && FilterMode == FilterMode.Advanced)
|
||||
{
|
||||
<i @onclick:stopPropagation="true" onclick="@($"Radzen.togglePopup(this, '{PopupID}{column.GetFilterProperty()}')")"
|
||||
class="@getFilterIconCss(column)" />
|
||||
|
||||
<div id="@($"{PopupID}{column.GetFilterProperty()}")" class="rz-overlaypanel"
|
||||
style="display:none;min-width:250px;" tabindex="0">
|
||||
<div class="rz-grid-filter rz-overlaypanel-content">
|
||||
@if (column.FilterTemplate != null)
|
||||
{
|
||||
@column.FilterTemplate(column)
|
||||
}
|
||||
else
|
||||
{
|
||||
<RadzenLabel Text="@FilterText" class="rz-grid-filter-label" />
|
||||
<RadzenDropDown @onclick:preventDefault="true" Data="@(column.GetFilterOperators().Select(t => new { Value = column.GetFilterOperatorText(t), Key = t }))" TextProperty="Value" ValueProperty="Key" TValue="FilterOperator" Value="@column.GetFilterOperator()" Change="@(args => column.SetFilterOperator((FilterOperator)args))" />
|
||||
@if (PropertyAccess.IsNumeric(column.FilterPropertyType))
|
||||
{
|
||||
@(DrawNumericFilter(column, false))
|
||||
}
|
||||
else if (PropertyAccess.IsDate(column.FilterPropertyType))
|
||||
{
|
||||
<RadzenDatePicker TValue="@object" ShowTime="true" ShowTimeOkButton="true" DateFormat="@getFilterDateFormat(column)"
|
||||
Value="@column.GetFilterValue()" Change="@(args => column.SetFilterValue(args.Value))" />
|
||||
|
||||
}
|
||||
else if (column.FilterPropertyType == typeof(bool) || column.FilterPropertyType == typeof(bool?))
|
||||
{
|
||||
<RadzenCheckBox TriState="true" TValue="@object" Value="@column.GetFilterValue()" Change="@(args => column.SetFilterValue(args))" />
|
||||
}
|
||||
else
|
||||
{
|
||||
<RadzenTextBox Value="@($"{column.GetFilterValue()}")" Change="@(args => column.SetFilterValue(args))" />
|
||||
}
|
||||
|
||||
<RadzenDropDown @onclick:preventDefault="true" TextProperty="Text" ValueProperty="Value" Style="width: 80px"
|
||||
Data="@(Enum.GetValues(typeof(LogicalFilterOperator)).Cast<LogicalFilterOperator>().Select(t => new { Text = t == LogicalFilterOperator.And ? AndOperatorText : OrOperatorText, Value = t }))" TValue="LogicalFilterOperator" Value="@column.LogicalFilterOperator" Change="@(args => column.SetLogicalFilterOperator((LogicalFilterOperator)args))" />
|
||||
|
||||
<RadzenDropDown @onclick:preventDefault="true" Data="@(column.GetFilterOperators().Select(t => new { Value = column.GetFilterOperatorText(t), Key = t }))" TextProperty="Value" ValueProperty="Key" TValue="FilterOperator" Value="@column.GetSecondFilterOperator()" Change="@(args => column.SetSecondFilterOperator((FilterOperator)args))" />
|
||||
@if (PropertyAccess.IsNumeric(column.FilterPropertyType))
|
||||
{
|
||||
@(DrawNumericFilter(column, false, false))
|
||||
}
|
||||
else if (PropertyAccess.IsDate(column.FilterPropertyType))
|
||||
{
|
||||
<RadzenDatePicker TValue="@object"
|
||||
ShowTime="true" ShowTimeOkButton="true" DateFormat="@getFilterDateFormat(column)"
|
||||
Value="@column.GetSecondFilterValue()" Change="@(args => column.SetFilterValue(args.Value, false))" />
|
||||
|
||||
}
|
||||
else if (column.FilterPropertyType == typeof(bool) || column.FilterPropertyType == typeof(bool?))
|
||||
{
|
||||
<RadzenCheckBox TriState="true" TValue="@object" Value="@column.GetSecondFilterValue()" Change="@(args => column.SetFilterValue(args, false))"/>
|
||||
}
|
||||
else
|
||||
{
|
||||
<RadzenTextBox Value="@($"{column.GetSecondFilterValue()}")" Change="@(args => column.SetFilterValue(args, false))" />
|
||||
}
|
||||
}
|
||||
</div>
|
||||
@if (column.FilterTemplate == null)
|
||||
{
|
||||
<div class="rz-grid-filter-buttons">
|
||||
<RadzenButton ButtonStyle="ButtonStyle.Secondary" Text=@ClearFilterText Click="@((args) => ClearFilter(column, true))" />
|
||||
<RadzenButton ButtonStyle="ButtonStyle.Primary" Text=@ApplyFilterText Click="@((args) => ApplyFilter(column, true))" />
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
</th>
|
||||
<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 && columns.Where(column => column.Filterable && (!string.IsNullOrEmpty(column.GetFilterProperty()) || column.FilterTemplate != null)).Any())
|
||||
}
|
||||
@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)
|
||||
@foreach(var g in Groups)
|
||||
{
|
||||
<th class="rz-col-icon rz-unselectable-text" scope="col">
|
||||
<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">
|
||||
<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 class="@($" rz-unselectable-text")" tabindex="1" scope="col" style="@column.GetStyle(true, true)">
|
||||
@if (AllowFiltering && column.Filterable && (!string.IsNullOrEmpty(column.GetFilterProperty()) || column.FilterTemplate != null))
|
||||
<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">
|
||||
@@ -219,72 +145,130 @@
|
||||
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?))
|
||||
@if (PropertyAccess.IsDate(column.FilterPropertyType))
|
||||
{
|
||||
<i onclick="@($"Radzen.togglePopup(this.parentNode, '{PopupID}{column.GetFilterProperty()}')")"
|
||||
class="rzi">date_range</i>
|
||||
@if (column.GetFilterValue() != null)
|
||||
{
|
||||
<span class="rz-current-filter">@column.GetFilterValue()</span>
|
||||
<i @onclick="@((args) => ClearFilter(column))" class="rzi rz-cell-filter-clear">close</i>
|
||||
}
|
||||
<div id="@($"{PopupID}{column.GetFilterProperty()}")" class="rz-overlaypanel"
|
||||
if (FilterMode == FilterMode.Simple)
|
||||
{
|
||||
<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 && 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>
|
||||
}
|
||||
<div id="@($"{PopupID}{column.GetFilterProperty()}")" class="rz-overlaypanel"
|
||||
style="display:none;width:550px;" tabindex="0">
|
||||
<div class="rz-overlaypanel-content">
|
||||
<div class="rz-overlaypanel-content">
|
||||
|
||||
<div class="rz-date-filter">
|
||||
<div class="rz-date-filter">
|
||||
|
||||
<div class="rz-listbox rz-inputtext ">
|
||||
<div class="rz-listbox-list-wrapper">
|
||||
<ul class="rz-listbox-list">
|
||||
@if (column.GetFilterOperators().Contains(FilterOperator.Equals))
|
||||
{
|
||||
<li class="@(DateFilterOperatorStyle(column, FilterOperator.Equals))" @onclick="@((args) => ApplyDateFilterByFilterOperator(column, FilterOperator.Equals))" style="display: block;">
|
||||
<span>@EqualsText</span>
|
||||
</li>
|
||||
}
|
||||
@if (column.GetFilterOperators().Contains(FilterOperator.NotEquals))
|
||||
{
|
||||
<li class="@(DateFilterOperatorStyle(column, FilterOperator.NotEquals))" @onclick="@((args) => ApplyDateFilterByFilterOperator(column, FilterOperator.NotEquals))" style="display: block;">
|
||||
<span>@NotEqualsText</span>
|
||||
</li>
|
||||
}
|
||||
@if (column.GetFilterOperators().Contains(FilterOperator.LessThan))
|
||||
{
|
||||
<li class="@(DateFilterOperatorStyle(column, FilterOperator.LessThan))" @onclick="@((args) => ApplyDateFilterByFilterOperator(column, FilterOperator.LessThan))" style="display: block;">
|
||||
<span>@LessThanText</span>
|
||||
</li>
|
||||
}
|
||||
@if (column.GetFilterOperators().Contains(FilterOperator.LessThanOrEquals))
|
||||
{
|
||||
<li class="@(DateFilterOperatorStyle(column, FilterOperator.LessThanOrEquals))" @onclick="@((args) => ApplyDateFilterByFilterOperator(column, FilterOperator.LessThanOrEquals))" style="display: block;">
|
||||
<span>@LessThanOrEqualsText</span>
|
||||
</li>
|
||||
}
|
||||
@if (column.GetFilterOperators().Contains(FilterOperator.GreaterThan))
|
||||
{
|
||||
<li class="@(DateFilterOperatorStyle(column, FilterOperator.GreaterThan))" @onclick="@((args) => ApplyDateFilterByFilterOperator(column, FilterOperator.GreaterThan))" style="display: block;">
|
||||
<span>@GreaterThanText</span>
|
||||
</li>
|
||||
}
|
||||
@if (column.GetFilterOperators().Contains(FilterOperator.GreaterThanOrEquals))
|
||||
{
|
||||
<li class="@(DateFilterOperatorStyle(column, FilterOperator.GreaterThanOrEquals))" @onclick="@((args) => ApplyDateFilterByFilterOperator(column, FilterOperator.GreaterThanOrEquals))" style="display: block;">
|
||||
<span>@GreaterThanOrEqualsText</span>
|
||||
</li>
|
||||
}
|
||||
@if (column.GetFilterOperators().Contains(FilterOperator.IsEmpty))
|
||||
{
|
||||
<li class="@(DateFilterOperatorStyle(column, FilterOperator.IsEmpty))" @onclick="@((args) => ApplyDateFilterByFilterOperator(column, FilterOperator.IsEmpty))" style="display: block;">
|
||||
<span>@IsEmptyText</span>
|
||||
</li>
|
||||
}
|
||||
@if (column.GetFilterOperators().Contains(FilterOperator.IsNotEmpty))
|
||||
{
|
||||
<li class="@(DateFilterOperatorStyle(column, FilterOperator.IsNotEmpty))" @onclick="@((args) => ApplyDateFilterByFilterOperator(column, FilterOperator.IsNotEmpty))" style="display: block;">
|
||||
<span>@IsNotEmptyText</span>
|
||||
</li>
|
||||
}
|
||||
@if (column.GetFilterOperators().Contains(FilterOperator.IsNull))
|
||||
{
|
||||
<li class="@(DateFilterOperatorStyle(column, FilterOperator.IsNull))" @onclick="@((args) => ApplyDateFilterByFilterOperator(column, FilterOperator.IsNull))" style="display: block;">
|
||||
<span>@IsNullText</span>
|
||||
</li>
|
||||
}
|
||||
@if (column.GetFilterOperators().Contains(FilterOperator.IsNotNull))
|
||||
{
|
||||
<li class="@(DateFilterOperatorStyle(column, FilterOperator.IsNotNull))" @onclick="@((args) => ApplyDateFilterByFilterOperator(column, FilterOperator.IsNotNull))" style="display: block;">
|
||||
<span>@IsNotNullText</span>
|
||||
</li>
|
||||
}
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<RadzenDatePicker TValue="@object" AllowInput=@(AllowFilterDateInput)
|
||||
ShowTime="@column.ShowTimeForDateTimeFilter()" ShowTimeOkButton="false" Inline="true" DateFormat="@getFilterDateFormat(column)"
|
||||
Value="@column.GetFilterValue()" Change="@(args => { column.SetFilterValue(args.Value); SaveSettings(); })" />
|
||||
|
||||
<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>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="rz-date-filter-buttons">
|
||||
<button class="rz-button rz-clear-filter" @onclick="@((args) => ClearFilter(column, true))">
|
||||
@ClearFilterText
|
||||
</button>
|
||||
<button class="rz-button rz-apply-filter" @onclick="@((args) => ApplyFilter(column, true))">
|
||||
@ApplyFilterText
|
||||
</button>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<RadzenDatePicker TValue="@object"
|
||||
ShowTime="true" ShowTimeOkButton="false" Inline="true" DateFormat="@getFilterDateFormat(column)"
|
||||
Value="@column.GetFilterValue()" Change="@(args => column.SetFilterValue(args.Value))" />
|
||||
|
||||
</div>
|
||||
<div class="rz-date-filter-buttons">
|
||||
<button class="rz-button rz-clear-filter" @onclick="@((args) => ClearFilter(column, true))">
|
||||
@ClearFilterText
|
||||
</button>
|
||||
<button class="rz-button rz-apply-filter" @onclick="@((args) => ApplyFilter(column, true))">
|
||||
@ApplyFilterText
|
||||
</button>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
else
|
||||
{
|
||||
<RadzenDataGridFilterMenu Grid="@this" Column="@column" />
|
||||
<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) { ClearFilter(column, true); } else {column.SetFilterValue(args.Value); ApplyFilter(column, true);} })" />
|
||||
}
|
||||
}
|
||||
else if (PropertyAccess.IsNullableEnum(column.FilterPropertyType) || PropertyAccess.IsEnum(column.FilterPropertyType))
|
||||
{
|
||||
<RadzenDropDown Style="width:100%" AllowClear="true" AllowFiltering="false" TValue="@object"
|
||||
Value=@column.GetFilterValue() Multiple="false" Placeholder="@EnumFilterSelectText" TextProperty="Text" ValueProperty="Value"
|
||||
Data=@((PropertyAccess.IsNullableEnum(column.FilterPropertyType) ? new object[]{ new { Value = -1, Text = "<null>"}} : 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);ApplyFilter(column, true);})" />
|
||||
}
|
||||
else if (PropertyAccess.IsNumeric(column.FilterPropertyType))
|
||||
{
|
||||
<i class="rzi">search</i>
|
||||
if(FilterMode == FilterMode.SimpleWithMenu)
|
||||
{
|
||||
<RadzenDataGridFilterMenu Grid="@this" Column="@column" />
|
||||
}
|
||||
@(DrawNumericFilter(column))
|
||||
}
|
||||
else if (column.FilterPropertyType == typeof(bool) || column.FilterPropertyType == typeof(bool?))
|
||||
@@ -295,8 +279,15 @@
|
||||
}
|
||||
else
|
||||
{
|
||||
<i class="rzi">search</i>
|
||||
<input id="@(getFilterInputId(column))" @onchange="@((args) => OnFilter(args, column))" @onkeydown="@((args) => OnFilterKeyPress(args, column))" value="@column.GetFilterValue()" type="text" />
|
||||
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" 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>
|
||||
}
|
||||
@@ -311,21 +302,24 @@
|
||||
<tbody>
|
||||
@if (Data != null)
|
||||
{
|
||||
@if (Count > 0 && columns.Count > 0)
|
||||
@if (!ShowEmptyMessage || Count > 0 && (IsVirtualizationAllowed() ? Data.Any() : true) || !AllowPaging && LoadData.HasDelegate && Count == 0)
|
||||
{
|
||||
@DrawRows(visibleColumns)
|
||||
if (columns.Count > 0)
|
||||
{
|
||||
@DrawRows(visibleColumns)
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
<tr class=" rz-datatable-emptymessage-row">
|
||||
<td class="rz-datatable-emptymessage" colspan="@(visibleColumns.Count + (Template != null && ShowExpandColumn ? 1 : 0))">
|
||||
<td class="rz-datatable-emptymessage" colspan="@(visibleColumns.Sum(c => c.GetColSpan()) + (Template != null && ShowExpandColumn ? 1 : 0))">
|
||||
@if (EmptyTemplate != null)
|
||||
{
|
||||
@EmptyTemplate
|
||||
}
|
||||
else
|
||||
{
|
||||
<span>@EmptyText</span>
|
||||
<span style="white-space: normal">@EmptyText</span>
|
||||
}
|
||||
</td>
|
||||
</tr>
|
||||
@@ -335,31 +329,40 @@
|
||||
@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)
|
||||
@foreach(var g in Groups)
|
||||
{
|
||||
<td class="rz-col-icon rz-unselectable-text" scope="col">
|
||||
<td class="rz-col-icon rz-unselectable-text" scope="col" rowspan=@(deepestChildColumnLevel + 1)>
|
||||
<span class="rz-column-title"></span>
|
||||
</td>
|
||||
}
|
||||
@if (Template != null && ShowExpandColumn)
|
||||
@if (Template != null && ShowExpandColumn && i == 0)
|
||||
{
|
||||
<td class="rz-col-icon rz-unselectable-text" scope="col">
|
||||
<td class="rz-col-icon rz-unselectable-text" scope="col" rowspan=@(deepestChildColumnLevel + 1)>
|
||||
<span class="rz-column-title"></span>
|
||||
</td>
|
||||
}
|
||||
@foreach (var column in visibleColumns)
|
||||
@for (var j = 0; j < visibleColumns.Count; j++)
|
||||
{
|
||||
<td class="@($" {column.FooterCssClass} {getFrozenColumnClass(column, visibleColumns)}")" style="@column.GetStyle(true, true)">
|
||||
<span class="rz-column-footer">
|
||||
@if (column.FooterTemplate != null)
|
||||
{
|
||||
@column.FooterTemplate
|
||||
}
|
||||
</span>
|
||||
</td>
|
||||
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>
|
||||
@@ -375,7 +378,7 @@
|
||||
|
||||
@if (AllowPaging && (PagerPosition == PagerPosition.Bottom || PagerPosition == PagerPosition.TopAndBottom))
|
||||
{
|
||||
<RadzenPager @ref="bottomPager" Count="@Count" PageSize="@PageSize" PageNumbersCount="@PageNumbersCount" PageChanged="@OnPageChanged" PageSizeChanged="@OnPageSizeChanged" PageSizeOptions="@PageSizeOptions" ShowPagingSummary="@ShowPagingSummary" PagingSummaryFormat="@PagingSummaryFormat" />
|
||||
<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" />
|
||||
}
|
||||
</div>
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,13 +1,69 @@
|
||||
@typeparam TItem
|
||||
<td @attributes="@Attributes" style="@GetStyle()" class="@GetCssClass()" @onclick="@OnClick" @ondblclick="@OnDblClick" @oncontextmenu="@OnContextMenu" @oncontextmenu:preventDefault="@Grid.CellContextMenu.HasDelegate">
|
||||
@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) + " " + Grid.getCompositeCellCSSClass(column))" 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 && Grid.ShowCellDataAsTooltip ? 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; }
|
||||
|
||||
@@ -30,7 +86,7 @@
|
||||
{
|
||||
if (Grid != null)
|
||||
{
|
||||
#if NET5
|
||||
#if NET5_0_OR_GREATER
|
||||
await Grid.OnCellContextMenu(new DataGridCellMouseEventArgs<TItem>
|
||||
{
|
||||
Data = Item,
|
||||
@@ -72,12 +128,58 @@
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool clicking;
|
||||
async Task OnClick(MouseEventArgs args)
|
||||
{
|
||||
if (clicking)
|
||||
{
|
||||
return;
|
||||
}
|
||||
try
|
||||
{
|
||||
clicking = true;
|
||||
if (Grid != null)
|
||||
{
|
||||
#if NET5
|
||||
#if NET5_0_OR_GREATER
|
||||
await Grid.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 Grid.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 Grid.OnRowClick(new DataGridRowMouseEventArgs<TItem>
|
||||
{
|
||||
Data = Item,
|
||||
@@ -114,6 +216,11 @@
|
||||
Type = args.Type
|
||||
});
|
||||
#endif
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
clicking = false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -121,7 +228,46 @@
|
||||
{
|
||||
if (Grid != null)
|
||||
{
|
||||
#if NET5
|
||||
#if NET5_0_OR_GREATER
|
||||
await Grid.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 Grid.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 Grid.OnRowDblClick(new DataGridRowMouseEventArgs<TItem>
|
||||
{
|
||||
Data = Item,
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using Microsoft.AspNetCore.Components;
|
||||
using Microsoft.JSInterop;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
@@ -22,6 +23,74 @@ namespace Radzen.Blazor
|
||||
[CascadingParameter]
|
||||
public RadzenDataGrid<TItem> Grid { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the columns.
|
||||
/// </summary>
|
||||
/// <value>The columns.</value>
|
||||
[Parameter]
|
||||
public RenderFragment Columns { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the parent column.
|
||||
/// </summary>
|
||||
/// <value>The parent column.</value>
|
||||
[CascadingParameter]
|
||||
public RadzenDataGridColumn<TItem> Parent { get; set; }
|
||||
|
||||
internal void RemoveColumn(RadzenDataGridColumn<TItem> column)
|
||||
{
|
||||
if (Grid.childColumns.Contains(column))
|
||||
{
|
||||
Grid.childColumns.Remove(column);
|
||||
if (!Grid.disposed)
|
||||
{
|
||||
try { InvokeAsync(StateHasChanged); } catch { }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal int GetLevel()
|
||||
{
|
||||
int i = 0;
|
||||
var p = Parent;
|
||||
while (p != null)
|
||||
{
|
||||
p = p.Parent;
|
||||
i++;
|
||||
}
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
internal int GetColSpan(bool isDataCell = false)
|
||||
{
|
||||
if (!Grid.AllowCompositeDataCells && isDataCell)
|
||||
return 1;
|
||||
|
||||
var directChildColumns = Grid.childColumns.Where(c => c.GetVisible() && c.Parent == this);
|
||||
|
||||
if (Parent == null)
|
||||
{
|
||||
return Columns == null ? 1 : directChildColumns.Sum(c => c.GetColSpan());
|
||||
}
|
||||
|
||||
return Columns == null ? 1 : directChildColumns.Count();
|
||||
}
|
||||
|
||||
internal int GetRowSpan(bool isDataCell = false)
|
||||
{
|
||||
if (!Grid.AllowCompositeDataCells && isDataCell)
|
||||
return 1;
|
||||
|
||||
if (Columns == null && Parent != null)
|
||||
{
|
||||
var level = this.GetLevel();
|
||||
return level == Grid.deepestChildColumnLevel ? 1 : level + 1;
|
||||
}
|
||||
|
||||
return Columns == null && Parent == null ? Grid.deepestChildColumnLevel + 1 : 1;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called when initialized.
|
||||
/// </summary>
|
||||
@@ -31,16 +100,16 @@ namespace Radzen.Blazor
|
||||
{
|
||||
Grid.AddColumn(this);
|
||||
|
||||
if (!string.IsNullOrEmpty(FilterProperty) || Type == null)
|
||||
{
|
||||
var property = GetFilterProperty();
|
||||
var property = GetFilterProperty();
|
||||
|
||||
if (!string.IsNullOrEmpty(property) && Type == null)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(property))
|
||||
{
|
||||
_filterPropertyType = PropertyAccess.GetPropertyType(typeof(TItem), property);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (_filterPropertyType == null)
|
||||
{
|
||||
_filterPropertyType = Type;
|
||||
@@ -57,6 +126,25 @@ namespace Radzen.Blazor
|
||||
}
|
||||
}
|
||||
|
||||
int? orderIndex;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the order index.
|
||||
/// </summary>
|
||||
/// <value>The order index.</value>
|
||||
[Parameter]
|
||||
public int? OrderIndex { get; set; }
|
||||
|
||||
internal int? GetOrderIndex()
|
||||
{
|
||||
return orderIndex ?? OrderIndex;
|
||||
}
|
||||
|
||||
internal void SetOrderIndex(int? value)
|
||||
{
|
||||
orderIndex = value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the sort order.
|
||||
/// </summary>
|
||||
@@ -64,12 +152,53 @@ 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;
|
||||
|
||||
if (Grid != null)
|
||||
{
|
||||
Grid.UpdatePickableColumn(this, visible);
|
||||
InvokeAsync(Grid.ChangeState);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool? _visible;
|
||||
|
||||
/// <summary>
|
||||
/// Gets if the column is visible or not.
|
||||
/// </summary>
|
||||
/// <returns>System.Boolean.</returns>
|
||||
public bool GetVisible()
|
||||
{
|
||||
return _visible ?? Visible;
|
||||
}
|
||||
|
||||
internal void SetVisible(bool? value)
|
||||
{
|
||||
_visible = value;
|
||||
|
||||
if (Grid != null)
|
||||
{
|
||||
Grid.UpdatePickableColumn(this, _visible == true);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the title.
|
||||
@@ -127,6 +256,13 @@ namespace Radzen.Blazor
|
||||
[Parameter]
|
||||
public string Width { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the min-width.
|
||||
/// </summary>
|
||||
/// <value>The min-width.</value>
|
||||
[Parameter]
|
||||
public string MinWidth { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the format string.
|
||||
/// </summary>
|
||||
@@ -204,6 +340,13 @@ namespace Radzen.Blazor
|
||||
[Parameter]
|
||||
public bool Groupable { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether this <see cref="RadzenDataGridColumn{TItem}"/> is pickable - listed when DataGrid AllowColumnPicking is set to true.
|
||||
/// </summary>
|
||||
/// <value><c>true</c> if pickable; otherwise, <c>false</c>.</value>
|
||||
[Parameter]
|
||||
public bool Pickable { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the text align.
|
||||
/// </summary>
|
||||
@@ -274,11 +417,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()
|
||||
@@ -323,10 +475,11 @@ namespace Radzen.Blazor
|
||||
style.Add($"text-align:{Enum.GetName(typeof(TextAlign), TextAlign).ToLower()};");
|
||||
}
|
||||
|
||||
if (forCell && Frozen)
|
||||
if (forCell && IsFrozen())
|
||||
{
|
||||
var left = Grid.ColumnsCollection
|
||||
.TakeWhile((c, i) => Grid.ColumnsCollection.IndexOf(this) > i && c.Frozen)
|
||||
var visibleColumns = Grid.ColumnsCollection.Where(c => c.GetVisible()).ToList();
|
||||
var left = visibleColumns
|
||||
.Where((c, i) => visibleColumns.IndexOf(this) > i && c.IsFrozen())
|
||||
.Sum(c => {
|
||||
var w = !string.IsNullOrEmpty(c.GetWidth()) ? c.GetWidth() : Grid.ColumnWidth;
|
||||
var cw = 200;
|
||||
@@ -340,14 +493,24 @@ namespace Radzen.Blazor
|
||||
style.Add($"left:{left}px");
|
||||
}
|
||||
|
||||
if ((isHeaderOrFooterCell && Frozen || isHeaderOrFooterCell && !Frozen || !isHeaderOrFooterCell && Frozen) && Grid.ColumnsCollection.Where(c => c.Visible && c.Frozen).Any())
|
||||
if ((isHeaderOrFooterCell && IsFrozen() || isHeaderOrFooterCell && !IsFrozen() || !isHeaderOrFooterCell && IsFrozen()) && Grid.ColumnsCollection.Where(c => c.GetVisible() && c.IsFrozen()).Any())
|
||||
{
|
||||
style.Add($"z-index:{(isHeaderOrFooterCell && Frozen ? 2 : 1)}");
|
||||
style.Add($"z-index:{(isHeaderOrFooterCell && IsFrozen() ? 2 : 1)}");
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(MinWidth))
|
||||
{
|
||||
style.Add($"min-width:{MinWidth}");
|
||||
}
|
||||
|
||||
return string.Join(";", style);
|
||||
}
|
||||
|
||||
internal bool IsFrozen()
|
||||
{
|
||||
return Frozen && Parent == null && Columns == null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the sort property.
|
||||
/// </summary>
|
||||
@@ -374,6 +537,42 @@ 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 (GetSortOrder() == null)
|
||||
{
|
||||
SetSortOrderInternal(Radzen.SortOrder.Ascending);
|
||||
descriptor.SortOrder = Radzen.SortOrder.Ascending;
|
||||
}
|
||||
else if (GetSortOrder() == Radzen.SortOrder.Ascending)
|
||||
{
|
||||
SetSortOrderInternal(Radzen.SortOrder.Descending);
|
||||
descriptor.SortOrder = Radzen.SortOrder.Descending;
|
||||
}
|
||||
else if (GetSortOrder() == Radzen.SortOrder.Descending)
|
||||
{
|
||||
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 };
|
||||
}
|
||||
@@ -417,7 +616,10 @@ namespace Radzen.Blazor
|
||||
|
||||
Type _filterPropertyType;
|
||||
|
||||
internal Type FilterPropertyType
|
||||
/// <summary>
|
||||
/// Gets the filter property type.
|
||||
/// </summary>
|
||||
public Type FilterPropertyType
|
||||
{
|
||||
get
|
||||
{
|
||||
@@ -444,22 +646,63 @@ namespace Radzen.Blazor
|
||||
{
|
||||
if (Grid != null)
|
||||
{
|
||||
Grid.UpdatePickableColumn(this, parameters.GetValueOrDefault<bool>(nameof(Visible)));
|
||||
await Grid.ChangeState();
|
||||
}
|
||||
}
|
||||
|
||||
if (parameters.DidParameterChange(nameof(OrderIndex), OrderIndex))
|
||||
{
|
||||
var newOrderIndex = parameters.GetValueOrDefault<int?>(nameof(OrderIndex));
|
||||
if (newOrderIndex != orderIndex)
|
||||
{
|
||||
SetOrderIndex(newOrderIndex);
|
||||
|
||||
if (Grid != null)
|
||||
{
|
||||
Grid.UpdateColumnsOrder();
|
||||
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))
|
||||
{
|
||||
filterValue = parameters.GetValueOrDefault<object>(nameof(FilterValue));
|
||||
|
||||
if (FilterTemplate != null)
|
||||
{
|
||||
FilterValue = filterValue;
|
||||
await Grid.Reload();
|
||||
Grid.SaveSettings();
|
||||
if (Grid.IsVirtualizationAllowed())
|
||||
{
|
||||
#if NET5_0_OR_GREATER
|
||||
if (Grid.virtualize != null)
|
||||
{
|
||||
await Grid.virtualize.RefreshDataAsync();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
await Grid.Reload();
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -487,37 +730,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?)
|
||||
{
|
||||
@@ -535,6 +799,31 @@ namespace Radzen.Blazor
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
SetFilterOperator(null);
|
||||
SetSecondFilterOperator(null);
|
||||
|
||||
FilterValue = null;
|
||||
SecondFilterValue = null;
|
||||
FilterOperator = typeof(System.Collections.IEnumerable).IsAssignableFrom(FilterPropertyType) ? FilterOperator.Contains : default(FilterOperator);
|
||||
SecondFilterOperator = default(FilterOperator);
|
||||
LogicalFilterOperator = default(LogicalFilterOperator);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the filter operator.
|
||||
/// </summary>
|
||||
@@ -549,40 +838,85 @@ 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;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Closes this column filter popup.
|
||||
/// </summary>
|
||||
public async Task 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;
|
||||
}
|
||||
|
||||
internal string GetWidth()
|
||||
/// <summary>
|
||||
/// Get column width.
|
||||
/// </summary>
|
||||
public string GetWidth()
|
||||
{
|
||||
return !string.IsNullOrEmpty(runtimeWidth) ? runtimeWidth : Width;
|
||||
}
|
||||
|
||||
internal IEnumerable<FilterOperator> GetFilterOperators()
|
||||
/// <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;
|
||||
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;
|
||||
|| o == FilterOperator.Equals || o == FilterOperator.NotEquals
|
||||
|| o == FilterOperator.IsNull || o == FilterOperator.IsNotNull
|
||||
: !isStringOperator;
|
||||
});
|
||||
}
|
||||
|
||||
@@ -612,13 +946,64 @@ 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}";
|
||||
}
|
||||
}
|
||||
|
||||
internal string GetFilterOperatorSymbol(FilterOperator filterOperator)
|
||||
{
|
||||
var symbol = Grid.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>
|
||||
/// Gets value indicating if the user can specify time in DateTime column filter.
|
||||
/// </summary>
|
||||
public virtual bool ShowTimeForDateTimeFilter()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Disposes this instance.
|
||||
/// </summary>
|
||||
@@ -627,4 +1012,4 @@ namespace Radzen.Blazor
|
||||
Grid?.RemoveColumn(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
11
Radzen.Blazor/RadzenDataGridColumn.razor
Normal file
11
Radzen.Blazor/RadzenDataGridColumn.razor
Normal file
@@ -0,0 +1,11 @@
|
||||
@typeparam TItem
|
||||
@inherits ComponentBase
|
||||
|
||||
@if (Columns != null)
|
||||
{
|
||||
<CascadingValue Value=this.Grid>
|
||||
<CascadingValue Value=this>
|
||||
@Columns
|
||||
</CascadingValue>
|
||||
</CascadingValue>
|
||||
}
|
||||
181
Radzen.Blazor/RadzenDataGridFilterMenu.razor
Normal file
181
Radzen.Blazor/RadzenDataGridFilterMenu.razor
Normal file
@@ -0,0 +1,181 @@
|
||||
@typeparam TItem
|
||||
@using Microsoft.AspNetCore.Components.Forms
|
||||
@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>
|
||||
@if (Column.GetFilterOperator() == FilterOperator.DoesNotContain)
|
||||
{
|
||||
<s>@Column.GetFilterOperatorSymbol(Column.GetFilterOperator())</s>
|
||||
}
|
||||
else
|
||||
{
|
||||
@Column.GetFilterOperatorSymbol(Column.GetFilterOperator())
|
||||
}
|
||||
</button>
|
||||
<div id="@($"{Grid.PopupID}{Column.GetFilterProperty()}")" class="rz-overlaypanel"
|
||||
style="display:none;" tabindex="0">
|
||||
<div class="rz-overlaypanel-content">
|
||||
<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>
|
||||
@code {
|
||||
[Parameter]
|
||||
public RadzenDataGridColumn<TItem> Column { get; set; }
|
||||
|
||||
[Parameter]
|
||||
public RadzenDataGrid<TItem> Grid { get; set; }
|
||||
|
||||
protected string FilterOperatorStyle(RadzenDataGridColumn<TItem> column, FilterOperator value)
|
||||
{
|
||||
return column.GetFilterOperator() == value ?
|
||||
"rz-multiselect-item rz-state-highlight" :
|
||||
"rz-multiselect-item";
|
||||
}
|
||||
|
||||
protected string FilterIconStyle()
|
||||
{
|
||||
var additionalStyle = Column.GetFilterValue() != null || Column.GetSecondFilterValue() != null ||
|
||||
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
|
||||
|| value == FilterOperator.IsEmpty || value == FilterOperator.IsNotEmpty)
|
||||
{
|
||||
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,
|
||||
FilterValue = Column.GetFilterValue(),
|
||||
SecondFilterValue = Column.GetSecondFilterValue(),
|
||||
FilterOperator = Column.GetFilterOperator(),
|
||||
SecondFilterOperator = Column.GetSecondFilterOperator(),
|
||||
LogicalFilterOperator = Column.GetLogicalFilterOperator()
|
||||
});
|
||||
|
||||
await JSRuntime.InvokeVoidAsync("Radzen.closePopup", $"{Grid.PopupID}{Column.GetFilterProperty()}");
|
||||
await Grid.Reload();
|
||||
}
|
||||
|
||||
protected async Task ClearFilter()
|
||||
{
|
||||
Column.ClearFilters();
|
||||
|
||||
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.Reload();
|
||||
}
|
||||
}
|
||||
37
Radzen.Blazor/RadzenDataGridFooterCell.razor
Normal file
37
Radzen.Blazor/RadzenDataGridFooterCell.razor
Normal file
@@ -0,0 +1,37 @@
|
||||
@typeparam TItem
|
||||
@if (RowIndex == Column.GetLevel())
|
||||
{
|
||||
<td rowspan="@(Column.GetRowSpan())" colspan="@(Column.GetColSpan())" @attributes="@Attributes" class="@CssClass" scope="col" style="@Column.GetStyle(true, true)">
|
||||
<span class="rz-column-footer">
|
||||
@if (Column.FooterTemplate != null)
|
||||
{
|
||||
@Column.FooterTemplate
|
||||
}
|
||||
</span>
|
||||
</td>
|
||||
}
|
||||
else
|
||||
{
|
||||
@foreach(var column in Grid.childColumns.Where(c => c.GetVisible() && c.Parent == Column))
|
||||
{
|
||||
<RadzenDataGridFooterCell RowIndex="@RowIndex" Grid="@Grid" Column="@column"
|
||||
CssClass="@($"{Column.FooterCssClass} {Grid.getFrozenColumnClass(column, Grid.ColumnsCollection.Where(c => c.GetVisible()).ToList())} {Grid.getCompositeCellCSSClass(column)}")"
|
||||
Attributes="@(Attributes)" />
|
||||
}
|
||||
}
|
||||
@code {
|
||||
[Parameter(CaptureUnmatchedValues = true)]
|
||||
public IReadOnlyDictionary<string, object> Attributes { get; set; }
|
||||
|
||||
[Parameter]
|
||||
public RadzenDataGridColumn<TItem> Column { get; set; }
|
||||
|
||||
[Parameter]
|
||||
public int RowIndex { get; set; }
|
||||
|
||||
[Parameter]
|
||||
public RadzenDataGrid<TItem> Grid { get; set; }
|
||||
|
||||
[Parameter]
|
||||
public string CssClass { get; set; }
|
||||
}
|
||||
@@ -1,6 +1,12 @@
|
||||
@typeparam TItem
|
||||
@using System.Linq.Dynamic.Core
|
||||
<tr>
|
||||
@if (Grid.Template != null && Grid.ShowExpandColumn)
|
||||
{
|
||||
<th class="rz-col-icon rz-unselectable-text" scope="col">
|
||||
<span class="rz-column-title"></span>
|
||||
</th>
|
||||
}
|
||||
@for(var i = 0; i < GetLevel(); i++)
|
||||
{
|
||||
<td class="rz-col-icon">
|
||||
@@ -43,7 +49,7 @@
|
||||
Group = new Group()
|
||||
{
|
||||
Level = level,
|
||||
GroupDescriptor = Grid.groups[level],
|
||||
GroupDescriptor = Grid.Groups[level],
|
||||
Data = _groupResult
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,41 +1,60 @@
|
||||
@typeparam TItem
|
||||
@using System.Linq.Dynamic.Core
|
||||
<tr>
|
||||
@for(var i = 0; i < GetLevel(); i++)
|
||||
@{
|
||||
var rowArgs = Grid?.GroupRowAttributes(this);
|
||||
}
|
||||
<tr class="rz-group-row" @attributes="@rowArgs.Item2">
|
||||
@if (Group.GroupDescriptor != null)
|
||||
{
|
||||
<td class="rz-col-icon">
|
||||
<span class="rz-column-title"></span>
|
||||
</td>
|
||||
@for (var i = 0; i < GetLevel(); i++)
|
||||
{
|
||||
<td class="rz-col-icon">
|
||||
<span class="rz-column-title"></span>
|
||||
</td>
|
||||
}
|
||||
|
||||
}
|
||||
<td class="rz-col-icon">
|
||||
<span class="rz-column-title"></span>
|
||||
<a href="javascript:void(0)" @onclick="@(_ => Grid.ExpandGroupItem(this))">
|
||||
<span class="@(Grid.ExpandedGroupItemStyle(this))"></span>
|
||||
<a href="javascript:void(0)" @onclick="@(_ => Grid.ExpandGroupItem(this, rowArgs.Item1.Expanded))">
|
||||
<span class="@(Grid.ExpandedGroupItemStyle(this, Grid.allGroupsExpanded != null ? Grid.allGroupsExpanded : rowArgs.Item1.Expanded))"></span>
|
||||
</a>
|
||||
</td>
|
||||
<td colspan="@(Columns.Count + Grid.groups.Count - 1 - Group.Level)">
|
||||
<td colspan="@(Columns.Count + Grid.Groups.Count - 1 - Group.Level + (Grid.Template != null && Grid.ShowExpandColumn ? 1 : 0))">
|
||||
<span class="rz-cell-data">
|
||||
@if (Grid.GroupHeaderTemplate != null)
|
||||
{
|
||||
@Grid.GroupHeaderTemplate(Group)
|
||||
}
|
||||
else
|
||||
else if(Group.GroupDescriptor != null)
|
||||
{
|
||||
@(Group.GroupDescriptor.GetTitle() + ": " + Group.Data.Key)
|
||||
@(Group.GroupDescriptor.GetTitle() + ": " + (Group.Data.Key != null ? Group.Data.Key.ToString() : ""))
|
||||
}
|
||||
</span>
|
||||
</td>
|
||||
</tr>
|
||||
@if(Grid != null)
|
||||
{
|
||||
if (Grid.IsGroupItemExpanded(this))
|
||||
if (Grid.IsGroupItemExpanded(this) && rowArgs.Item1.Expanded != false && Grid.allGroupsExpanded != false)
|
||||
{
|
||||
@DrawDataRows()
|
||||
}
|
||||
else if(Grid.GroupFootersAlwaysVisible)
|
||||
{
|
||||
if (!Grid.collapsedGroupItems.Keys.Contains(this))
|
||||
{
|
||||
Grid.collapsedGroupItems.Add(this, true);
|
||||
}
|
||||
|
||||
@DrawDataRows(true)
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!Grid.collapsedGroupItems.Keys.Contains(this))
|
||||
{
|
||||
Grid.collapsedGroupItems.Add(this, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
@code {
|
||||
[Parameter]
|
||||
@@ -59,7 +78,7 @@
|
||||
Group = new Group()
|
||||
{
|
||||
Level = level,
|
||||
GroupDescriptor = Grid.groups[level],
|
||||
GroupDescriptor = Grid.Groups?.ElementAtOrDefault(level),
|
||||
Data = _groupResult
|
||||
};
|
||||
}
|
||||
@@ -106,6 +125,12 @@
|
||||
builder.AddAttribute(4, "TItem", typeof(TItem));
|
||||
builder.AddAttribute(5, "Item", item);
|
||||
builder.AddAttribute(6, "InEditMode", Grid.IsRowInEditMode((TItem)item));
|
||||
|
||||
if (Grid.editContexts.ContainsKey((TItem)item))
|
||||
{
|
||||
builder.AddAttribute(7, nameof(RadzenDataGridRow<TItem>.EditContext), Grid.editContexts[(TItem)item]);
|
||||
}
|
||||
|
||||
builder.CloseComponent();
|
||||
i++;
|
||||
}
|
||||
|
||||
234
Radzen.Blazor/RadzenDataGridHeaderCell.razor
Normal file
234
Radzen.Blazor/RadzenDataGridHeaderCell.razor
Normal file
@@ -0,0 +1,234 @@
|
||||
@typeparam TItem
|
||||
@using Radzen.Blazor.Rendering
|
||||
@if (RowIndex == Column.GetLevel())
|
||||
{
|
||||
<th rowspan="@(Column.GetRowSpan())" colspan="@(Column.GetColSpan())" @attributes="@Attributes" class="@CssClass" scope="col" style="@Column.GetStyle(true, true)" @onmouseup=@(args => Grid.EndColumnReorder(args, ColumnIndex)) >
|
||||
<div @onclick='@((args) => Grid.OnSort(args, Column))' tabindex="@SortingTabIndex" @onkeydown="OnSortKeyPressed">
|
||||
@if (Column.Parent == null && Column.Columns == null && (Grid.AllowColumnReorder && Column.Reorderable || Grid.AllowGrouping && Column.Groupable))
|
||||
{
|
||||
<span id="@Grid.getColumnResizerId(ColumnIndex)" class="rz-column-drag"
|
||||
@onclick:preventDefault="true" @onclick:stopPropagation="true"
|
||||
@onmousedown:preventDefault="true"
|
||||
@onmousedown=@(args => Grid.StartColumnReorder(args, ColumnIndex))></span>
|
||||
}
|
||||
<span class="rz-column-title" title="@Column.Title">
|
||||
@if (Column.HeaderTemplate != null)
|
||||
{
|
||||
<span class="rz-column-title-content">@Column.HeaderTemplate</span>
|
||||
}
|
||||
else
|
||||
{
|
||||
<span class="rz-column-title-content">@Column.Title</span>
|
||||
}
|
||||
|
||||
@if (Grid.AllowSorting && Column.Sortable)
|
||||
{
|
||||
@if (Column.GetSortOrder() == SortOrder.Ascending)
|
||||
{
|
||||
<span class="rz-sortable-column-icon rzi-grid-sort rzi-sort rzi-sort-asc"></span>
|
||||
@if(Grid.ShowMultiColumnSortingIndex)
|
||||
{
|
||||
<RadzenBadge BadgeStyle="BadgeStyle.Info" Shade="Shade.Lighter" IsPill=true Text="@getSortIndex()" />
|
||||
}
|
||||
}
|
||||
else if (Column.GetSortOrder() == SortOrder.Descending)
|
||||
{
|
||||
<span class="rz-sortable-column-icon rzi-grid-sort rzi-sort rzi-sort-desc"></span>
|
||||
@if(Grid.ShowMultiColumnSortingIndex)
|
||||
{
|
||||
<RadzenBadge BadgeStyle="BadgeStyle.Info" Shade="Shade.Lighter" IsPill=true Text="@getSortIndex()" />
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
<span class="rz-sortable-column-icon rzi-grid-sort rzi-sort"></span>
|
||||
}
|
||||
}
|
||||
</span>
|
||||
@if (Grid.AllowColumnResize && Column.Resizable && Column.Parent == null)
|
||||
{
|
||||
<div id="@Grid.getColumnResizerId(ColumnIndex)" style="cursor:col-resize;float:right;"
|
||||
@onclick:preventDefault="true" @onclick:stopPropagation="true" class="rz-column-resizer"
|
||||
@onmousedown:preventDefault="true"
|
||||
@onmousedown=@(args => Grid.StartColumnResize(args, ColumnIndex))> </div>
|
||||
}
|
||||
@if (Grid.AllowFiltering && Column.Filterable && Grid.FilterMode == FilterMode.Advanced)
|
||||
{
|
||||
<i @ref=@filterButton @onclick:stopPropagation="true" @onmousedown=@ToggleFilter
|
||||
class="@getFilterIconCss(Column)" onclick=@getFilterOpen() />
|
||||
|
||||
<Popup Lazy=@(Grid.FilterPopupRenderMode == PopupRenderMode.OnDemand) @ref=popup id="@($"{getColumnPopupID()}")" class="rz-overlaypanel"
|
||||
style="display:none;min-width:250px;" tabindex="0">
|
||||
<div class="rz-overlaypanel-content">
|
||||
@if (Column.FilterTemplate != null)
|
||||
{
|
||||
@Column.FilterTemplate(Column)
|
||||
}
|
||||
else
|
||||
{
|
||||
<form id="@($"{getColumnPopupID()}-form")" @onsubmit="@(args => ApplyFilter())" class="rz-grid-filter">
|
||||
<RadzenLabel Text="@Grid.FilterText" class="rz-grid-filter-label" />
|
||||
<RadzenDropDown @onclick:preventDefault="true" Data="@(Column.GetFilterOperators().Select(t => new { Value = Column.GetFilterOperatorText(t), Key = t }))" TextProperty="Value" ValueProperty="Key" TValue="FilterOperator" Value="@Column.GetFilterOperator()" Change="@(args => Column.SetFilterOperator((FilterOperator)args))" />
|
||||
@if (PropertyAccess.IsNullableEnum(Column.FilterPropertyType) || PropertyAccess.IsEnum(Column.FilterPropertyType))
|
||||
{
|
||||
<RadzenDropDown AllowClear="false" AllowFiltering="false" TValue="@object"
|
||||
Value=@Column.GetFilterValue() Multiple="false" Placeholder="@Grid.EnumFilterSelectText" TextProperty="Text" ValueProperty="Value" Data=@EnumExtensions.EnumAsKeyValuePair(Nullable.GetUnderlyingType(Column.FilterPropertyType) ?? Column.FilterPropertyType)
|
||||
Change="@(args => Column.SetFilterValue(args))" />
|
||||
}
|
||||
else if (PropertyAccess.IsNumeric(Column.FilterPropertyType))
|
||||
{
|
||||
@(Grid.DrawNumericFilter(Column, false))
|
||||
}
|
||||
else if (PropertyAccess.IsDate(Column.FilterPropertyType))
|
||||
{
|
||||
<RadzenDatePicker TValue="@object" ShowTime="true" ShowTimeOkButton="true" DateFormat="@Grid.getFilterDateFormat(Column)"
|
||||
Value="@Column.GetFilterValue()" Change="@(args => Column.SetFilterValue(args.Value))" AllowInput=@(Grid.AllowFilterDateInput) />
|
||||
|
||||
}
|
||||
else if (Column.FilterPropertyType == typeof(bool) || Column.FilterPropertyType == typeof(bool?))
|
||||
{
|
||||
<RadzenCheckBox TriState="true" TValue="@object" Value="@Column.GetFilterValue()" Change="@(args => { Column.FilterValue = null; Column.SetFilterValue(args); Grid.SaveSettings(); Grid.Reload(); })" />
|
||||
}
|
||||
else
|
||||
{
|
||||
<RadzenTextBox Value="@($"{Column.GetFilterValue()}")" Change="@(args => Column.SetFilterValue(args))" />
|
||||
}
|
||||
|
||||
<RadzenDropDown @onclick:preventDefault="true" TextProperty="Text" ValueProperty="Value" Style="width: 90px"
|
||||
Data="@(Enum.GetValues(typeof(LogicalFilterOperator)).Cast<LogicalFilterOperator>().Select(t => new { Text = t == LogicalFilterOperator.And ? Grid.AndOperatorText : Grid.OrOperatorText, Value = t }))" TValue="LogicalFilterOperator" Value="@Column.LogicalFilterOperator" Change="@(args => Column.SetLogicalFilterOperator((LogicalFilterOperator)args))" />
|
||||
|
||||
<RadzenDropDown @onclick:preventDefault="true" Data="@(Column.GetFilterOperators().Select(t => new { Value = Column.GetFilterOperatorText(t), Key = t }))" TextProperty="Value" ValueProperty="Key" TValue="FilterOperator" Value="@Column.GetSecondFilterOperator()" Change="@(args => Column.SetSecondFilterOperator((FilterOperator)args))" />
|
||||
@if (PropertyAccess.IsNullableEnum(Column.FilterPropertyType) || PropertyAccess.IsEnum(Column.FilterPropertyType))
|
||||
{
|
||||
<RadzenDropDown AllowClear="false" AllowFiltering="false" TValue="@object"
|
||||
Value=@Column.GetSecondFilterValue() Multiple="false" Placeholder="@Grid.EnumFilterSelectText" TextProperty="Text" ValueProperty="Value" Data=@EnumExtensions.EnumAsKeyValuePair(Nullable.GetUnderlyingType(Column.FilterPropertyType) ?? Column.FilterPropertyType)
|
||||
Change="@(args => Column.SetFilterValue(args,false))" />
|
||||
}
|
||||
else if (PropertyAccess.IsNumeric(Column.FilterPropertyType))
|
||||
{
|
||||
@(Grid.DrawNumericFilter(Column, false, false))
|
||||
}
|
||||
else if (PropertyAccess.IsDate(Column.FilterPropertyType))
|
||||
{
|
||||
<RadzenDatePicker TValue="@object"
|
||||
ShowTime="@Column.ShowTimeForDateTimeFilter()" ShowTimeOkButton="true" DateFormat="@Grid.getFilterDateFormat(Column)"
|
||||
Value="@Column.GetSecondFilterValue()" Change="@(args => Column.SetFilterValue(args.Value, false))" AllowInput=@(Grid.AllowFilterDateInput) />
|
||||
|
||||
}
|
||||
else if (Column.FilterPropertyType == typeof(bool) || Column.FilterPropertyType == typeof(bool?))
|
||||
{
|
||||
<RadzenCheckBox TriState="true" TValue="@object" Value="@Column.GetSecondFilterValue()" Change="@(args => { Column.SetFilterValue(args, false); Grid.SaveSettings(); })" />
|
||||
}
|
||||
else
|
||||
{
|
||||
<RadzenTextBox Value="@($"{Column.GetSecondFilterValue()}")" Change="@(args => Column.SetFilterValue(args, false))" />
|
||||
}
|
||||
</form>
|
||||
}
|
||||
</div>
|
||||
@if (Column.FilterTemplate == null)
|
||||
{
|
||||
<div class="rz-grid-filter-buttons">
|
||||
<RadzenButton ButtonStyle="ButtonStyle.Secondary" Text=@Grid.ClearFilterText Click="@ClearFilter" />
|
||||
<RadzenButton form="@($"{getColumnPopupID()}-form")" ButtonType="ButtonType.Submit" ButtonStyle="ButtonStyle.Primary" Text=@Grid.ApplyFilterText Click="@ApplyFilter" />
|
||||
</div>
|
||||
}
|
||||
</Popup>
|
||||
}
|
||||
</div>
|
||||
</th>
|
||||
}
|
||||
else
|
||||
{
|
||||
@foreach(var column in Grid.childColumns.Where(c => c.GetVisible() && c.Parent == Column))
|
||||
{
|
||||
<RadzenDataGridHeaderCell RowIndex="@RowIndex" Grid="@Grid" Column="@column" ColumnIndex="@ColumnIndex"
|
||||
CssClass="@($"rz-unselectable-text {(Grid.AllowSorting && column.Sortable ? "rz-sortable-column" : "")} {column.HeaderCssClass} {Grid.getFrozenColumnClass(column, Grid.ColumnsCollection.Where(c => c.GetVisible()).ToList())} {Grid.getCompositeCellCSSClass(column)} {Grid.getColumnAlignClass(column)}".Trim())" />
|
||||
}
|
||||
}
|
||||
@code {
|
||||
Radzen.Blazor.Rendering.Popup popup;
|
||||
ElementReference filterButton;
|
||||
|
||||
string getFilterOpen()
|
||||
{
|
||||
return Grid.FilterPopupRenderMode == PopupRenderMode.Initial ? $"Radzen.togglePopup(this, '{getColumnPopupID()}')" : "";
|
||||
}
|
||||
|
||||
async Task ToggleFilter()
|
||||
{
|
||||
if (Grid.FilterPopupRenderMode == PopupRenderMode.OnDemand)
|
||||
{
|
||||
await popup.ToggleAsync(filterButton);
|
||||
}
|
||||
}
|
||||
|
||||
async Task ClearFilter()
|
||||
{
|
||||
if (Grid.FilterPopupRenderMode == PopupRenderMode.OnDemand)
|
||||
{
|
||||
await popup.CloseAsync();
|
||||
}
|
||||
await Grid.ClearFilter(Column, true);
|
||||
}
|
||||
|
||||
async Task ApplyFilter()
|
||||
{
|
||||
if (Grid.FilterPopupRenderMode == PopupRenderMode.OnDemand)
|
||||
{
|
||||
await popup.CloseAsync();
|
||||
}
|
||||
await Grid.ApplyFilter(Column, true);
|
||||
}
|
||||
|
||||
[Parameter(CaptureUnmatchedValues = true)]
|
||||
public IReadOnlyDictionary<string, object> Attributes { get; set; }
|
||||
|
||||
[Parameter]
|
||||
public RadzenDataGridColumn<TItem> Column { get; set; }
|
||||
|
||||
[Parameter]
|
||||
public int ColumnIndex { get; set; }
|
||||
|
||||
[Parameter]
|
||||
public int RowIndex { get; set; }
|
||||
|
||||
[Parameter]
|
||||
public RadzenDataGrid<TItem> Grid { get; set; }
|
||||
|
||||
[Parameter]
|
||||
public string CssClass { get; set; }
|
||||
|
||||
private int SortingTabIndex => Grid.AllowSorting && Column.Sortable ? 0 : -1;
|
||||
|
||||
private string getFilterIconCss(RadzenDataGridColumn<TItem> column)
|
||||
{
|
||||
var additionalStyle = column.GetFilterValue() != null || column.GetSecondFilterValue() != null ||
|
||||
column.GetFilterOperator() == FilterOperator.IsNotNull || column.GetFilterOperator() == FilterOperator.IsNull
|
||||
|| column.GetFilterOperator() == FilterOperator.IsEmpty || column.GetFilterOperator() == FilterOperator.IsNotEmpty
|
||||
? "rz-grid-filter-active" : "";
|
||||
return $"rzi rz-grid-filter-icon {additionalStyle}";
|
||||
}
|
||||
|
||||
private void OnSortKeyPressed(KeyboardEventArgs args)
|
||||
{
|
||||
var key = args.Code ?? args.Key;
|
||||
if (key == "Enter")
|
||||
{
|
||||
Grid.OnSort(args, Column);
|
||||
}
|
||||
}
|
||||
|
||||
string getSortIndex()
|
||||
{
|
||||
var descriptor = Grid.sorts.Where(s => s.Property == Column.GetSortProperty()).FirstOrDefault();
|
||||
return descriptor != null ? $"{Grid.sorts.IndexOf(descriptor) + 1}" : "";
|
||||
}
|
||||
|
||||
string getColumnPopupID()
|
||||
{
|
||||
var fiterProperty = Column.GetFilterProperty();
|
||||
|
||||
return $"{Grid.PopupID}{(string.IsNullOrEmpty(fiterProperty) ? Grid.allColumns.IndexOf(Column).ToString() : fiterProperty)}";
|
||||
}
|
||||
}
|
||||
@@ -2,27 +2,29 @@
|
||||
@typeparam TItem
|
||||
@implements IRadzenForm
|
||||
@{var rowArgs = Grid?.RowAttributes(Item); }
|
||||
@{var firstLevel = Grid.AllowCompositeDataCells ? 0 : Grid.deepestChildColumnLevel; }
|
||||
@for(var i = firstLevel; i < Grid.deepestChildColumnLevel + 1; i++)
|
||||
{
|
||||
<tr class="@(Grid.RowStyle(Item, Index))" @attributes="@rowArgs.Item2">
|
||||
@foreach(var g in Grid.groups)
|
||||
@foreach(var g in Grid.Groups)
|
||||
{
|
||||
<td class="rz-col-icon">
|
||||
<td class="rz-col-icon" rowspan="@(Grid.AllowCompositeDataCells ? (Grid.deepestChildColumnLevel + 1) : 1)">
|
||||
<span class="rz-column-title"></span>
|
||||
</td>
|
||||
}
|
||||
@if (Grid.Template != null && Grid.ShowExpandColumn)
|
||||
@if (Grid.Template != null && Grid.ShowExpandColumn && i == firstLevel)
|
||||
{
|
||||
<td class="rz-col-icon">
|
||||
<td class="rz-col-icon" rowspan="@(Grid.AllowCompositeDataCells ? (Grid.deepestChildColumnLevel + 1) : 1)">
|
||||
<span class="rz-column-title"></span>
|
||||
@if (rowArgs.Item1.Expandable)
|
||||
{
|
||||
<a href="javascript:void(0)" @onclick="@(_ => Grid.ExpandItem(Item))">
|
||||
<a href="javascript:void(0)" @onclick="@(_ => Grid.ExpandItem(Item))" @onclick:stopPropagation>
|
||||
<span class="@(Grid.ExpandedItemStyle(Item))"></span>
|
||||
</a>
|
||||
}
|
||||
</td>
|
||||
}
|
||||
<CascadingValue Value=@EditContext>
|
||||
<CascadingValue Value=this>
|
||||
|
||||
@for (var j = 0; j < Columns.Count; j++)
|
||||
{
|
||||
if (Grid.rowSpans.ContainsKey(j))
|
||||
@@ -58,8 +60,48 @@
|
||||
Grid.rowSpans.Add(j, (int)Convert.ChangeType(rowspan, TypeCode.Int32));
|
||||
}
|
||||
|
||||
<RadzenDataGridCell Grid="@this.Grid" Item="@Item" Column="@column"
|
||||
Style="@column.GetStyle(true)" CssClass="@(column.CssClass + " " + Grid.getFrozenColumnClass(column, Columns))" Attributes="@(cellAttr)">
|
||||
<RadzenDataGridCell Row=@this EditContext=EditContext RowIndex="@i" Grid="@this.Grid" Item="@Item" Column="@column"
|
||||
Style="@column.GetStyle(true)" CssClass="@(column.CssClass + " " + Grid.getFrozenColumnClass(column, Columns) + " " + Grid.getCompositeCellCSSClass(column))" Attributes="@(cellAttr)">
|
||||
@if (Grid.Responsive)
|
||||
{
|
||||
<span class="rz-column-title">
|
||||
@if (column.HeaderTemplate != null)
|
||||
{
|
||||
@column.HeaderTemplate
|
||||
}
|
||||
else
|
||||
{
|
||||
@column.Title
|
||||
}
|
||||
</span>
|
||||
}
|
||||
@if (Grid.LoadChildData.HasDelegate && Grid.ShowExpandColumn && Grid.allColumns.IndexOf(column) == 0)
|
||||
{
|
||||
<span class="rz-cell-toggle">
|
||||
<a style="@(getExpandIconStyle(rowArgs.Item1.Expandable))" href="javascript:void(0)" @onclick="@(_ => Grid.ExpandItem(Item))" @onclick:stopPropagation>
|
||||
<span class="@(Grid.ExpandedItemStyle(Item))"></span>
|
||||
</a>
|
||||
<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>
|
||||
</span>
|
||||
}
|
||||
else
|
||||
{
|
||||
<span class="rz-cell-data" title="@(column.Template == null ? column.GetValue(Item) : "")">
|
||||
@if (Item != null)
|
||||
{
|
||||
@@ -77,15 +119,17 @@
|
||||
}
|
||||
}
|
||||
</span>
|
||||
}
|
||||
</RadzenDataGridCell>
|
||||
}
|
||||
</CascadingValue>
|
||||
</CascadingValue>
|
||||
|
||||
</tr>
|
||||
}
|
||||
|
||||
@if (Grid.Template != null && Grid.expandedItems.Keys.Contains(Item))
|
||||
{
|
||||
<tr class="rz-expanded-row-content">
|
||||
<td colspan="@(Columns.Count + (Grid.ShowExpandColumn ? 1 : 0) + + Grid.groups.Count)">
|
||||
<td colspan="@(Columns.Sum(c => c.GetColSpan()) + (Grid.ShowExpandColumn ? 1 : 0) + Grid.Groups.Count)">
|
||||
<div class="rz-expanded-row-template" style="position:sticky">
|
||||
@Grid.Template(Item)
|
||||
</div>
|
||||
@@ -151,4 +195,25 @@
|
||||
{
|
||||
return components.Where(component => component.Name == name).FirstOrDefault();
|
||||
}
|
||||
|
||||
internal string getExpandIconStyle(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);
|
||||
}
|
||||
}
|
||||
@@ -6,48 +6,24 @@
|
||||
<div @ref="@Element" @attributes="Attributes" class="@GetCssClass()" style="@Style" id="@GetId()">
|
||||
@if (AllowPaging && (PagerPosition == PagerPosition.Top || PagerPosition == PagerPosition.TopAndBottom))
|
||||
{
|
||||
<RadzenPager @ref="topPager" Count="@Count" PageSize="@PageSize" PageNumbersCount="@PageNumbersCount" PageChanged="@OnPageChanged" PageSizeChanged="@OnPageSizeChanged" PageSizeOptions="@PageSizeOptions" ShowPagingSummary="@ShowPagingSummary" PagingSummaryFormat="@PagingSummaryFormat" />
|
||||
<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" />
|
||||
}
|
||||
@if (Data != null)
|
||||
{
|
||||
@if (!WrapItems)
|
||||
{
|
||||
@foreach (var item in LoadData.HasDelegate ? Data : PagedView)
|
||||
{
|
||||
<ul class="rz-datalist-data">
|
||||
<li>
|
||||
@if (Template != null)
|
||||
{
|
||||
@Template(item)
|
||||
}
|
||||
else
|
||||
{
|
||||
<span>Template</span>
|
||||
}
|
||||
</li>
|
||||
</ul>
|
||||
}
|
||||
@DrawDataListRows()
|
||||
}
|
||||
else
|
||||
{
|
||||
<div class="rz-g">
|
||||
@foreach (var item in LoadData.HasDelegate ? Data : PagedView)
|
||||
{
|
||||
@if (Template != null)
|
||||
{
|
||||
@Template(item)
|
||||
}
|
||||
else
|
||||
{
|
||||
<span>Template</span>
|
||||
}
|
||||
}
|
||||
@DrawDataListRows()
|
||||
</div>
|
||||
}
|
||||
}
|
||||
@if (AllowPaging && (PagerPosition == PagerPosition.Bottom || PagerPosition == PagerPosition.TopAndBottom))
|
||||
{
|
||||
<RadzenPager @ref="bottomPager" Count="@Count" PageSize="@PageSize" PageNumbersCount="@PageNumbersCount" PageChanged="@OnPageChanged" PageSizeChanged="@OnPageSizeChanged" PageSizeOptions="@PageSizeOptions" ShowPagingSummary="@ShowPagingSummary" PagingSummaryFormat="@PagingSummaryFormat" class="rz-paginator-bottom" />
|
||||
<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" class="rz-paginator-bottom" />
|
||||
}
|
||||
</div>
|
||||
}
|
||||
|
||||
@@ -1,4 +1,16 @@
|
||||
using Microsoft.AspNetCore.Components;
|
||||
using Microsoft.AspNetCore.Components.Forms;
|
||||
using Microsoft.AspNetCore.Components.Web;
|
||||
using Microsoft.JSInterop;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Collections.Specialized;
|
||||
using System.Data.Common;
|
||||
using System.Linq;
|
||||
using System.Linq.Dynamic.Core;
|
||||
using System.Text.Json;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Radzen.Blazor
|
||||
{
|
||||
@@ -29,5 +41,98 @@ namespace Radzen.Blazor
|
||||
/// <value><c>true</c> if wrap items; otherwise, <c>false</c>.</value>
|
||||
[Parameter]
|
||||
public bool WrapItems { get; set; }
|
||||
#if NET5_0_OR_GREATER
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether this instance is virtualized.
|
||||
/// </summary>
|
||||
/// <value><c>true</c> if this instance is virtualized; otherwise, <c>false</c>.</value>
|
||||
[Parameter]
|
||||
public bool AllowVirtualization { get; set; }
|
||||
|
||||
internal Microsoft.AspNetCore.Components.Web.Virtualization.Virtualize<TItem> virtualize;
|
||||
|
||||
/// <summary>
|
||||
/// Gets Virtualize component reference.
|
||||
/// </summary>
|
||||
public Microsoft.AspNetCore.Components.Web.Virtualization.Virtualize<TItem> Virtualize
|
||||
{
|
||||
get
|
||||
{
|
||||
return virtualize;
|
||||
}
|
||||
}
|
||||
|
||||
private async ValueTask<Microsoft.AspNetCore.Components.Web.Virtualization.ItemsProviderResult<TItem>> LoadItems(Microsoft.AspNetCore.Components.Web.Virtualization.ItemsProviderRequest request)
|
||||
{
|
||||
var view = AllowPaging ? PagedView : View;
|
||||
var top = request.Count;
|
||||
|
||||
if(top <= 0)
|
||||
{
|
||||
top = PageSize;
|
||||
}
|
||||
|
||||
await LoadData.InvokeAsync(new Radzen.LoadDataArgs()
|
||||
{
|
||||
Skip = request.StartIndex,
|
||||
Top = top
|
||||
});
|
||||
|
||||
var totalItemsCount = LoadData.HasDelegate ? Count : view.Count();
|
||||
|
||||
var virtualDataItems = (LoadData.HasDelegate ? Data : view.Skip(request.StartIndex).Take(top))?.ToList();
|
||||
|
||||
return new Microsoft.AspNetCore.Components.Web.Virtualization.ItemsProviderResult<TItem>(virtualDataItems, totalItemsCount);
|
||||
}
|
||||
#endif
|
||||
RenderFragment DrawDataListRows()
|
||||
{
|
||||
return new RenderFragment(builder =>
|
||||
{
|
||||
#if NET5_0_OR_GREATER
|
||||
if (AllowVirtualization)
|
||||
{
|
||||
builder.OpenComponent(0, typeof(Microsoft.AspNetCore.Components.Web.Virtualization.Virtualize<TItem>));
|
||||
builder.AddAttribute(1, "ItemsProvider", new Microsoft.AspNetCore.Components.Web.Virtualization.ItemsProviderDelegate<TItem>(LoadItems));
|
||||
|
||||
builder.AddAttribute(2, "ChildContent", (RenderFragment<TItem>)((context) =>
|
||||
{
|
||||
return (RenderFragment)((b) =>
|
||||
{
|
||||
DrawRow(b, context);
|
||||
});
|
||||
}));
|
||||
|
||||
builder.AddComponentReferenceCapture(4, c => { virtualize = (Microsoft.AspNetCore.Components.Web.Virtualization.Virtualize<TItem>)c; });
|
||||
|
||||
builder.CloseComponent();
|
||||
}
|
||||
else
|
||||
{
|
||||
DrawRows(builder);
|
||||
}
|
||||
#else
|
||||
DrawRows(builder);
|
||||
#endif
|
||||
});
|
||||
}
|
||||
|
||||
internal void DrawRows(Microsoft.AspNetCore.Components.Rendering.RenderTreeBuilder builder)
|
||||
{
|
||||
foreach (var item in LoadData.HasDelegate ? Data : PagedView)
|
||||
{
|
||||
DrawRow(builder, item);
|
||||
}
|
||||
}
|
||||
|
||||
internal void DrawRow(Microsoft.AspNetCore.Components.Rendering.RenderTreeBuilder builder, TItem item)
|
||||
{
|
||||
builder.OpenComponent<RadzenDataListRow<TItem>>(0);
|
||||
builder.AddAttribute(1, "DataList", this);
|
||||
builder.AddAttribute(2, "Item", item);
|
||||
builder.SetKey(item);
|
||||
builder.CloseComponent();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user