mirror of
https://github.com/radzenhq/radzen-blazor.git
synced 2026-02-04 05:35:44 +00:00
Compare commits
1105 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
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 |
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-2022 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,7 @@ namespace Radzen
|
||||
/// <typeparam name="T"></typeparam>
|
||||
public class DropDownBase<T> : DataBoundFormComponent<T>
|
||||
{
|
||||
#if NET5
|
||||
#if NET5_0_OR_GREATER
|
||||
internal Microsoft.AspNetCore.Components.Web.Virtualization.Virtualize<object> virtualize;
|
||||
|
||||
/// <summary>
|
||||
@@ -30,6 +30,8 @@ namespace Radzen
|
||||
}
|
||||
}
|
||||
|
||||
List<object> virtualItems;
|
||||
|
||||
private async ValueTask<Microsoft.AspNetCore.Components.Web.Virtualization.ItemsProviderResult<object>> LoadItems(Microsoft.AspNetCore.Components.Web.Virtualization.ItemsProviderRequest request)
|
||||
{
|
||||
var data = Data != null ? Data.Cast<object>() : Enumerable.Empty<object>();
|
||||
@@ -47,7 +49,9 @@ namespace Radzen
|
||||
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>
|
||||
@@ -74,7 +78,7 @@ 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;
|
||||
@@ -89,7 +93,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>));
|
||||
@@ -122,6 +126,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>
|
||||
@@ -132,6 +156,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>
|
||||
@@ -153,6 +194,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>
|
||||
@@ -167,6 +215,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>
|
||||
@@ -177,7 +232,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>
|
||||
@@ -206,21 +261,43 @@ 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>().All(i => IsItemSelectedByValue(GetItemOrValueFromProperty(i, ValueProperty)));
|
||||
}
|
||||
|
||||
return View != null && selectedItems.Count == View.Cast<object>().Count();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Resets this instance.
|
||||
/// </summary>
|
||||
@@ -241,16 +318,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());
|
||||
|
||||
@@ -286,15 +363,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>
|
||||
@@ -303,7 +459,7 @@ namespace Radzen
|
||||
{
|
||||
get
|
||||
{
|
||||
return $"popup{UniqueID}";
|
||||
return $"popup-{GetId()}";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -315,7 +471,7 @@ namespace Radzen
|
||||
{
|
||||
get
|
||||
{
|
||||
return $"search{UniqueID}";
|
||||
return $"search-{GetId()}";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -361,7 +517,7 @@ namespace Radzen
|
||||
/// <summary>
|
||||
/// The list
|
||||
/// </summary>
|
||||
protected ElementReference list;
|
||||
protected ElementReference? list;
|
||||
/// <summary>
|
||||
/// The selected index
|
||||
/// </summary>
|
||||
@@ -381,7 +537,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>
|
||||
@@ -394,7 +553,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;
|
||||
|
||||
@@ -402,11 +582,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);
|
||||
@@ -414,7 +596,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)
|
||||
@@ -422,7 +604,7 @@ namespace Radzen
|
||||
//
|
||||
}
|
||||
}
|
||||
else if (Multiple && key == "Space")
|
||||
else if (Multiple && key == "Enter")
|
||||
{
|
||||
if (selectedIndex >= 0 && selectedIndex <= items.Count() - 1)
|
||||
{
|
||||
@@ -438,7 +620,7 @@ namespace Radzen
|
||||
{
|
||||
await JSRuntime.InvokeVoidAsync("Radzen.closePopup", PopupID);
|
||||
}
|
||||
else if (key == "Delete")
|
||||
else if (key == "Delete" && AllowClear)
|
||||
{
|
||||
if (!Multiple && selectedItem != null)
|
||||
{
|
||||
@@ -451,7 +633,7 @@ namespace Radzen
|
||||
Debounce(DebounceFilter, FilterDelay);
|
||||
}
|
||||
}
|
||||
else if(AllowFiltering && isFilter)
|
||||
else if (AllowFiltering && isFilter)
|
||||
{
|
||||
Debounce(DebounceFilter, FilterDelay);
|
||||
}
|
||||
@@ -477,13 +659,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
|
||||
{
|
||||
@@ -494,20 +676,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);
|
||||
}
|
||||
|
||||
@@ -545,7 +730,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) };
|
||||
@@ -576,6 +761,14 @@ namespace Radzen
|
||||
return base.OnAfterRenderAsync(firstRender);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void OnInitialized()
|
||||
{
|
||||
internalValue = Value;
|
||||
|
||||
base.OnInitialized();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Set parameters as an asynchronous operation.
|
||||
/// </summary>
|
||||
@@ -583,7 +776,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))
|
||||
{
|
||||
@@ -604,6 +797,11 @@ namespace Radzen
|
||||
shouldClose = !visible;
|
||||
}
|
||||
|
||||
if (parameters.DidParameterChange(nameof(Value), Value))
|
||||
{
|
||||
internalValue = parameters.GetValueOrDefault<object>(nameof(Value));
|
||||
}
|
||||
|
||||
await base.SetParametersAsync(parameters);
|
||||
|
||||
if (shouldClose && !firstRender)
|
||||
@@ -618,7 +816,7 @@ namespace Radzen
|
||||
/// <returns>Task.</returns>
|
||||
protected override Task OnParametersSetAsync()
|
||||
{
|
||||
var valueAsEnumerable = Value as IEnumerable;
|
||||
var valueAsEnumerable = internalValue as IEnumerable;
|
||||
|
||||
if (valueAsEnumerable != null)
|
||||
{
|
||||
@@ -628,7 +826,7 @@ namespace Radzen
|
||||
}
|
||||
}
|
||||
|
||||
SelectItemFromValue(Value);
|
||||
SelectItemFromValue(internalValue);
|
||||
|
||||
return base.OnParametersSetAsync();
|
||||
}
|
||||
@@ -639,7 +837,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>
|
||||
@@ -647,15 +845,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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -679,6 +884,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>
|
||||
@@ -775,13 +987,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))
|
||||
@@ -790,11 +1009,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();
|
||||
@@ -803,43 +1022,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({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>
|
||||
@@ -854,7 +1124,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
|
||||
{
|
||||
@@ -863,7 +1133,7 @@ namespace Radzen
|
||||
}
|
||||
else
|
||||
{
|
||||
selectedItem = Value;
|
||||
selectedItem = internalValue;
|
||||
}
|
||||
|
||||
SetSelectedIndexFromSelectedItem();
|
||||
@@ -872,25 +1142,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({ValueProperty},@0)", v).Any())
|
||||
{
|
||||
selectedItems.Add(item);
|
||||
}
|
||||
@@ -909,5 +1179,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-2022 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,146 @@ 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>
|
||||
/// 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.6</Version>
|
||||
<Version>4.4.7</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))
|
||||
|
||||
@@ -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";
|
||||
}
|
||||
}
|
||||
}
|
||||
81
Radzen.Blazor/RadzenAlert.razor
Normal file
81
Radzen.Blazor/RadzenAlert.razor
Normal file
@@ -0,0 +1,81 @@
|
||||
@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">@ChildContent</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>
|
||||
}
|
||||
151
Radzen.Blazor/RadzenAlert.razor.cs
Normal file
151
Radzen.Blazor/RadzenAlert.razor.cs
Normal file
@@ -0,0 +1,151 @@
|
||||
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 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"
|
||||
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"
|
||||
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)";
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
266
Radzen.Blazor/RadzenDataFilterItem.razor
Normal file
266
Radzen.Blazor/RadzenDataFilterItem.razor
Normal file
@@ -0,0 +1,266 @@
|
||||
@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(property)
|
||||
</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))
|
||||
{
|
||||
var formats = property.FormatString.Split(new char[] { '{', '}' }, StringSplitOptions.RemoveEmptyEntries);
|
||||
if (formats.Length > 0)
|
||||
{
|
||||
var format = formats[0].Trim().Split(':');
|
||||
if (format.Length > 1)
|
||||
{
|
||||
return format[1].Trim();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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<RadzenDataFilterProperty<TItem>> 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,155 +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">
|
||||
@@ -220,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"
|
||||
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="false" AllowClear="true"
|
||||
ShowTime="false" ShowTimeOkButton="false" DateFormat="@getFilterDateFormat(column)"
|
||||
Value="@column.GetFilterValue()" Change="@(args => { if(!args.HasValue) { ClearFilter(column, true); } else {column.SetFilterValue(args.Value); ApplyFilter(column, true);} })" />
|
||||
}
|
||||
}
|
||||
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?))
|
||||
@@ -296,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>
|
||||
}
|
||||
@@ -312,7 +302,7 @@
|
||||
<tbody>
|
||||
@if (Data != null)
|
||||
{
|
||||
@if (Count > 0)
|
||||
@if (!ShowEmptyMessage || Count > 0 || !AllowPaging && LoadData.HasDelegate && Count == 0)
|
||||
{
|
||||
if (columns.Count > 0)
|
||||
{
|
||||
@@ -322,14 +312,14 @@
|
||||
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>
|
||||
@@ -339,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>
|
||||
@@ -379,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 ? 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,10 +417,19 @@ 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) : "";
|
||||
|
||||
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(FormatString, value, Grid?.Culture ?? CultureInfo.CurrentCulture) : Convert.ToString(value, Grid?.Culture ?? CultureInfo.CurrentCulture);
|
||||
}
|
||||
|
||||
@@ -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>
|
||||
}
|
||||
179
Radzen.Blazor/RadzenDataGridFilterMenu.razor
Normal file
179
Radzen.Blazor/RadzenDataGridFilterMenu.razor
Normal file
@@ -0,0 +1,179 @@
|
||||
@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);
|
||||
|
||||
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, 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)
|
||||
{
|
||||
@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++;
|
||||
}
|
||||
|
||||
195
Radzen.Blazor/RadzenDataGridHeaderCell.razor
Normal file
195
Radzen.Blazor/RadzenDataGridHeaderCell.razor
Normal file
@@ -0,0 +1,195 @@
|
||||
@typeparam TItem
|
||||
@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=@(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=@(args => Grid.StartColumnResize(args, ColumnIndex))> </div>
|
||||
}
|
||||
@if (Grid.AllowFiltering && Column.Filterable && Grid.FilterMode == FilterMode.Advanced)
|
||||
{
|
||||
<i @onclick:stopPropagation="true" onclick="@($"Radzen.togglePopup(this, '{getColumnPopupID()}')")"
|
||||
class="@getFilterIconCss(Column)" />
|
||||
|
||||
<div id="@($"{getColumnPopupID()}")" 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="@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))" />
|
||||
|
||||
}
|
||||
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))" />
|
||||
|
||||
}
|
||||
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))" />
|
||||
}
|
||||
}
|
||||
</div>
|
||||
@if (Column.FilterTemplate == null)
|
||||
{
|
||||
<div class="rz-grid-filter-buttons">
|
||||
<RadzenButton ButtonStyle="ButtonStyle.Secondary" Text=@Grid.ClearFilterText Click="@((args) => Grid.ClearFilter(Column, true))" />
|
||||
<RadzenButton ButtonStyle="ButtonStyle.Primary" Text=@Grid.ApplyFilterText Click="@((args) => Grid.ApplyFilter(Column, true))" />
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
}
|
||||
</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 {
|
||||
[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,16 +2,19 @@
|
||||
@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)
|
||||
{
|
||||
@@ -21,8 +24,7 @@
|
||||
}
|
||||
</td>
|
||||
}
|
||||
<CascadingValue Value=@EditContext>
|
||||
<CascadingValue Value=this>
|
||||
|
||||
@for (var j = 0; j < Columns.Count; j++)
|
||||
{
|
||||
if (Grid.rowSpans.ContainsKey(j))
|
||||
@@ -58,8 +60,8 @@
|
||||
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">
|
||||
@@ -73,6 +75,33 @@
|
||||
}
|
||||
</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))">
|
||||
<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)
|
||||
{
|
||||
@@ -90,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>
|
||||
@@ -164,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,7 +6,7 @@
|
||||
<div @ref="@Element" @attributes="Attributes" class="@GetCssClass()" style="@Style" id="@GetId()">
|
||||
@if (AllowPaging && (PagerPosition == PagerPosition.Top || PagerPosition == PagerPosition.TopAndBottom))
|
||||
{
|
||||
<RadzenPager @ref="topPager" Count="@Count" PageSize="@PageSize" PageNumbersCount="@PageNumbersCount" PageChanged="@OnPageChanged" 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)
|
||||
{
|
||||
@@ -47,7 +47,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" 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>
|
||||
}
|
||||
|
||||
@@ -14,10 +14,10 @@
|
||||
@if (!Inline)
|
||||
{
|
||||
<span class="@($"rz-calendar rz-calendar-w-btn{(Disabled ? " rz-state-disabled" : "")}")" style="width:100%">
|
||||
<input @ref="@input" disabled="@Disabled" readonly="@IsReadonly" value="@FormattedValue" tabindex="@TabIndex"
|
||||
@onchange="@ParseDate" autocomplete="off" type="text"
|
||||
class="rz-inputtext @InputClass" id="@Name" placeholder="@Placeholder" />
|
||||
<button onclick="@getOpenPopup()" class="@($"rz-datepicker-trigger rz-calendar-button rz-button rz-button-icon-only{(Disabled ? " rz-state-disabled" : "")}")" tabindex="-1" type="button">
|
||||
<input @ref="@input" disabled="@Disabled" readonly="@IsReadonly" value="@FormattedValue" tabindex="@(Disabled ? "-1" : $"{TabIndex}")"
|
||||
@onchange="@ParseDate" autocomplete="off" type="text" name="@Name"
|
||||
class="rz-inputtext @InputClass @(IsReadonly ? "rz-readonly" : "")" id="@Name" placeholder="@Placeholder" onclick="@getOpenPopupForInput()"/>
|
||||
<button @onmousedown=@OnToggle onclick="@getOpenPopup()" class="@($"rz-datepicker-trigger rz-calendar-button rz-button rz-button-icon-only{(Disabled ? " rz-state-disabled" : "")}")" tabindex="-1" type="button">
|
||||
<span aria-hidden="true" class="rz-button-icon-left rzi rzi-calendar"></span><span class="rz-button-text"></span>
|
||||
</button>
|
||||
@if (AllowClear && HasValue)
|
||||
@@ -27,18 +27,18 @@
|
||||
</span>
|
||||
}
|
||||
|
||||
<div id="@PopupID" style=@PopupStyle class="@($"{(Inline ? "rz-datepicker-inline " : "")}rz-datepicker")" @onclick:preventDefault="true">
|
||||
<Popup id="@PopupID" Lazy=@(PopupRenderMode == PopupRenderMode.OnDemand) @ref=@popup style=@PopupStyle class="@($"{(Inline ? "rz-datepicker-inline " : "")}rz-datepicker")">
|
||||
<div class="rz-datepicker-group">
|
||||
@if (!TimeOnly)
|
||||
{
|
||||
<div class="rz-datepicker-header">
|
||||
<a href="javascript:void(0)" class="rz-datepicker-prev" @onclick="@(async () => { if (!Disabled) { CurrentDate = CurrentDate.AddMonths(-1); } })">
|
||||
<a href="javascript:void(0)" class="rz-datepicker-prev" @onclick="@(async () => { if (!Disabled) { try { if(CurrentDate.AddMonths(-1).Year >= YearFrom) {CurrentDate = CurrentDate.AddMonths(-1);}} catch (ArgumentOutOfRangeException) {}} })">
|
||||
<span class="rz-datepicker-prev-icon rzi rzi-chevron-left"></span>
|
||||
</a>
|
||||
<a href="javascript:void(0)" class="rz-datepicker-next" @onclick="@(async () => { if (!Disabled) { CurrentDate = CurrentDate.AddMonths(1); } })">
|
||||
<a href="javascript:void(0)" class="rz-datepicker-next" @onclick="@(async () => { if (!Disabled) { try { if(CurrentDate.AddMonths(1).Year <= YearTo) {CurrentDate = CurrentDate.AddMonths(1);}} catch (ArgumentOutOfRangeException) {} } })">
|
||||
<span class="rz-datepicker-next-icon rzi rzi-chevron-right"></span>
|
||||
</a>
|
||||
<div class="rz-datepicker-title" style="height:40px;">
|
||||
<div class="rz-datepicker-title">
|
||||
<RadzenDropDown @ref="monthDropDown" Style="height:auto;width:120px;margin-top:5px;text-align:left;" TabIndex="-1"
|
||||
TValue="int" Value="@CurrentDate.Month" Disabled="@Disabled" Data="@months" TextProperty="Name" ValueProperty="Value"
|
||||
Change="@((args) => { SetMonth(int.Parse(args.ToString())); })" />
|
||||
@@ -68,21 +68,26 @@
|
||||
<tr>
|
||||
@for (int j = 0; j < 7; j++)
|
||||
{
|
||||
@if((DateTime.MaxValue - StartDate).TotalDays <= dayNumber)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
DateTime date = StartDate.AddDays(dayNumber++);
|
||||
var dateArgs = DateAttributes(date);
|
||||
|
||||
@if (CurrentDate.Month == date.Month)
|
||||
{
|
||||
<td @attributes="@(dateArgs.Attributes)" onmouseup=@(Inline || ShowTime ? "" : $"Radzen.closePopup('{PopupID}')")
|
||||
<td @attributes="@(dateArgs.Attributes)" onmouseup=@(Inline || ShowTime || dateArgs.Disabled ? "" : $"Radzen.closePopup('{PopupID}')")
|
||||
@onclick="@(async () => { if (!Disabled && !dateArgs.Disabled) { await SetDay(date); } })">
|
||||
<span class=@($"rz-state-default{(DateTimeValue.HasValue && DateTimeValue.Value.Year == date.Year && DateTimeValue.Value.Month == date.Month && DateTimeValue.Value.Day == date.Day ? " rz-state-active" : "")}{(!dateArgs.Disabled ? "" : " rz-state-disabled")}")>@date.Day</span>
|
||||
<span class=@($"rz-state-default{(DateTimeValue.HasValue && DateTimeValue.Value.Date.CompareTo(date.Date)== 0 ? " rz-state-active" : "")}{(DateTime.Now.Date.CompareTo(date.Date) == 0 ? " rz-datepicker-currentday" : "")}{(!dateArgs.Disabled ? "" : " rz-state-disabled")}")>@date.Day</span>
|
||||
</td>
|
||||
}
|
||||
else
|
||||
{
|
||||
<td @attributes="@(dateArgs.Attributes)" class="rz-datepicker-other-month" onmouseup=@(Inline || ShowTime ? "" : $"Radzen.closePopup('{PopupID}')")
|
||||
<td @attributes="@(dateArgs.Attributes)" class="rz-datepicker-other-month" onmouseup=@(Inline || ShowTime || dateArgs.Disabled ? "" : $"Radzen.closePopup('{PopupID}')")
|
||||
@onclick="@(async () => { if (!Disabled && !dateArgs.Disabled) { await SetDay(date); } })">
|
||||
<span class="rz-state-default rz-state-disabled">@date.Day</span>
|
||||
<span class=@($"rz-state-default{(!dateArgs.Disabled ? "" : " rz-state-disabled")} rz-datepicker-other-month")>@date.Day</span>
|
||||
</td>
|
||||
}
|
||||
}
|
||||
@@ -91,42 +96,48 @@
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
@if (FooterTemplate != null)
|
||||
{
|
||||
<div class="rz-datepicker-footer">
|
||||
@FooterTemplate
|
||||
</div>
|
||||
}
|
||||
}
|
||||
</div>
|
||||
@if (ShowTime)
|
||||
{
|
||||
<div class="rz-timepicker">
|
||||
<div class="rz-timepicker" @onmousedown:stopPropagation>
|
||||
<RadzenNumeric TValue="int" Disabled="@Disabled" Value="@(HourFormat == "12" ? ((CurrentDate.Hour + 11) % 12) + 1 : CurrentDate.Hour)"
|
||||
Min="@(HourFormat == "12" ? 1 : -1)" Max="@(HourFormat == "12" ? 12 : 24)" TValue="double" Step="@HoursStep"
|
||||
Change="@UpdateHour" class="rz-hour-picker" @oninput=@OnUpdateHourInput />
|
||||
Change="@UpdateHour" class="rz-hour-picker" @oninput=@OnUpdateHourInput Format="@(PadHours ? "00" : "")" />
|
||||
<div class="rz-separator">
|
||||
<span>:</span>
|
||||
</div>
|
||||
<RadzenNumeric TValue="int" Disabled="@Disabled" Value="CurrentDate.Minute" TValue="double" Step="@MinutesStep" Min="0" Max="59"
|
||||
Change="@UpdateMinutes" class="rz-minute-picker" @oninput=@OnUpdateHourMinutes />
|
||||
Change="@UpdateMinutes" class="rz-minute-picker" @oninput=@OnUpdateHourMinutes Format="@(PadMinutes ? "00" : "")" />
|
||||
@if (ShowSeconds)
|
||||
{
|
||||
<div class="rz-separator">
|
||||
<span>:</span>
|
||||
</div>
|
||||
<RadzenNumeric TValue="int" Disabled="@Disabled" Value="CurrentDate.Second" TValue="double" Step="@SecondsStep" Min="0" Max="59"
|
||||
Change="@UpdateSeconds" class="rz-second-picker" @oninput=@OnUpdateHourSeconds />
|
||||
Change="@UpdateSeconds" class="rz-second-picker" @oninput=@OnUpdateHourSeconds Format="@(PadSeconds ? "00" : "")"/>
|
||||
}
|
||||
@if (HourFormat == "12")
|
||||
{
|
||||
<div class="rz-ampm-picker">
|
||||
<a href="javascript:void(0)" @onclick="@AmToPm">
|
||||
<a href="javascript:void(0)" @onclick="@ToggleAmPm">
|
||||
<span class="rzi rzi-chevron-up"></span>
|
||||
</a>
|
||||
<span>@CurrentDate.ToString("tt")</span>
|
||||
<a href="javascript:void(0)" @onclick="@PmToAm">
|
||||
<a href="javascript:void(0)" @onclick="@ToggleAmPm">
|
||||
<span class="rzi rzi-chevron-down"></span>
|
||||
</a>
|
||||
</div>
|
||||
}
|
||||
@if (ShowTimeOkButton)
|
||||
{
|
||||
<button type="button" class="rz-button rz-button-md btn-secondary" style="width:60px;padding:0px;margin-left:10px;"
|
||||
<button type="button" class="rz-button rz-button-md rz-secondary"
|
||||
@onclick="@OkClick"
|
||||
onmouseup="@($"Radzen.closePopup('{PopupID}')")">
|
||||
<span class="rz-button-text">Ok</span>
|
||||
@@ -134,7 +145,7 @@
|
||||
}
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
</Popup>
|
||||
|
||||
</div>
|
||||
}
|
||||
|
||||
@@ -26,52 +26,39 @@ namespace Radzen.Blazor
|
||||
RadzenDropDown<int> monthDropDown;
|
||||
RadzenDropDown<int> yearDropDown;
|
||||
|
||||
async Task AmToPm()
|
||||
async Task ToggleAmPm()
|
||||
{
|
||||
if (amPm == "am" && !Disabled)
|
||||
{
|
||||
amPm = "pm";
|
||||
if (Disabled) return;
|
||||
|
||||
var currentHour = ((CurrentDate.Hour + 11) % 12) + 1;
|
||||
var currentHour = ((CurrentDate.Hour + 11) % 12) + 1;
|
||||
int newHour = 0;
|
||||
|
||||
var newHour = currentHour - 12;
|
||||
|
||||
if (newHour < 1)
|
||||
{
|
||||
newHour = currentHour;
|
||||
}
|
||||
|
||||
var newValue = new DateTime(CurrentDate.Year, CurrentDate.Month, CurrentDate.Day, newHour, CurrentDate.Minute, CurrentDate.Second);
|
||||
|
||||
if (!object.Equals(newValue, Value))
|
||||
{
|
||||
await UpdateValueFromTime(newValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async Task PmToAm()
|
||||
{
|
||||
if (amPm == "pm" && !Disabled)
|
||||
if (amPm == "pm")
|
||||
{
|
||||
amPm = "am";
|
||||
|
||||
var currentHour = ((CurrentDate.Hour + 11) % 12) + 1;
|
||||
|
||||
var newHour = currentHour + 12;
|
||||
newHour = currentHour + 12;
|
||||
|
||||
if (newHour > 23)
|
||||
{
|
||||
newHour = 0;
|
||||
}
|
||||
}
|
||||
else if (amPm == "am")
|
||||
{
|
||||
amPm = "pm";
|
||||
|
||||
var newValue = new DateTime(CurrentDate.Year, CurrentDate.Month, CurrentDate.Day, newHour, CurrentDate.Minute, CurrentDate.Second);
|
||||
newHour = currentHour - 12;
|
||||
|
||||
if (!object.Equals(newValue, Value))
|
||||
if (newHour < 1)
|
||||
{
|
||||
await UpdateValueFromTime(newValue);
|
||||
newHour = currentHour;
|
||||
}
|
||||
}
|
||||
|
||||
var newValue = new DateTime(CurrentDate.Year, CurrentDate.Month, CurrentDate.Day, newHour, CurrentDate.Minute, CurrentDate.Second);
|
||||
|
||||
await UpdateValueFromTime(newValue);
|
||||
}
|
||||
|
||||
int? hour;
|
||||
@@ -81,7 +68,8 @@ namespace Radzen.Blazor
|
||||
var value = $"{args.Value}";
|
||||
if (!string.IsNullOrWhiteSpace(value))
|
||||
{
|
||||
hour = (int)Convert.ChangeType(value, typeof(int));
|
||||
int outValue;
|
||||
hour = int.TryParse(value, NumberStyles.Integer, CultureInfo.InvariantCulture, out outValue) ? (int?)outValue : null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -93,7 +81,9 @@ namespace Radzen.Blazor
|
||||
var value = $"{args.Value}";
|
||||
if (!string.IsNullOrWhiteSpace(value))
|
||||
{
|
||||
minutes = (int)Convert.ChangeType(value, typeof(int));
|
||||
int outValue;
|
||||
minutes = int.TryParse(value, NumberStyles.Integer, CultureInfo.InvariantCulture, out outValue) ? (int?)outValue : null;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -104,7 +94,8 @@ namespace Radzen.Blazor
|
||||
var value = $"{args.Value}";
|
||||
if (!string.IsNullOrWhiteSpace(value))
|
||||
{
|
||||
seconds = (int)Convert.ChangeType(value, typeof(int));
|
||||
int outValue;
|
||||
seconds = int.TryParse(value, NumberStyles.Integer, CultureInfo.InvariantCulture, out outValue) ? (int?)outValue : null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -211,13 +202,24 @@ namespace Radzen.Blazor
|
||||
IList<NameValue> months;
|
||||
IList<NameValue> years;
|
||||
|
||||
int YearFrom { get; set; }
|
||||
int YearTo { get; set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void OnInitialized()
|
||||
{
|
||||
base.OnInitialized();
|
||||
|
||||
UpdateYearsAndMonths(Min, Max);
|
||||
|
||||
}
|
||||
|
||||
void UpdateYearsAndMonths(DateTime? min, DateTime? max)
|
||||
{
|
||||
YearFrom = min.HasValue ? min.Value.Year : int.Parse(YearRange.Split(':').First());
|
||||
YearTo = max.HasValue ? max.Value.Year : int.Parse(YearRange.Split(':').Last());
|
||||
months = Enumerable.Range(1, 12).Select(i => new NameValue() { Name = Culture.DateTimeFormat.GetMonthName(i), Value = i }).ToList();
|
||||
years = Enumerable.Range(int.Parse(YearRange.Split(':').First()), int.Parse(YearRange.Split(':').Last()) - int.Parse(YearRange.Split(':').First()) + 1)
|
||||
years = Enumerable.Range(YearFrom, YearTo - YearFrom + 1)
|
||||
.Select(i => new NameValue() { Name = $"{i}", Value = i }).ToList();
|
||||
}
|
||||
|
||||
@@ -251,6 +253,27 @@ namespace Radzen.Blazor
|
||||
[Parameter]
|
||||
public string InputClass { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the Minimum Selectable Date.
|
||||
/// </summary>
|
||||
/// <value>The Minimum Selectable Date.</value>
|
||||
[Parameter]
|
||||
public DateTime? Min { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the Maximum Selectable Date.
|
||||
/// </summary>
|
||||
/// <value>The Maximum Selectable Date.</value>
|
||||
[Parameter]
|
||||
public DateTime? Max { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the Initial Date/Month View.
|
||||
/// </summary>
|
||||
/// <value>The Initial Date/Month View.</value>
|
||||
[Parameter]
|
||||
public DateTime? InitialViewDate { get; set; }
|
||||
|
||||
DateTime? _dateTimeValue;
|
||||
|
||||
DateTime? DateTimeValue
|
||||
@@ -278,7 +301,7 @@ namespace Radzen.Blazor
|
||||
|
||||
DateRenderEventArgs DateAttributes(DateTime value)
|
||||
{
|
||||
var args = new Radzen.DateRenderEventArgs() { Date = value, Disabled = false };
|
||||
var args = new Radzen.DateRenderEventArgs() { Date = value, Disabled = (Min.HasValue && value < Min.Value) || (Max.HasValue && value > Max.Value) };
|
||||
|
||||
if (DateRender != null)
|
||||
{
|
||||
@@ -314,10 +337,21 @@ namespace Radzen.Blazor
|
||||
_value = value;
|
||||
_currentDate = default(DateTime);
|
||||
|
||||
DateTimeOffset? offset = value as DateTimeOffset?;
|
||||
if (offset != null && offset.HasValue)
|
||||
if (value is DateTimeOffset offset)
|
||||
{
|
||||
_dateTimeValue = offset.Value.DateTime;
|
||||
if (offset.Offset == TimeSpan.Zero && Kind == DateTimeKind.Local)
|
||||
{
|
||||
_dateTimeValue = offset.LocalDateTime;
|
||||
}
|
||||
else if (offset.Offset != TimeSpan.Zero && Kind == DateTimeKind.Utc)
|
||||
{
|
||||
_dateTimeValue = offset.UtcDateTime;
|
||||
}
|
||||
else
|
||||
{
|
||||
_dateTimeValue = DateTime.SpecifyKind(offset.DateTime, Kind);
|
||||
}
|
||||
|
||||
_value = _dateTimeValue;
|
||||
}
|
||||
else
|
||||
@@ -330,12 +364,6 @@ namespace Radzen.Blazor
|
||||
{
|
||||
DateTimeValue = null;
|
||||
}
|
||||
|
||||
if (DateTimeValue.HasValue && DateTimeValue.Value == default(DateTime))
|
||||
{
|
||||
_value = null;
|
||||
_dateTimeValue = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -349,11 +377,11 @@ namespace Radzen.Blazor
|
||||
{
|
||||
if (_currentDate == default(DateTime))
|
||||
{
|
||||
_currentDate = HasValue && DateTimeValue.Value != default(DateTime) ? DateTimeValue.Value : DateTime.Today;
|
||||
_currentDate = HasValue ? DateTimeValue.Value : InitialViewDate ?? DateTime.Today;
|
||||
}
|
||||
return _currentDate;
|
||||
}
|
||||
set
|
||||
set
|
||||
{
|
||||
_currentDate = value;
|
||||
CurrentDateChanged.InvokeAsync(value);
|
||||
@@ -370,8 +398,18 @@ namespace Radzen.Blazor
|
||||
{
|
||||
get
|
||||
{
|
||||
if (CurrentDate == DateTime.MinValue)
|
||||
{
|
||||
return DateTime.MinValue;
|
||||
}
|
||||
|
||||
var firstDayOfTheMonth = new DateTime(CurrentDate.Year, CurrentDate.Month, 1);
|
||||
|
||||
if (firstDayOfTheMonth == DateTime.MinValue)
|
||||
{
|
||||
return DateTime.MinValue;
|
||||
}
|
||||
|
||||
int diff = (7 + (firstDayOfTheMonth.DayOfWeek - Culture.DateTimeFormat.FirstDayOfWeek)) % 7;
|
||||
return firstDayOfTheMonth.AddDays(-1 * diff).Date;
|
||||
}
|
||||
@@ -484,7 +522,7 @@ namespace Radzen.Blazor
|
||||
|
||||
if (valid && !DateAttributes(value).Disabled)
|
||||
{
|
||||
newValue = value;
|
||||
newValue = TimeOnly && CurrentDate != null ? new DateTime(CurrentDate.Year, CurrentDate.Month, CurrentDate.Day, value.Hour, value.Minute, value.Second) : value;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -506,7 +544,7 @@ namespace Radzen.Blazor
|
||||
DateTimeValue = newValue;
|
||||
if ((typeof(TValue) == typeof(DateTimeOffset) || typeof(TValue) == typeof(DateTimeOffset?)) && Value != null)
|
||||
{
|
||||
DateTimeOffset? offset = DateTime.SpecifyKind((DateTime)Value, DateTimeKind.Utc);
|
||||
DateTimeOffset? offset = DateTime.SpecifyKind((DateTime)Value, Kind);
|
||||
await ValueChanged.InvokeAsync((TValue)(object)offset);
|
||||
}
|
||||
else
|
||||
@@ -526,6 +564,9 @@ namespace Radzen.Blazor
|
||||
|
||||
async Task Clear()
|
||||
{
|
||||
if (Disabled || ReadOnly)
|
||||
return;
|
||||
|
||||
Value = null;
|
||||
|
||||
await ValueChanged.InvokeAsync(default(TValue));
|
||||
@@ -611,6 +652,27 @@ namespace Radzen.Blazor
|
||||
[Parameter]
|
||||
public string SecondsStep { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether the hour picker is padded with a leading zero.
|
||||
/// </summary>
|
||||
/// <value><c>true</c> if hour component is padded; otherwise, <c>false</c>.</value>
|
||||
[Parameter]
|
||||
public bool PadHours { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether the minute picker is padded with a leading zero.
|
||||
/// </summary>
|
||||
/// <value><c>true</c> if hour component is padded; otherwise, <c>false</c>.</value>
|
||||
[Parameter]
|
||||
public bool PadMinutes { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether the second picker is padded with a leading zero.
|
||||
/// </summary>
|
||||
/// <value><c>true</c> if hour component is padded; otherwise, <c>false</c>.</value>
|
||||
[Parameter]
|
||||
public bool PadSeconds { get; set; }
|
||||
|
||||
enum StepType
|
||||
{
|
||||
/// <summary>
|
||||
@@ -671,7 +733,7 @@ namespace Radzen.Blazor
|
||||
/// </summary>
|
||||
/// <value>The year range.</value>
|
||||
[Parameter]
|
||||
public string YearRange { get; set; } = "1950:2050";
|
||||
public string YearRange { get; set; } = $"1950:{DateTime.Now.AddYears(30).Year}";
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the hour format.
|
||||
@@ -701,6 +763,13 @@ namespace Radzen.Blazor
|
||||
[Parameter]
|
||||
public EventCallback<TValue> ValueChanged { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the footer template.
|
||||
/// </summary>
|
||||
/// <value>The footer template.</value>
|
||||
[Parameter]
|
||||
public RenderFragment FooterTemplate { get; set; }
|
||||
|
||||
string contentStyle = "display:none;";
|
||||
|
||||
private string getStyle()
|
||||
@@ -739,7 +808,7 @@ namespace Radzen.Blazor
|
||||
{
|
||||
if ((typeof(TValue) == typeof(DateTimeOffset) || typeof(TValue) == typeof(DateTimeOffset?)) && Value != null)
|
||||
{
|
||||
DateTimeOffset? offset = DateTime.SpecifyKind((DateTime)Value, DateTimeKind.Utc);
|
||||
DateTimeOffset? offset = DateTime.SpecifyKind((DateTime)Value, Kind);
|
||||
await ValueChanged.InvokeAsync((TValue)(object)offset);
|
||||
}
|
||||
else
|
||||
@@ -765,7 +834,7 @@ namespace Radzen.Blazor
|
||||
{
|
||||
if (ShowTimeOkButton)
|
||||
{
|
||||
CurrentDate = new DateTime(newValue.Year, newValue.Month,newValue.Day, CurrentDate.Hour, CurrentDate.Minute, CurrentDate.Second);
|
||||
CurrentDate = new DateTime(newValue.Year, newValue.Month, newValue.Day, CurrentDate.Hour, CurrentDate.Minute, CurrentDate.Second);
|
||||
await OkClick();
|
||||
}
|
||||
else
|
||||
@@ -800,7 +869,12 @@ namespace Radzen.Blazor
|
||||
|
||||
private string getOpenPopup()
|
||||
{
|
||||
return !Disabled && !ReadOnly && !Inline ? $"Radzen.togglePopup(this.parentNode, '{PopupID}')" : "";
|
||||
return PopupRenderMode == PopupRenderMode.Initial && !Disabled && !ReadOnly && !Inline ? $"Radzen.togglePopup(this.parentNode, '{PopupID}')" : "";
|
||||
}
|
||||
|
||||
private string getOpenPopupForInput()
|
||||
{
|
||||
return PopupRenderMode == PopupRenderMode.Initial && !Disabled && !ReadOnly && !Inline && !AllowInput ? $"Radzen.togglePopup(this.parentNode, '{PopupID}')" : "";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -826,6 +900,12 @@ namespace Radzen.Blazor
|
||||
/// <inheritdoc />
|
||||
public override async Task SetParametersAsync(ParameterView parameters)
|
||||
{
|
||||
if (parameters.DidParameterChange(nameof(Min), Min) || parameters.DidParameterChange(nameof(Max), Max))
|
||||
{
|
||||
var min = parameters.GetValueOrDefault<DateTime?>(nameof(Min));
|
||||
var max = parameters.GetValueOrDefault<DateTime?>(nameof(Max));
|
||||
UpdateYearsAndMonths(min, max);
|
||||
}
|
||||
var shouldClose = false;
|
||||
|
||||
if (parameters.DidParameterChange(nameof(Visible), Visible))
|
||||
@@ -901,5 +981,22 @@ namespace Radzen.Blazor
|
||||
|
||||
return base.OnAfterRenderAsync(firstRender);
|
||||
}
|
||||
|
||||
Popup popup;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the render mode.
|
||||
/// </summary>
|
||||
/// <value>The render mode.</value>
|
||||
[Parameter]
|
||||
public PopupRenderMode PopupRenderMode { get; set; } = PopupRenderMode.Initial;
|
||||
|
||||
async Task OnToggle()
|
||||
{
|
||||
if (PopupRenderMode == PopupRenderMode.OnDemand && !Disabled && !ReadOnly && !Inline)
|
||||
{
|
||||
await popup.ToggleAsync(Element);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,14 +6,12 @@
|
||||
@code {
|
||||
public override RenderFragment Render()
|
||||
{
|
||||
var date = Scheduler.CurrentDate.Date;
|
||||
|
||||
var appointments = Scheduler.GetAppointmentsInRange(date, date.AddDays(1)).ToList();
|
||||
var appointments = Scheduler.GetAppointmentsInRange(StartDate, EndDate).ToList();
|
||||
|
||||
return
|
||||
@<CascadingValue Value=@Scheduler>
|
||||
<DayView StartDate=@StartDate EndDate=@EndDate StartTime=@StartTime EndTime=@EndTime Appointments=@appointments
|
||||
TimeFormat="@TimeFormat" />
|
||||
TimeFormat=@TimeFormat MinutesPerSlot=@MinutesPerSlot />
|
||||
</CascadingValue>
|
||||
;
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user