diff --git a/public/assets/comics/1/0000-angry_web_1312217558.png b/public/assets/comics/1/0000-angry_web_1312217558.png new file mode 100644 index 0000000..204b98c Binary files /dev/null and b/public/assets/comics/1/0000-angry_web_1312217558.png differ diff --git a/public/assets/comics/10/0002-owl-dimensionality-web_web_1312882080.png b/public/assets/comics/10/0002-owl-dimensionality-web_web_1312882080.png new file mode 100644 index 0000000..a397a4c Binary files /dev/null and b/public/assets/comics/10/0002-owl-dimensionality-web_web_1312882080.png differ diff --git a/public/assets/comics/11/0003-qa-black-magic_web_web_1312973269.png b/public/assets/comics/11/0003-qa-black-magic_web_web_1312973269.png new file mode 100644 index 0000000..45d72fc Binary files /dev/null and b/public/assets/comics/11/0003-qa-black-magic_web_web_1312973269.png differ diff --git a/public/assets/comics/12/0004-dark-intellisense_web_web_1313141785.png b/public/assets/comics/12/0004-dark-intellisense_web_web_1313141785.png new file mode 100644 index 0000000..07e85ed Binary files /dev/null and b/public/assets/comics/12/0004-dark-intellisense_web_web_1313141785.png differ diff --git a/public/assets/comics/13/0005-who-takes-the-credit_web_web_1313244880.png b/public/assets/comics/13/0005-who-takes-the-credit_web_web_1313244880.png new file mode 100644 index 0000000..c2f917a Binary files /dev/null and b/public/assets/comics/13/0005-who-takes-the-credit_web_web_1313244880.png differ diff --git a/public/assets/comics/14/0006-ergonomic-chairs_web_web_1313244999.png b/public/assets/comics/14/0006-ergonomic-chairs_web_web_1313244999.png new file mode 100644 index 0000000..1f72ee8 Binary files /dev/null and b/public/assets/comics/14/0006-ergonomic-chairs_web_web_1313244999.png differ diff --git a/public/assets/comics/15/0007-the-meaningful-deadline_web_web_1313685127.png b/public/assets/comics/15/0007-the-meaningful-deadline_web_web_1313685127.png new file mode 100644 index 0000000..da5abbd Binary files /dev/null and b/public/assets/comics/15/0007-the-meaningful-deadline_web_web_1313685127.png differ diff --git a/public/assets/comics/16/0008-green-productivity_web_web_1314037931.png b/public/assets/comics/16/0008-green-productivity_web_web_1314037931.png new file mode 100644 index 0000000..4c30551 Binary files /dev/null and b/public/assets/comics/16/0008-green-productivity_web_web_1314037931.png differ diff --git a/public/assets/comics/17/0009-from-scratch_web_web_1314809417.png b/public/assets/comics/17/0009-from-scratch_web_web_1314809417.png new file mode 100644 index 0000000..f2647a1 Binary files /dev/null and b/public/assets/comics/17/0009-from-scratch_web_web_1314809417.png differ diff --git a/public/assets/comics/18/0010-a-reward_web_web_1316015834.png b/public/assets/comics/18/0010-a-reward_web_web_1316015834.png new file mode 100644 index 0000000..7bdd5c3 Binary files /dev/null and b/public/assets/comics/18/0010-a-reward_web_web_1316015834.png differ diff --git a/public/assets/comics/19/0011-hard-discipline_web_web_1318625423.png b/public/assets/comics/19/0011-hard-discipline_web_web_1318625423.png new file mode 100644 index 0000000..a56966a Binary files /dev/null and b/public/assets/comics/19/0011-hard-discipline_web_web_1318625423.png differ diff --git a/public/assets/comics/2/01-boss_and_the_worker-out_web_1312287061.png b/public/assets/comics/2/01-boss_and_the_worker-out_web_1312287061.png new file mode 100644 index 0000000..f439717 Binary files /dev/null and b/public/assets/comics/2/01-boss_and_the_worker-out_web_1312287061.png differ diff --git a/public/assets/comics/20/0012-breaking-the-nda-web_web_1321141101.png b/public/assets/comics/20/0012-breaking-the-nda-web_web_1321141101.png new file mode 100644 index 0000000..013bc92 Binary files /dev/null and b/public/assets/comics/20/0012-breaking-the-nda-web_web_1321141101.png differ diff --git a/public/assets/comics/21/0013-thorough-nda-web_web_1321359683.png b/public/assets/comics/21/0013-thorough-nda-web_web_1321359683.png new file mode 100644 index 0000000..712c9a1 Binary files /dev/null and b/public/assets/comics/21/0013-thorough-nda-web_web_1321359683.png differ diff --git a/public/assets/comics/22/0014-santa-courier-web_web_1322411181.png b/public/assets/comics/22/0014-santa-courier-web_web_1322411181.png new file mode 100644 index 0000000..becb228 Binary files /dev/null and b/public/assets/comics/22/0014-santa-courier-web_web_1322411181.png differ diff --git a/public/assets/comics/23/0015-write-it-a-thousand-times-web_web_1322855667.png b/public/assets/comics/23/0015-write-it-a-thousand-times-web_web_1322855667.png new file mode 100644 index 0000000..6db71fd Binary files /dev/null and b/public/assets/comics/23/0015-write-it-a-thousand-times-web_web_1322855667.png differ diff --git a/public/assets/comics/24/0016-touch-the-tiles-web_web_1323309221.png b/public/assets/comics/24/0016-touch-the-tiles-web_web_1323309221.png new file mode 100644 index 0000000..3f792ef Binary files /dev/null and b/public/assets/comics/24/0016-touch-the-tiles-web_web_1323309221.png differ diff --git a/public/assets/comics/25/0017-lazy-evaluation-web_web_1323736761.png b/public/assets/comics/25/0017-lazy-evaluation-web_web_1323736761.png new file mode 100644 index 0000000..6692947 Binary files /dev/null and b/public/assets/comics/25/0017-lazy-evaluation-web_web_1323736761.png differ diff --git a/public/assets/comics/26/0018-replacement-with-a-script-web_web_1324658954.png b/public/assets/comics/26/0018-replacement-with-a-script-web_web_1324658954.png new file mode 100644 index 0000000..bbcc5aa Binary files /dev/null and b/public/assets/comics/26/0018-replacement-with-a-script-web_web_1324658954.png differ diff --git a/public/assets/comics/27/0019-human-resources-web_web_1325082644.png b/public/assets/comics/27/0019-human-resources-web_web_1325082644.png new file mode 100644 index 0000000..43ec768 Binary files /dev/null and b/public/assets/comics/27/0019-human-resources-web_web_1325082644.png differ diff --git a/public/assets/comics/28/0020-nonstop-dev-team_web_web_1330007563.png b/public/assets/comics/28/0020-nonstop-dev-team_web_web_1330007563.png new file mode 100644 index 0000000..da2e2d8 Binary files /dev/null and b/public/assets/comics/28/0020-nonstop-dev-team_web_web_1330007563.png differ diff --git a/public/assets/comics/29/0021-lsd_web_web_1335527057.png b/public/assets/comics/29/0021-lsd_web_web_1335527057.png new file mode 100644 index 0000000..83d222f Binary files /dev/null and b/public/assets/comics/29/0021-lsd_web_web_1335527057.png differ diff --git a/public/assets/comics/30/0022-badge-of-shame-web_web_1336135809.png b/public/assets/comics/30/0022-badge-of-shame-web_web_1336135809.png new file mode 100644 index 0000000..e1f6ba8 Binary files /dev/null and b/public/assets/comics/30/0022-badge-of-shame-web_web_1336135809.png differ diff --git a/public/assets/comics/31/0023-bloody-cartridge-web_web_1336498077.png b/public/assets/comics/31/0023-bloody-cartridge-web_web_1336498077.png new file mode 100644 index 0000000..46e8fd2 Binary files /dev/null and b/public/assets/comics/31/0023-bloody-cartridge-web_web_1336498077.png differ diff --git a/public/assets/comics/32/0024-from-the-ground-up-web_web_1336955366.png b/public/assets/comics/32/0024-from-the-ground-up-web_web_1336955366.png new file mode 100644 index 0000000..4bdb5fb Binary files /dev/null and b/public/assets/comics/32/0024-from-the-ground-up-web_web_1336955366.png differ diff --git a/public/assets/comics/33/0025-boxed-office-web_web_1337198604.png b/public/assets/comics/33/0025-boxed-office-web_web_1337198604.png new file mode 100644 index 0000000..beda19c Binary files /dev/null and b/public/assets/comics/33/0025-boxed-office-web_web_1337198604.png differ diff --git a/public/assets/comics/34/0026-pet-scanner-web_web_1337979080.png b/public/assets/comics/34/0026-pet-scanner-web_web_1337979080.png new file mode 100644 index 0000000..6bd4adc Binary files /dev/null and b/public/assets/comics/34/0026-pet-scanner-web_web_1337979080.png differ diff --git a/public/assets/comics/35/0027-skyscraper-web_web_1338077520.png b/public/assets/comics/35/0027-skyscraper-web_web_1338077520.png new file mode 100644 index 0000000..5483427 Binary files /dev/null and b/public/assets/comics/35/0027-skyscraper-web_web_1338077520.png differ diff --git a/public/assets/comics/36/0028-coin-machine-web_web_1338424277.png b/public/assets/comics/36/0028-coin-machine-web_web_1338424277.png new file mode 100644 index 0000000..0171ced Binary files /dev/null and b/public/assets/comics/36/0028-coin-machine-web_web_1338424277.png differ diff --git a/public/assets/comics/37/0029-amphetamine-coffee-web_web_1338592639.png b/public/assets/comics/37/0029-amphetamine-coffee-web_web_1338592639.png new file mode 100644 index 0000000..5564e09 Binary files /dev/null and b/public/assets/comics/37/0029-amphetamine-coffee-web_web_1338592639.png differ diff --git a/public/assets/comics/38/0030-office-animals-web_web_1339281061.png b/public/assets/comics/38/0030-office-animals-web_web_1339281061.png new file mode 100644 index 0000000..afffacd Binary files /dev/null and b/public/assets/comics/38/0030-office-animals-web_web_1339281061.png differ diff --git a/public/assets/comics/39/0031-project-triangle-web_web_1340062832.png b/public/assets/comics/39/0031-project-triangle-web_web_1340062832.png new file mode 100644 index 0000000..1e5bb0d Binary files /dev/null and b/public/assets/comics/39/0031-project-triangle-web_web_1340062832.png differ diff --git a/public/assets/comics/4/03-whole-food-honey-out_web_1312377904.png b/public/assets/comics/4/03-whole-food-honey-out_web_1312377904.png new file mode 100644 index 0000000..50b166a Binary files /dev/null and b/public/assets/comics/4/03-whole-food-honey-out_web_1312377904.png differ diff --git a/public/assets/comics/40/0032-investment-cloud-web_web_1340911880.png b/public/assets/comics/40/0032-investment-cloud-web_web_1340911880.png new file mode 100644 index 0000000..83a8c96 Binary files /dev/null and b/public/assets/comics/40/0032-investment-cloud-web_web_1340911880.png differ diff --git a/public/assets/comics/41/0033-the-smoker-web_web_1346260357.png b/public/assets/comics/41/0033-the-smoker-web_web_1346260357.png new file mode 100644 index 0000000..359e307 Binary files /dev/null and b/public/assets/comics/41/0033-the-smoker-web_web_1346260357.png differ diff --git a/public/assets/comics/42/0034-the-assassin-web_web_1349211995.png b/public/assets/comics/42/0034-the-assassin-web_web_1349211995.png new file mode 100644 index 0000000..c92c505 Binary files /dev/null and b/public/assets/comics/42/0034-the-assassin-web_web_1349211995.png differ diff --git a/public/assets/comics/43/0035-extra-dimension-web_web_1352715455.png b/public/assets/comics/43/0035-extra-dimension-web_web_1352715455.png new file mode 100644 index 0000000..f57e613 Binary files /dev/null and b/public/assets/comics/43/0035-extra-dimension-web_web_1352715455.png differ diff --git a/public/assets/comics/44/0036-budget-cuts-web_web_1354427969.png b/public/assets/comics/44/0036-budget-cuts-web_web_1354427969.png new file mode 100644 index 0000000..20cef04 Binary files /dev/null and b/public/assets/comics/44/0036-budget-cuts-web_web_1354427969.png differ diff --git a/public/assets/comics/5/0007-bugs_web_1312448241.png b/public/assets/comics/5/0007-bugs_web_1312448241.png new file mode 100644 index 0000000..5ccf94f Binary files /dev/null and b/public/assets/comics/5/0007-bugs_web_1312448241.png differ diff --git a/public/assets/comics/6/0008-food-chain_web_1312543561.png b/public/assets/comics/6/0008-food-chain_web_1312543561.png new file mode 100644 index 0000000..3f61ac5 Binary files /dev/null and b/public/assets/comics/6/0008-food-chain_web_1312543561.png differ diff --git a/public/assets/comics/7/0009-mono_web_1312634072.png b/public/assets/comics/7/0009-mono_web_1312634072.png new file mode 100644 index 0000000..ec274c6 Binary files /dev/null and b/public/assets/comics/7/0009-mono_web_1312634072.png differ diff --git a/public/assets/comics/8/0011-a-toilet-paper_web_1312711686.png b/public/assets/comics/8/0011-a-toilet-paper_web_1312711686.png new file mode 100644 index 0000000..2416e3b Binary files /dev/null and b/public/assets/comics/8/0011-a-toilet-paper_web_1312711686.png differ diff --git a/public/assets/comics/9/0001-a-diagram-web_web_1312798348.png b/public/assets/comics/9/0001-a-diagram-web_web_1312798348.png new file mode 100644 index 0000000..3a47fd5 Binary files /dev/null and b/public/assets/comics/9/0001-a-diagram-web_web_1312798348.png differ diff --git a/public/assets/icons/better-listview-32-1355160256.png b/public/assets/icons/better-listview-32-1355160256.png new file mode 100644 index 0000000..cf26e61 Binary files /dev/null and b/public/assets/icons/better-listview-32-1355160256.png differ diff --git a/public/assets/icons/better-listview-express-32-1355160327.png b/public/assets/icons/better-listview-express-32-1355160327.png new file mode 100644 index 0000000..cf26e61 Binary files /dev/null and b/public/assets/icons/better-listview-express-32-1355160327.png differ diff --git a/public/assets/icons/better-splitbutton-32-1355160307.png b/public/assets/icons/better-splitbutton-32-1355160307.png new file mode 100644 index 0000000..8d10eaa Binary files /dev/null and b/public/assets/icons/better-splitbutton-32-1355160307.png differ diff --git a/public/assets/icons/better-thumbnail-browser-32-1355160281.png b/public/assets/icons/better-thumbnail-browser-32-1355160281.png new file mode 100644 index 0000000..5a7d83d Binary files /dev/null and b/public/assets/icons/better-thumbnail-browser-32-1355160281.png differ diff --git a/public/assets/images/10/Column Headers In LargeIcons View_original_1298622038.png b/public/assets/images/10/Column Headers In LargeIcons View_original_1298622038.png new file mode 100644 index 0000000..be9bc3d Binary files /dev/null and b/public/assets/images/10/Column Headers In LargeIcons View_original_1298622038.png differ diff --git a/public/assets/images/11/ListView Image Shadows and Image Borders_original_1298622678.png b/public/assets/images/11/ListView Image Shadows and Image Borders_original_1298622678.png new file mode 100644 index 0000000..04c1d92 Binary files /dev/null and b/public/assets/images/11/ListView Image Shadows and Image Borders_original_1298622678.png differ diff --git a/public/assets/images/12/Multi Column Sort in List View_original_1298623013.png b/public/assets/images/12/Multi Column Sort in List View_original_1298623013.png new file mode 100644 index 0000000..d7ddc05 Binary files /dev/null and b/public/assets/images/12/Multi Column Sort in List View_original_1298623013.png differ diff --git a/public/assets/images/13/Checkboxes In LargeIcons View_original_1298623385.png b/public/assets/images/13/Checkboxes In LargeIcons View_original_1298623385.png new file mode 100644 index 0000000..23ac1d8 Binary files /dev/null and b/public/assets/images/13/Checkboxes In LargeIcons View_original_1298623385.png differ diff --git a/public/assets/images/14/Three State Checkboxes in List View_original_1298624577.png b/public/assets/images/14/Three State Checkboxes in List View_original_1298624577.png new file mode 100644 index 0000000..9b4aa8b Binary files /dev/null and b/public/assets/images/14/Three State Checkboxes in List View_original_1298624577.png differ diff --git a/public/assets/images/15/List View Tooltips Region And Owner Drawn Tooltips_original_1298632357.png b/public/assets/images/15/List View Tooltips Region And Owner Drawn Tooltips_original_1298632357.png new file mode 100644 index 0000000..9b0bcfc Binary files /dev/null and b/public/assets/images/15/List View Tooltips Region And Owner Drawn Tooltips_original_1298632357.png differ diff --git a/public/assets/images/17/Column Header Context Menu in List View_original_1298721855.png b/public/assets/images/17/Column Header Context Menu in List View_original_1298721855.png new file mode 100644 index 0000000..464a513 Binary files /dev/null and b/public/assets/images/17/Column Header Context Menu in List View_original_1298721855.png differ diff --git a/public/assets/images/18/Show Text When List View is Empty_original_1298629916.png b/public/assets/images/18/Show Text When List View is Empty_original_1298629916.png new file mode 100644 index 0000000..80f0347 Binary files /dev/null and b/public/assets/images/18/Show Text When List View is Empty_original_1298629916.png differ diff --git a/public/assets/images/19/Custom Embedded Control in List View for Editing_original_1298630263.png b/public/assets/images/19/Custom Embedded Control in List View for Editing_original_1298630263.png new file mode 100644 index 0000000..315c4f9 Binary files /dev/null and b/public/assets/images/19/Custom Embedded Control in List View for Editing_original_1298630263.png differ diff --git a/public/assets/images/20/Custom Item Size in List View_original_1298630739.png b/public/assets/images/20/Custom Item Size in List View_original_1298630739.png new file mode 100644 index 0000000..e8f2639 Binary files /dev/null and b/public/assets/images/20/Custom Item Size in List View_original_1298630739.png differ diff --git a/public/assets/images/21/List View Item Reordering Mark Preview_original_1298631798.png b/public/assets/images/21/List View Item Reordering Mark Preview_original_1298631798.png new file mode 100644 index 0000000..f9dafd7 Binary files /dev/null and b/public/assets/images/21/List View Item Reordering Mark Preview_original_1298631798.png differ diff --git a/public/assets/images/22/List View Owner Drawing Background Gradient_original_1298633053.png b/public/assets/images/22/List View Owner Drawing Background Gradient_original_1298633053.png new file mode 100644 index 0000000..9a8bd94 Binary files /dev/null and b/public/assets/images/22/List View Owner Drawing Background Gradient_original_1298633053.png differ diff --git a/public/assets/images/23/show-or-hide-checkboxes-for-specific-listview-items_original_1299748307.png b/public/assets/images/23/show-or-hide-checkboxes-for-specific-listview-items_original_1299748307.png new file mode 100644 index 0000000..714585a Binary files /dev/null and b/public/assets/images/23/show-or-hide-checkboxes-for-specific-listview-items_original_1299748307.png differ diff --git a/public/assets/images/25/focus-list-view-sub-items_original_1313674098.png b/public/assets/images/25/focus-list-view-sub-items_original_1313674098.png new file mode 100644 index 0000000..2ec7fff Binary files /dev/null and b/public/assets/images/25/focus-list-view-sub-items_original_1313674098.png differ diff --git a/public/assets/images/26/Advanced-Hit-Test_original_1326105831.png b/public/assets/images/26/Advanced-Hit-Test_original_1326105831.png new file mode 100644 index 0000000..0e7ad68 Binary files /dev/null and b/public/assets/images/26/Advanced-Hit-Test_original_1326105831.png differ diff --git a/public/assets/images/27/Background-Images_original_1326106027.png b/public/assets/images/27/Background-Images_original_1326106027.png new file mode 100644 index 0000000..1fdb177 Binary files /dev/null and b/public/assets/images/27/Background-Images_original_1326106027.png differ diff --git a/public/assets/images/29/Background-Images_original_1326106990.png b/public/assets/images/29/Background-Images_original_1326106990.png new file mode 100644 index 0000000..6a4a2ca Binary files /dev/null and b/public/assets/images/29/Background-Images_original_1326106990.png differ diff --git a/public/assets/images/31/Column-Images-Sub-Item-Images-Groups-Images_original_1326107040.png b/public/assets/images/31/Column-Images-Sub-Item-Images-Groups-Images_original_1326107040.png new file mode 100644 index 0000000..bff2ffd Binary files /dev/null and b/public/assets/images/31/Column-Images-Sub-Item-Images-Groups-Images_original_1326107040.png differ diff --git a/public/assets/images/32/Custom-Embedded-Controls-For-Label-Edit_original_1326107064.png b/public/assets/images/32/Custom-Embedded-Controls-For-Label-Edit_original_1326107064.png new file mode 100644 index 0000000..78b43e6 Binary files /dev/null and b/public/assets/images/32/Custom-Embedded-Controls-For-Label-Edit_original_1326107064.png differ diff --git a/public/assets/images/33/Custom-Sub-Item-Label-Edit_original_1326107089.png b/public/assets/images/33/Custom-Sub-Item-Label-Edit_original_1326107089.png new file mode 100644 index 0000000..c564275 Binary files /dev/null and b/public/assets/images/33/Custom-Sub-Item-Label-Edit_original_1326107089.png differ diff --git a/public/assets/images/34/Focusable-Advanced-Groups-With-Image-Support_original_1326107120.png b/public/assets/images/34/Focusable-Advanced-Groups-With-Image-Support_original_1326107120.png new file mode 100644 index 0000000..0131a64 Binary files /dev/null and b/public/assets/images/34/Focusable-Advanced-Groups-With-Image-Support_original_1326107120.png differ diff --git a/public/assets/images/36/product-image_original_1328613483.png b/public/assets/images/36/product-image_original_1328613483.png new file mode 100644 index 0000000..b1ed663 Binary files /dev/null and b/public/assets/images/36/product-image_original_1328613483.png differ diff --git a/public/assets/images/7/Overview Collage_original_1367470843.png b/public/assets/images/7/Overview Collage_original_1367470843.png new file mode 100644 index 0000000..9e0d06f Binary files /dev/null and b/public/assets/images/7/Overview Collage_original_1367470843.png differ diff --git a/public/assets/images/8/Column Header Images_original_1298620501.png b/public/assets/images/8/Column Header Images_original_1298620501.png new file mode 100644 index 0000000..609f503 Binary files /dev/null and b/public/assets/images/8/Column Header Images_original_1298620501.png differ diff --git a/public/assets/images/9/Column Header Reordering With Insertion Mark_original_1298621331.png b/public/assets/images/9/Column Header Reordering With Insertion Mark_original_1298621331.png new file mode 100644 index 0000000..64cc472 Binary files /dev/null and b/public/assets/images/9/Column Header Reordering With Insertion Mark_original_1298621331.png differ diff --git a/public/assets/screenshots/15/blv-overview_original_1326499754.png b/public/assets/screenshots/15/blv-overview_original_1326499754.png new file mode 100644 index 0000000..e67a355 Binary files /dev/null and b/public/assets/screenshots/15/blv-overview_original_1326499754.png differ diff --git a/public/assets/screenshots/15/blv-overview_thumb_1326499754.png b/public/assets/screenshots/15/blv-overview_thumb_1326499754.png new file mode 100644 index 0000000..0ad076e Binary files /dev/null and b/public/assets/screenshots/15/blv-overview_thumb_1326499754.png differ diff --git a/public/assets/screenshots/16/thumbnails_original_1312133021.png b/public/assets/screenshots/16/thumbnails_original_1312133021.png new file mode 100644 index 0000000..73f2398 Binary files /dev/null and b/public/assets/screenshots/16/thumbnails_original_1312133021.png differ diff --git a/public/assets/screenshots/16/thumbnails_thumb_1312133021.png b/public/assets/screenshots/16/thumbnails_thumb_1312133021.png new file mode 100644 index 0000000..f313523 Binary files /dev/null and b/public/assets/screenshots/16/thumbnails_thumb_1312133021.png differ diff --git a/public/assets/screenshots/18/betterlistview-tree-hierarchy_original_1313676477.png b/public/assets/screenshots/18/betterlistview-tree-hierarchy_original_1313676477.png new file mode 100644 index 0000000..2e30e56 Binary files /dev/null and b/public/assets/screenshots/18/betterlistview-tree-hierarchy_original_1313676477.png differ diff --git a/public/assets/screenshots/18/betterlistview-tree-hierarchy_thumb_1313676477.png b/public/assets/screenshots/18/betterlistview-tree-hierarchy_thumb_1313676477.png new file mode 100644 index 0000000..0065552 Binary files /dev/null and b/public/assets/screenshots/18/betterlistview-tree-hierarchy_thumb_1313676477.png differ diff --git a/public/assets/screenshots/21/multi-line-items_original_1312133213.png b/public/assets/screenshots/21/multi-line-items_original_1312133213.png new file mode 100644 index 0000000..35893f5 Binary files /dev/null and b/public/assets/screenshots/21/multi-line-items_original_1312133213.png differ diff --git a/public/assets/screenshots/21/multi-line-items_thumb_1312133213.png b/public/assets/screenshots/21/multi-line-items_thumb_1312133213.png new file mode 100644 index 0000000..aec5229 Binary files /dev/null and b/public/assets/screenshots/21/multi-line-items_thumb_1312133213.png differ diff --git a/public/assets/screenshots/34/better-splitbutton-overview_original_1328267692.png b/public/assets/screenshots/34/better-splitbutton-overview_original_1328267692.png new file mode 100644 index 0000000..2ff6a93 Binary files /dev/null and b/public/assets/screenshots/34/better-splitbutton-overview_original_1328267692.png differ diff --git a/public/assets/screenshots/34/better-splitbutton-overview_thumb_1328267692.png b/public/assets/screenshots/34/better-splitbutton-overview_thumb_1328267692.png new file mode 100644 index 0000000..d825313 Binary files /dev/null and b/public/assets/screenshots/34/better-splitbutton-overview_thumb_1328267692.png differ diff --git a/public/assets/screenshots/35/always-drop-down_original_1328267712.png b/public/assets/screenshots/35/always-drop-down_original_1328267712.png new file mode 100644 index 0000000..bb94151 Binary files /dev/null and b/public/assets/screenshots/35/always-drop-down_original_1328267712.png differ diff --git a/public/assets/screenshots/35/always-drop-down_thumb_1328267712.png b/public/assets/screenshots/35/always-drop-down_thumb_1328267712.png new file mode 100644 index 0000000..ba05d6c Binary files /dev/null and b/public/assets/screenshots/35/always-drop-down_thumb_1328267712.png differ diff --git a/public/assets/screenshots/36/flat-style_original_1328267962.png b/public/assets/screenshots/36/flat-style_original_1328267962.png new file mode 100644 index 0000000..6624418 Binary files /dev/null and b/public/assets/screenshots/36/flat-style_original_1328267962.png differ diff --git a/public/assets/screenshots/36/flat-style_thumb_1328267962.png b/public/assets/screenshots/36/flat-style_thumb_1328267962.png new file mode 100644 index 0000000..125f846 Binary files /dev/null and b/public/assets/screenshots/36/flat-style_thumb_1328267962.png differ diff --git a/public/assets/screenshots/37/image-list_original_1328268002.png b/public/assets/screenshots/37/image-list_original_1328268002.png new file mode 100644 index 0000000..22763e6 Binary files /dev/null and b/public/assets/screenshots/37/image-list_original_1328268002.png differ diff --git a/public/assets/screenshots/37/image-list_thumb_1328268002.png b/public/assets/screenshots/37/image-list_thumb_1328268002.png new file mode 100644 index 0000000..f1063d9 Binary files /dev/null and b/public/assets/screenshots/37/image-list_thumb_1328268002.png differ diff --git a/public/assets/screenshots/43/overview_original_1354296079.png b/public/assets/screenshots/43/overview_original_1354296079.png new file mode 100644 index 0000000..034dd8f Binary files /dev/null and b/public/assets/screenshots/43/overview_original_1354296079.png differ diff --git a/public/assets/screenshots/43/overview_thumb_1354296079.png b/public/assets/screenshots/43/overview_thumb_1354296079.png new file mode 100644 index 0000000..6c704c7 Binary files /dev/null and b/public/assets/screenshots/43/overview_thumb_1354296079.png differ diff --git a/public/assets/screenshots/44/using-auto-populate_original_1354296146.png b/public/assets/screenshots/44/using-auto-populate_original_1354296146.png new file mode 100644 index 0000000..cce7178 Binary files /dev/null and b/public/assets/screenshots/44/using-auto-populate_original_1354296146.png differ diff --git a/public/assets/screenshots/44/using-auto-populate_thumb_1354296146.png b/public/assets/screenshots/44/using-auto-populate_thumb_1354296146.png new file mode 100644 index 0000000..9080f7c Binary files /dev/null and b/public/assets/screenshots/44/using-auto-populate_thumb_1354296146.png differ diff --git a/public/assets/screenshots/45/using-sorting_original_1354296174.png b/public/assets/screenshots/45/using-sorting_original_1354296174.png new file mode 100644 index 0000000..104c7fd Binary files /dev/null and b/public/assets/screenshots/45/using-sorting_original_1354296174.png differ diff --git a/public/assets/screenshots/45/using-sorting_thumb_1354296174.png b/public/assets/screenshots/45/using-sorting_thumb_1354296174.png new file mode 100644 index 0000000..3e0f733 Binary files /dev/null and b/public/assets/screenshots/45/using-sorting_thumb_1354296174.png differ diff --git a/public/assets/screenshots/46/layout-thumbnails-spacing_original_1354296209.jpg b/public/assets/screenshots/46/layout-thumbnails-spacing_original_1354296209.jpg new file mode 100644 index 0000000..235ead8 Binary files /dev/null and b/public/assets/screenshots/46/layout-thumbnails-spacing_original_1354296209.jpg differ diff --git a/public/assets/screenshots/46/layout-thumbnails-spacing_thumb_1354296209.jpg b/public/assets/screenshots/46/layout-thumbnails-spacing_thumb_1354296209.jpg new file mode 100644 index 0000000..a2a4cc0 Binary files /dev/null and b/public/assets/screenshots/46/layout-thumbnails-spacing_thumb_1354296209.jpg differ diff --git a/public/class-reference/better-listview/hxlinktable.htc.html b/public/class-reference/better-listview/hxlinktable.htc.html index b716ec9..871bbfc 100644 --- a/public/class-reference/better-listview/hxlinktable.htc.html +++ b/public/class-reference/better-listview/hxlinktable.htc.html @@ -53,16 +53,16 @@ height="0" width="0" style="display:none;visibility:hidden"> - icon Better ListView
Ultimate ListView control for .NET
+ icon Better ListView
Ultimate ListView control for .NET
- icon Better Thumbnail Browser
Thumbnail loading and browsing control for .NET
+ icon Better Thumbnail Browser
Thumbnail loading and browsing control for .NET
- icon Better SplitButton
Free customizable dropdown button control
+ icon Better SplitButton
Free customizable dropdown button control
- icon Better ListView Express
Free edition with less features
+ icon Better ListView Express
Free edition with less features
@@ -135,236 +135,236 @@ height="0" width="0" style="display:none;visibility:hidden"> - @@ -135,236 +135,236 @@ height="0" width="0" style="display:none;visibility:hidden"> - @@ -135,236 +135,236 @@ height="0" width="0" style="display:none;visibility:hidden"> - @@ -135,236 +135,236 @@ height="0" width="0" style="display:none;visibility:hidden"> - @@ -135,236 +135,236 @@ height="0" width="0" style="display:none;visibility:hidden"> - @@ -135,236 +135,236 @@ height="0" width="0" style="display:none;visibility:hidden"> - @@ -135,236 +135,236 @@ height="0" width="0" style="display:none;visibility:hidden"> - @@ -135,236 +135,236 @@ height="0" width="0" style="display:none;visibility:hidden"> - @@ -135,236 +135,236 @@ height="0" width="0" style="display:none;visibility:hidden"> - @@ -103,1554 +103,1554 @@ var t = {"antispam":"capek-rulz","purchase_email":"valid purchase email","valid_

Visual Studio Toolbox Control Integration

- - - - -

The Most Complete Guide to Visual Studio Toolbox Control Integration

-

Libor -Tinka, Lead Developer, ComponentOwl.com

-

-

-

Contents

-

1. Introduction
-2. Prerequisites
-3. Creating a Sample Control
-4. Manual Toolbox Integration
-5. Toolbox Integration using TCI
-6. Toolbox Integration using DTE
-7. Toolbox Integration using VSI Packages
-8. Toolbox Integration using VSPackages
-9. Toolbox Integration using VSIX Packages
-10. Supporting Multiple Version of .NET Framework
-11. Sample Source Code

-

1. Introduction

-

This tutorial is intended for developers who would like to distribute their -WPF or WinForms controls and automatically put them into Visual Studio Toolbox -during installation.

-

I struggled with Toolbox integration earlier because there are several possible -approaches (harder to decide between them). Each approach have its own pros and cons and -no overall comparison is provided. I wrote this tutorial to shed some light on the topic -and spare you hours, maybe days of research and experimenting with aspects of -Visual Studio (Toolbox) extensibility.

-

We will first take a look on Toolbox control integration in general to get a -big picture. Each approach will be then discussed in detail and the following -question will be answered:

-
    -
  • How to install control in Visual Studio Toolbox?
  • -
  • How to update the control?
  • -
  • How to uninstall/remove the control?
  • -
  • How to support multiple Visual Studio versions?
  • -

-

There are several options on how to integrate your controls with Visual -Studio Toolbox:

-
    -
  • Manual installation
  • -
  • Toolbox Control Installer (TCI)
  • -
  • Visual Studio Automation Object Model (DTE)
  • -
  • VSPackage
  • -
  • VSI package
  • -
  • VSIX package
  • -
-

Manual installation

-

The simplest way of adding control into Visual Studio Toolbox is from within -the IDE.

-

This approach have one crucial drawback, which is that you leave Toolbox -integration to the user. Many developers are not that experienced with Visual -Studio and when your component is shipped, even if you provide appropriate -step-by-step guide, they may find it too complicated and rather try -another component which "just works". I thought that every developer using -Visual Studio is experienced enough to know how to add new items in VS Toolbox, -but I received few e-mails from users who uninstalled the product just because -the component have not appeared in the Toolbox and they thought it is broken -(without reading our documentation, of course). On the other hand, there is -a group of users who are not experienced developers, but are in charge of trying -some products in a given company (e.g. project managers). These people can -install the component, play with it and they would really appreciate if it just -works. This increases chance they will actually purchase your product.

-

Advantages: zero effort
-Disadvantages: require experienced users, slows user -producitivity, updating controls is not intuitive

-

Toolbox Control Installer (TCI)

-

Visual Studio 2005 SDK contained a VSPackage called Toolbox Control -Installer. This package comes pre-installed with Visual Studio 2008 and newer. -Its job is to simplify the specific task of extending Visual Studio Toolbox. -This approach requires you to install your assembly in GAC (Global Assembly -Cache) and create a key in Windows Registry.

-

Advantages: simple and fast component installation, updating -and removing
-Disadvantages: requires installation in GAC (not always -wanted), VS 2005 supported with SDK only

-

Visual Studio Automation Object Model (DTE)

-

If you are not afraid of COM, you can try DTE (Development Tools Environment) approach. -There is already a project on CodePlex called -Visual Studio Toolbox Manager, -which solves the toolbox integration problem using a simple command-line -application. The project is outdated since it does not support Visual Studio -2010 and newer. I made a project called DteToolboxInstaller, which -is also a command-line application and does support Visual Studio 2013, 2012, 2010, -2008 and 2005. You can use the project as you like. The main disadvantage of DTE -approach is the speed. The installer have to run devenv.exe using the automation interface, create a -fake VS Solution, open Toolbox, add the stuff and then close the Solution. The -whole process take no less than 10 seconds. If you want to integrate with two or -three versions of Visual Studio, it can take well over a minute.

-

Advantages: does not require updating registry or GAC, full -control over Toolbox
-Disadvantages: very slow, separate installation required for -every version of Visual Studio

-

VSPackage

-

A VSPackage seems to be a natural option. VSPackages allow any type -of Visual Studio extension and you can manipulate Toolbox as well. There was a trouble -with VSPackages in providing a Package Load Key (PLK) which can be -generated only manually using web form. The requirement for PLK vanished with -Visual Studio 2010 (hooray!). The nice thing about VSPackage approcach is that it does not slow -down the installation process. The package is loaded and the controls are installed -on-demand (when the Toolbox is opened for the first time after installation). -After trying all the approaches, using VSPackage seems to be fastest and most -universal one.

-

Advantages: quick installation, appearance in About box and -other extensibility features
-Disadvantages: cmplicated setup, each component requires its -own package if shipped separately

-

VSI Package

-

VSI packages are quite old but you can use them for integration with Visual -Studio 2005 and newer. It have very simple structure and you can create one even -without Visual Studio. The only trouble with VSI compared to other -approaches is invoking a wizard form which cannot be suppressed. The -installation just cannot run in "quiet" mode. Another trouble with VSI is that a -digital signature is required in order to get rid of a warning dialog. Your control will be always installed under "My Controls" tab in the -Toolbox, which is not always desirable.

-

Advantages: simple creation, installer provided by Visual -Studio, automated creation and signing requires several specific steps
-Disadvantages: no quiet mode (extra steps when custom installer -is used), manual uninstallation

-

VSIX Package

-

VSIX packages came with Visual Studio 2010 so you can integrate with 2010 or -newer. the .VSI and .VSIX file extensions are associated with Visual Studio so -you can simply double-click it or run it via shell. You can also run -VsixInstaller.exe utility that performs the installation. Good news: No more -nag screens when VSIX is not signed - the installer only contains a dialog with -simple text: "This extension does not contain a digital signature." -Even better news: The VsixInstaller supports quiet mode!

-

Please note that VSI and VSIX package installers contain features like -displaying EULA, choosing which components to install or localization. When -deploying your controls for use in Visual Studio, you won't need an installer on -top of the package.

-

Advantages: installer provided by Visual Studio, quiet mode, -fast installation
-Disadvantages: package project required, automated creation is -complicated, no support for VS 2005 and 2008

-

Comparison of Approaches

-

Here is a table summarizing features of the discussed approaches. As you can -see, the VSPackage approach gives you the most freedom, but is also hardest -to implement. We will discuss every approach so -that you will be able to impement the one that suits you best.

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 20052008201020122013SpeedInstall AutomationUninstall automation 
Manual installationdepends on user
TCIfast 
EnvDTEslow 
VSImoderate 
VSIXmoderate (faster than VSI) 
VSPackagefast 
- -

2. Prerequisites

-

We will focus on integration with Visual Studio 2010, 2012 and 2013. Hence you will need:

-
    -
  • Visual Studio 2010 (or 2012, 2013)
  • -
  • Visual Studio 2010 SDK (or 2012 SDK, 2013 SDK)
  • -
  • Microsoft Windows SDK
  • -
-

The VS SDK contains regpkg.exe tool and project templates discussed in VSIX -and VSPackage approaches.

-

The Windows SDK contains gacutil.exe, guidgen.exe, signtool.exe and other -useful tools.

-

There are two kinds of versioning used for Visual Studio. One is based on the -release name (e.g. Visual Studio 2008) and the other is a classic version number -(e.g. 8.0). Both will be used, so it should be noted which version numbers -correspond to which versions of Visual Studio:

- - - - - - - - - - - - - - - - - - - - - - - - - -
Release nameVersion number
Visual Studio 20058.0
Visual Studio 20089.0
Visual Studio 201010.0
Visual Studio 201211.0
Visual Studio 201312.0
-

3. Creating a Sample Control

-

We will start by creating simple WinForms control for integration in VS -Toolbox.

-

You can start with File - New - Project... (Control+Shift+N) and select -Windows Forms Controls Library template.

-

Of course, you can also create empty Class Library project, add references to -System.Drawing and System.Windows.Forms and create a new control. In fact, any -DLL containing public classes derived from Control will -suffice.

-

We want to support .NET Runtime version 4.0 and 4.5, so the control should be -built against .NET 4.0 to ensure compatibility (the lower framework version you -use, the wider range of compatible frameworks since they are backward -compatible). It should be noted that .NET 4.5 is an in-place update of .NET 4.0 -and hence the 4.5 assemblies will work on machines with 4.0 runtime installed -unless you use some feature specific to 4.5.

-

If you have multiple controls in your assembly and don't want to use some of -them in Toolbox, decorate them with ToolboxItem attribute with -defaultType parameter set to false:

-
-[ToolboxItem(false)]
-public class InvisibleControl : UserControl
-{
-  ...
-}
-
-

I have created a very simple control called SampleControl:

-

-

Finally, I set version of the assembly 3.3.0.0 (I chose just something else -than 1.0.0.0 to see where the specific version number appears).

-

Custom Transparent Icon for the Toolbox

-

Icons for Toolbox are 16 by 16 pixel images. Various image formats are supported -(BMP, JPEG, PNG and ICO). However, you need to -create 256-color BMP image to ensure transparency. The transparent color is determined by bottom left -pixel of the icon. Transparency works for magenta (#ff00ff):

-

-

The icon file should have same name as the control class (i.e. -SampleControl.BMP).

-

Finally, use ToolboxBitmapAttribute to link icon with the control class:

-
-[ToolboxBitmap(typeof(SampleControl), "Resources.SampleControl.bmp")]
-public partial class SampleControl : UserControl
-{
-	...
-}
-
-

Note that icon location matters, at least in C#. Since I have added -the icon under custom folder named Resources, I need to reference -Resources.SampleControl.bmp instead of just SampleControl.bmp.

-

Here is the resulting transparent icon in Toolbox:

-

-

Marking the Control as Toolbox Item

-

We can mark control as toolbox item by adding a ToolboxItemAttribute -with defaultType parameter set to true:

-
-[ToolboxItem(true)]
-public partial class SampleControl : UserControl
-...
-
-

This decoration is optional since the controls within assembly are -considered toolbox items by default. However, we can mark certain control -classes with ToolboxItem(false) to hide them from Toolbox. This -comes in handy when we have multiple projects and there are too many controls in -the Toolbox because loaded from all the other projects.

-

Signing the Assembly

-

The assembly containing controls (SampleControl.dll in our -case) should be strongly named if we want them installed in GAC -(Global Assembly Cache) later on. This is optional in most cases, but the Toolbox Controls -Installer approach requires the assembly being installed in GAC, hence the -strong name is necessary there.

-

To give an assembly a strong name, open project properties and find -Signing tab:

-

-

Check the "Sign the assembly" option and select "<New...>" -from the combo box. This will create a new .SNK file in your project which will -be used to sign the assembly. You can also browse for existing key file. If you -want to distribute multiple assemblies with custom controls, it is a best -practice to use same strong name key for each assembly (it is possible to have -one .SNK file located in Solution folder and put just a link to that file in -each project; when we browse for the key under the Signing tab, the link will be -used without copying the file).

-

The SNK (Strong Name Key) file is basically a private key to digitally sign -your assembly. There is also a public key which can be used to verify the -assembly and its shorter variant called "public key token" for assembly -identification.

-

4. Manual Toolbox Integration

-

Installing

-

To install component into Visual Studio Toolbox manually, open some form or -control in designer, open the Toolbox window (Control+Alt+X), right-click on the -Toolbox window and select "Choose Items...":

-

-

The "Choose Toolbox Items" dialog will show up:

-

-

You can browse for DLL file with your component by clicking the "Browse..." -button.

-

This is the simplest way of putting component in the Toolbox without extra -actions required.

-

This can be unpleasant for end-users since it means many clicks they have -to perform. I will explain how to integrate a component a little bit more so that it -will be visible under the ".NET Framework Components" tab in the above dialog box and -possibly show up in Toolbox automatically without extra effort of the user.

-

Making the Control Visible in "Choose Toolbox Items" Dialog Box

-

As you can see on the above picture, the SampleControl component is already -displayed in the dialog box under ".NET Framework Components" tab.

-

This is because the folder containing our control is registered as "assembly folder" in the -registry and hence is searched when the above dialog is populated.

-

You can register your own assembly this way by creating a key in registry:

-
32-bit OS: HKLM\SOFTWARE\Microsoft\.NETFramework\AssemblyFolders\<your control name>
-64-bit OS: HKLM\SOFTWARE\Wow6432Node\Microsoft\.NETFramework\AssemblyFolders\<your control name>
-

You can also create key for specific version of .NET runtime (this comes in -handy if you distribute different components for different versions of .NET):

-
32-bit OS: HKLM\SOFTWARE\Microsoft\.NETFramework\v4.0.30319\AssemblyFoldersEx\<your control name>
-64-bit OS: HKLM\SOFTWARE\Wow6432Node\Microsoft\.NETFramework\v4.0.30319\AssemblyFoldersEx\<your control name>
-

In both cases, the default value for the key is a string with full path to -the folder with your assembly.

-

You can specify Toolbox tab in which the component should show up by adding -subkey named "Toolbox" with single string value "TabName" this value has Toolbox -tab name as data. When you add such control in the Toolbox, it will reside under -new tab with the specified name:

-

-

-

The control should also appear in "Choose Toolbox Items" dialog box if it -is installed in Global Assembly Cache.

-

The control pops up in the Toolbox automatically in -its own tab in Visual Studio 2012/2013.

-

Installing the Control in GAC

-

The benefit of GAC (Global Assembly Cache) is that the user needs not to -browse for your control. He will just select it form the above dialog box -without having to know where it is actually installed (the dialog is populated -by controls from "assembly folders" and from the GAC).

-

The GAC have one useful feature and disadvantage at the same time: It allows -holding multiple versions of the same assembly. When user makes reference to -your control from GAC and set "Specific Version" to true in -Reference Properties window, it will be tied to that version. When you install an -"update", a new version will be added to GAC, but the user will stay with the -older one. Of course, the "Choose Toolbox Items" dialog will show both versions, -so the user can just replace old reference with the new one.

-

You can make the installer removing any older versions from GAC during -installation and add/keep just the newest one. This will force the user to -replace the reference since it breaks the build.

-

You can work with GAC by using tool called gacutil.exe or -from code. We will discuss both approaches.

-

The gacutil.exe is located in Microsoft Windows SDK directory. There are two -such extecutables:

-
c:\Program Files (x86)\Microsoft SDKs\Windows\v7.0A\Bin\gacutil.exe
-c:\Program Files (x86)\Microsoft SDKs\Windows\v7.0A\Bin\NETFX 4.0 Tools\gacutil.exe
-

The former is for .NET Framework up to version 3.5. The latter is for -.NET 4.0 and higher. This is for compatibility reasons as a separate GAC have -been introduced with .NET 4.0.

-

You can install an assembly to GAC by calling:

-
gacutil.exe /i SampleControl.dll
-

To uninstall it, we refer to our assembly by its assembly name, not file -name:

-
gacutil.exe /u SampleControl
-

Finally, you can check if the assembly is installed in GAC by listing any -instances of the provided name:

-
gacutil.exe /l SampleControl
-

It is not wise, however, to use gacutil.exe from a custom -installer as it is located in SDK that user might not have installed. -Furthermore, the SDK license does not allow bundling gacutil.exe -with your installer.

-

Some installers like Inno Setup or MSI allow installing in GAC anyway.

-

You can also work with GAC using -System.EnterpriseServices.Internal.Publish class. The class have two -methods: GacInstall and GacRemove. Both -methods take just path to assembly file as a parameter, so for example:

-
(new Publish()).GacInstall(assemblyPath);
-

will install the specified assembly in GAC.

-

Updating

-

Updating the control depends on how it is installed and referenced.

-

If you have added component in the Toolbox manually via "Choose Toolbox Items" -dialog box and "Browse..." button, i.e. as a file reference, the -default property of such reference is that it simply points to the specified -file no matter which version it have (unless user sets "Specific Version" to -true in reference properties window; the default is -false in this case). Simply replacing the DLL with the control by a newer -file will suffice. If the user have specified "Specific Version" to true, -the build will break because the reference is no longer valid. He needs to -replace the reference by a new one pointing on the same file which now have -newer version.

-

If you have added the component from GAC (these components also appear in the -"Choose Toolbox Items" dialog box), the "Specific Version" property of the -reference is true by default:

-

-

This means that even if you install a newer version of the component in GAC, -the project will still reference the older version and both versions will reside -in GAC.

-

If you remove all versions of the component from GAC (e.g. using -gacutil.exe) and then install just the newest one, the build will break -unless the user changed "Specific Version" property to false.

-

Removing

-

Removing the manually installed control consists of just reverting all the -steps done during the installation.

-

In case of file references, deleting the file is sufficient.

-

In case of tighter integration (GAC, registry), the registry keys need to be -deleted and the control can be removed from GAC (e.g. using gacutil.exe).

-

Resetting Toolbox and Clearing the Toolbox Cache

-

The Toolbox can fall into state where it does not display some items, some are -duplicate and some can be disabled. Sometimes the only remedy is to let Visual -Studio rebuild the -Toolbox from scratch.

-

To do that, right-click on the Toolbox window and select "Reset -Toolbox". Visual Studio will go through all the installed packages and reloads -components into the Toolbox.

-

If this won't help, you can perform hard reset of the Toolbox. Exit -Visual Studio and delete all .TBD files in the following folder:

-
\Users\<user>\AppData\Local\Microsoft\VisualStudio\10.0\
-

It should be up to four files:

-

-

Once removed, start Visual Studio again. After showing the Toolbox, all items -should load instead of loading only the cached versions.

-

5. Toolbox Integration using TCI

-

Installing

-

Toolbox Control Installer is a VS package pre-installed in Visual Studio 2008 and -newer. It looks in Windows registry for components and loads them in the -Toolbox.

-

Before using TCI, one can check if it is installed in the given version of -VS. For example, the following registry key should exist if the Visual Studio -2010 have TCI installed:

-
32-bit OS: HKLM\SOFTWARE\Microsoft\VisualStudio\10.0\Packages\{2c298b35-07da-45f1-96a3-be55d91c8d7a}
-64-bit OS: HKLM\SOFTWARE\Wow6432Node\Microsoft\VisualStudio\10.0\Packages\{2c298b35-07da-45f1-96a3-be55d91c8d7a}
-

The TCI package GUID is always the same so you can make the check for any -version of Visual Studio with the above key (only change the version number from -10.0 to corresponding version number, of course).

-

The only prerequisites for the assembly is that it should have strong name -(i.e. to be signed). See section "Creating the Sample Control" for more -information.

-

The installation consists of putting the control in GAC (see previous -section for more information) and creating registry keys.

-

Suppose we have the SampleControl installed in GAC:

-

-

We will make reference to this assembly from registry by creating the -following key:

-
32-bit OS: HKLM\SOFTWARE\Microsoft\VisualStudio\10.0\ToolboxControlsInstaller\SampleControl, Version=3.7.0.0, Culture=neutral, PublicKeyToken=3cc4c7b61201d46c
-64-bit OS: HKLM\SOFTWARE\Wow6432Node\Microsoft\VisualStudio\10.0\ToolboxControlsInstaller\SampleControl, Version=3.7.0.0, Culture=neutral, PublicKeyToken=3cc4c7b61201d46c
-

The default value for the key is the Toolbox tab name name you would like to -have for the component(s), e.g. "Component Owl".

-

Installing in Visual Studio 2012 and 2013

-

One extra step is required to make this work in Visual Studio 2012/2013, which is -adding the registry key also in its user config hive, i.e.:

-
HKCU\Software\Microsoft\VisualStudio\11.0_Config\ToolboxControlsInstaller\SampleControl, Version=3.7.0.0, Culture=neutral, PublicKeyToken=3cc4c7b61201d46c
-

for VS 2012. Use 12.0_Config for VS 2013.

-

Updating

-

Updating the component is very simple. Just modify the above registry keys by -changing the version number.

-

Removing

-

To remove the component, delete the above registry keys. You should also -remove the corresponding assembly from GAC.

-

Automating Integration with TCI using TciToolboxInstaller

-

I made a simple command-line application called TciToolboxInstaller -which does all the described steps. The usage is simple:

-
TciToolboxInstaller.exe [install|uninstall] [vs2005|vs2008|vs2010|vs2012|vs2013] [tab name] [assembly path]
-

For example, if you like to install SampleControl.dll in Visual Studio 2012 -Toolbox, just call:

-
TciToolboxInstaller.exe install vs2012 "Component Owl" SampleControl.dll
-

You can use quotes for the last two parameters if they contain spaces.

-

The TciToolboxInstaller project is contained in sample -source code.

-

6. Toolbox Integration using DTE

-

Installing

-

The -DTE (Development Tools Environment) approach does not require working -with GAC or registry. It remotely manipulates Visual Studio Toolbox and -adds/removes items as needed.

-

The whole installation is done from (managed) code using COM wrappers. It -works in the following steps:

-
    -
  • Check if an instance of Visual Studio is not running. If not, continue.
  • -
  • Retrieve an EnvDTE.DTE object corresponding to the - version of Visual Studio we want to integrate with.
  • -
  • Create a "dummy" project using the DTE object
  • -
  • Obtain Toolbox window and ToolBox object from it.
  • -
  • Find or create ToolBoxTab object.
  • -
  • Add item in the Toolbox tab (ToolBoxTab.ToolBoxItems.Add).
  • -
  • Wait until current instance of Visual Studio stops running.
  • -
-

Here are some of the step/strongs in C# code - it is an excerpt from -DteToolboxInstaller project provided in sample source code:

-
-// obtain a DTE object
-Type typeDTE = Type.GetTypeFromProgID("VisualStudio.DTE.11.0");
-
-DTE dte = (DTE)Activator.CreateInstance(typeDTE, true);
-
-// create a temporary file
-string tempFile = Path.GetFileNameWithoutExtension(Path.GetTempFileName());
-string tempDirectory = string.Format("{0}{1}", Path.GetTempPath(), tempFile);
-
-// create Visual Studio Solution
-Solution4 solution = (dte.Solution as Solution4);
-
-string templatePath = solution.GetProjectTemplate(TemplateName, "CSharp");
-
-solution.AddFromTemplate(templatePath, tempDirectory, DummyProjectName, false);
-
-// get Toolbox window
-Window window = dte.Windows.Item(Constants.vsWindowKindToolbox);
-
-// get Toolbox
-ToolBox toolBox = (ToolBox)window.Object;
-
-// get Toolbox tab
-ToolBoxTab toolBoxTab = (GetToolBoxTab(toolBox.ToolBoxTabs) ?? toolBox.ToolBoxTabs.Add(this.tabName));
-
-// add new item under the Toolbox tab
-toolBoxTab.ToolBoxItems.Add(assemblyName, this.assemblyPath, vsToolBoxItemFormat.vsToolBoxItemFormatDotNETComponent);
-
-// select the Toolbox tab
-toolBoxTab.Activate();
-
-// cleanup
-dte.Solution.Close(false);
-dte.Quit();
-Marshal.ReleaseComObject(dte);
-
-// wait till Visual Studio turns off completely
-if (IsVisualStudioRunning())
-{
-	Thread.Sleep(VisualStudioProcessTimeout);
-}
-
-

There are several obstacles on implementing the DTE approach.

-

First of all, we need to ensure that Visual Studio is not running during the -installation - this is because we want messages sent to Visual Studio instance -will arrive in the "invisible" one ran from our code and not the one which the -user have currently opened.

-

Similarly, we would like to wait a while until the instance terminates after -installation. This is necessary when integrating with multiple versions of -Visual Studio when just a single instance have to be running at a time. Doing two -installations too quickly in succession may cause the previous one to fail -because a Visual Studio instance is still running.

-

The communication between our code and Visual Studio is mediated by OLE -message filter which needs to be implemented. You can take a look on -DteToolboxInstaller (see below) source code, where is a working installer -implemented that uses this approach.

-

Updating and Removing

-

Since we have full control over the Toolbox with this approach, updating or -removing items/tabs is done with the corresponding DTE objects.

-

Automatic Integration with DTE using DteToolboxInstaller

-

I made a simple command-line application called DteToolboxInstaller -which does all the necessary steps and solves the deals with the discussed -obstacles. The usage is simple:

-
DteToolboxInstaller.exe [install|uninstall] [vs2005|vs2008|vs2010|vs2012|vs2013] [tab name] [assembly path]
-

For example, if you like to install SampleControl.dll in Visual Studio 2012 -Toolbox, just call:

-
DteToolboxInstaller.exe install vs2012 "Component Owl" SampleControl.dll
-

You can use quotes for the last two parameters if they contain spaces.

-

The DteToolboxInstaller project is contained in sample -source code.

-

7. Toolbox Integration using VSI Packages

-

Let's consider you don't have a custom installer and want to distribute your -components in some kind of simple extension package that Visual Studio -understands.

-

Visual Studio contains an installer for so called VSI packages that will -do the integration work for you. If you have Visual Studio installed, the .VSI -extension is already associated with the Visual Studio Content Installer.

-

Creating the VSI Package

-

I have created an empty folder and copied SampleControl.dll in -it. All that is needed to make a VSI package is to create a .VSCONTENT file, -which is simply a XML file satisfying -Visual Studio Content Installer schema:

-
-<VSContent xmlns="http://schemas.microsoft.com/developer/vscontent/2005"> 
-    <Content>
-        <FileName>SampleControl.dll</FileName>
-        <DisplayName>SampleControl</DisplayName>
-        <Description>ComponentOwl.com SampleControl</Description>
-        <FileContentType>Toolbox Control</FileContentType>
-        <ContentVersion>2.0</ContentVersion>
-    </Content>
-</VSContent>
-
-

The content is readable and pretty straightforward. The -ContentVersion element can contain either "1.0" (support for Visual -Studio 2005, 2008 and 2010) or "2.0" (support for Visual Studio 2008, 2010, -2012, 2013).

-

Now we zip the two files and rename extension of the archive to .VSI. We -should end up with the following three files:

-

-

If you double-click the SampleControl.vsi, the Visual Studio -Content Installer opens up. You can start the installer from command line as -well:

-
32-bit OS: C:\Program Files\Common Files\Microsoft Shared\MSEnv\VSContentInstaller.exe SampleControl.vsi
-64-bit OS: C:\Program Files (x86)\Common Files\Microsoft Shared\MSEnv\VSContentInstaller.exe SampleControl.vsi
-

The installer have a form o wizard:

-

-

Signing the VSI Package

-

By default, the VSI package is not signed. This causes showing: "Publisher: -Unknown" label on the first page of the installation wizard and an unpleasant -dialog box later on:

-

-

To avoid this, you need to digitally sign the VSI package. Of course, you -have to own a digital certificate (usually an X.509 certificate stored in .PFX -file).

-

Because we cannot sign ZIP files, we need to convert the .VSI file (which is -actually a ZIP archive with just an altered extension) to self-extracting archive that the Visual Studio Content -Installer recognizes. There is a tool called MakeZipExe -to do this task:

-
MakeZipExe.exe -zipfile:SampleControl.vsi -output:SampleControl-unsigned.vsi -overwrite
-

The MakeZipExe tool is located at Visual Studio's binary -folder:

-
c:\Program Files (x86)\Microsoft Visual Studio 11.0\Common7\IDE\MakeZipExe.exe
-

The second step is signing the .EXE file using signtool.exe. -You can find signtool.exe in Microsoft Windows SDK, i.e.:

-
c:\Program Files (x86)\Microsoft SDKs\Windows\v7.0A\Bin\signtool.exe
-

Here is a sample usage of signtool.exe:

-
signtool.exe sign /du "http://www.componentowl.com/sample-control" /f certificate.pfx /p abc123 /t "http://timestamp.comodoca.com/authenticode" "SampleControl-signed.vsi"
-

When signed, the "Publisher" and "Information URL" labels are filled in the -installer and no dialog box appears. The benefit of signing is obvious - your -users will know they are installing trusted, possibly high-quality software and there -is a higher chance of your software being used more widely (for example, the -government sector usually require such certified software).

-

You can also add an EULA to your VSI package. This can be done by adding a -comment metadata in the archive by ZIP archiver that supports such feature (e.g. -WinZip).

-

Uninstalling the Control from Toolbox

-

As far as I know, the control cannot be removed from the Toolbox -programmatically. You need to delete the control's DLL located at

-
c:\Users\<user>\Documents\Visual Studio 2010\Controls\
-

the same should be done for every version of Visual Studio installed.

-

In Visual Studio, right-click on Toolbox and select "Reset Toolbox". The -component will not be found and disappear. Similarly, you can just -delete the control from the Toolbox or select "Choose Items..." from context -menu and untick the control there:

-

 

-

Drawbacks of Using VSI Package

-

One drawback of using VSI package is that the installer runs every version of -VS IDE you have installed and which is supported by the package. The form will -disappear eventually, but it lowers user experience.

-

Another drawback is that when you want to update your control, the installer -offers whether to rename, replace or skip the file (e.g. SampleControl.dll). User have to decide to -update, which also slows down installation and requires user interaction.

-

You also cannot specify custom Toolbox tab. All controls are installed under -"My Controls" tab:

-

-

8. Toolbox Integration using VSPackages

-

This approach brings full control over the integration and other benefits. The VSPackages are loaded on-demand, so -the integration process won't slow down a custom installer.

-

Although VSPackage and our sample control can be packed within the same -assembly, we will create a separate Visual Studio Package project.

-

When user opens Toolbox in VS for the first time after installation, the IDE -will look in registry for any registered packages and load them (if not loaded -previously).

-

Creating VSPackage Project

-

We would like to have our VSPackage compatible with VS 2010, 2012 -and 2013, so we will work in Visual Studio 2010.

-

Select "File - New - Project.." (Control+Shift+N) and -select the "Visual Studio Package" template:

-

-

This will start a "Visual Studio Package Wizard":

-

-

You can leave most options in the wizard on defaults. Leave all the check boxes unchecked -on "Page 3 of 7" and "Page 7 of 7":

-

-

-

Now we will take a look on the generated files. Open the Guids.cs -file:

-
-// Guids.cs
-// MUST match guids.h
-using System;
-
-namespace ComponentOwl.ToolboxIntegration
-{
-    static class GuidList
-    {
-        public const string GuidSampleVSPackagePkgString = "00000000-8fdf-48b6-98f8-4ff21a3a4def";
-        public const string GuidSampleVSPackageCmdSetString = "def6519d-5ace-4062-95d6-4ee43f4a5de9";
-
-        public static readonly Guid GuidSampleVSPackageCmdSet = new Guid(GuidSampleVSPackageCmdSetString);
-    };
-}
-
-

Here are the GUIDs that -uniquely identify your package. I have edited the first four hex digits of -package identifier to "00000000" so that we can find it more easily later. This is -just for purpose of convenience in our sample project. Always use randomly generated GUID -in a real-world application. Visual Studio will generate a new GUID -whenever you create a new VSPackage project.

-

You can also generate new GUIDs any time, for example using -online GUID -generator or guidgen.exe utility from Windows SDK. When these numbers are changed, your package will be different from -Visual Studio's point of view.

-

Another important file here is source.extension.vsixmanifest. -If you double-click on the file in Solution Explorer, the VSIX Manifest Designer -will show up:

-

-

Not all the fields are mandatory, but I will fill all of them nevertheless:

-
    -
  • ID - Unique product "Identity" - the ID is limited to - 100 characters and the recommended format is "Company.Product.Feature.Name". - We can leave the VSPackage's GUID here.
  • -
  • Product Name - This field is used for Toolbox Tab name, - so I will put "Component Owl Controls" here.
  • -
  • Author - Your name or company name - - "ComponentOwl.com", for example.
  • -
  • Version - This is version of the package and its - contents. The format is same as for assembly versions: - Major.Minor.Build.Revision. I will put "1.4.0.128" here.
  • -
  • Description - Speaks for itself.
  • -
  • Locale - Language for the package.
  • -
  • Supported VS Editions - Here you can specify which - editions of Visual Studio 2010 you would like to support. Of course, it can - support VS 2012/2013 as well, but for now I will just check Ultimate, Premium and - Professional editions.
  • -
  • Supported Framework Runtime - Minimum and maximum .NET - Framework Runtime versions your extension supports. Since my component will - support 4.0 and 4.5 runtime, I will put 4.0 and 4.5 here.
  • -
-

Adding Support for Visual Studio 2012/2013

-

We have specified supported Visual Studio Editions in VSIX Manifest Designer, -through the "Visual Studio Version and Edition" dialog box:

-

-

As you can see, only Visual Studio 2010 is supported here because VSIX is new -to 2010 and of course VS 2010 does not know about 2012/2013. We have to -source.extensions.vsixmanifest file for manual editing. Select the file -in Solution Explorer and press F7 (View Code):

-
-<?xml version="1.0" encoding="utf-8"?>
-<Vsix xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" Version="1.0.0" xmlns="http://schemas.microsoft.com/developer/vsx-schema/2010">
-  <Identifier Id="aaaaaaaa-8fdf-48b6-98f8-4ff21a3a4def">
-    <Name>SampleVsPackage</Name>
-    <Author>ComponentOwl.com</Author>
-    <Version>1.0</Version>
-    <Description xml:space="preserve">Information about my package</Description>
-    <Locale>1033</Locale>
-    <InstalledByMsi>false</InstalledByMsi>
-    <SupportedProducts>
-      <VisualStudio Version="10.0">
-        <Edition>Ultimate</Edition>
-        <Edition>Premium</Edition>
-        <Edition>Pro</Edition>
-      </VisualStudio>
-    </SupportedProducts>
-    <SupportedFrameworkRuntimeEdition MinVersion="4.0" MaxVersion="4.5" />
-  </Identifier>
-  <References>
-    <Reference Id="Microsoft.VisualStudio.MPF" MinVersion="10.0">
-      <Name>Visual Studio MPF</Name>
-    </Reference>
-  </References>
-  <Content>
-    <VsPackage>|%CurrentProject%;PkgdefProjectOutputGroup|</VsPackage>
-  </Content>
-</Vsix>
-
-

Take a look on the Vsix/Identifier/SupportedProducts/VisualStudio -element (highlighted in bold). Copy and paste this element and modify -Version attribute on the second one to "11.0":

-
-<VisualStudio Version="11.0">
-  <Edition>Ultimate</Edition>
-  <Edition>Premium</Edition>
-  <Edition>Pro</Edition>
-</VisualStudio>
-
-

The edition tags are valid for version 11.0 because Visual Studio 2012 -template generates the same edition names.

-

Writing Package Code

-

Now we will take a look on the VSPackage code itself. Open the -SampleVSPackage.cs -file. I kept only the necessary code and added the ProvideToolboxItems attribute:

-
-[PackageRegistration(UseManagedResourcesOnly = true)]
-[InstalledProductRegistration("#110", "#112", "1.0", IconResourceID = 400)]
-[Guid(GuidList.guidSampleVsPackagePkgString)]
-[ProvideToolboxItems(1)]
-public sealed class SampleVsPackage : Package
-{
-}
-
-

Our VSPackage implementation inherits from -Microsoft.VisualStudio.Shell.Package class and is decorated by three -attributes:

-
    -
  • PackageRegistrationAttribute - Specifies that package - registration tool should look for additional attributes (will be discussed - later).
  • -
  • InstalledProductRegistrationAttribute - Provides - information for the Visual Studio splash screen and About box.
  • -
  • GuidAttribute - Provides custom GUID for the class - because automatic GUID is undesirable here (Visual Studio need to be able to trace our - package by its unique ID).
  • -
  • ProvideToolboxItemsAttribute - Specifies that the - package provides toolbox items. There are various uses of VSPackages, but we - are interested in intalling controls to Visual Studio Toolbox, hence this - attribute.
  • -
-

The strings "#110" and "#112" in -InstalledProductRegistrationAttribute refer to keys in -VSPackage.resx. You can open this file and edit package name and -description there:

-

-

Now we write methods within SampleVsPackage class that work with the Toolbox:

-
-private const string ComponentFile = "SampleControl.dll";
-private const string TabName = "Component Owl";
-
-private void InstallToolboxItems()
-{
-    IToolboxService toolboxService = (IToolboxService)GetService(typeof(IToolboxService));
-
-    foreach (ToolboxItem item in ToolboxService.GetToolboxItems(GetAssemblyName()))
-    {
-        toolboxService.AddToolboxItem(item, TabName);
-    }
-}
-
-private void RemoveToolboxItems()
-{
-    IToolboxService toolboxService = (IToolboxService)GetService(typeof(IToolboxService));
-
-    foreach (ToolboxItem item in ToolboxService.GetToolboxItems(GetAssemblyName()))
-    {
-        toolboxService.RemoveToolboxItem(item);
-    }
-}
-
-private AssemblyName GetAssemblyName()
-{
-    string pathAssembly = String.Concat(
-        Path.GetDirectoryName(GetType().Assembly.Location),
-        Path.DirectorySeparatorChar,
-        ComponentFile);
-
-    return AssemblyName.GetAssemblyName(pathAssembly);
-}
-
-

The method names InstallToolboxItems and -RemoveToolboxItems -speak for themselves. Both methods look for SampleControl.dll in the same -location as the VSPackage's assembly. They get all toolbox items from the -assembly and either put them under "Component Owl" tab or remove them.

-

The ToolboxService class comes from -System.Drawing.Design and we need to add reference to this asssembly in -order to use ToolboxService.

-

Building the Package

-

Before building the SampleVsPackage project, open project -properties, find the VSIX tab and uncheck all the options:

-

-

Finally, build the project. Just two files, SampleVsPackage.dll -and SampleVsPackage.pdb, should be generated.

-

Registering the Package

-

Until the package can be loaded by Visual Studio, it needs to be -registered. -The registration is simply writing specific keys into Windows Registry.

-

To do that, find the Package Registration Utility (RegPkg.exe). It should be -located in Visual Studio SDK directory, e.g.:

-
32-bit OS: c:\Program Files\Microsoft Visual Studio 11.0\VSSDK\VisualStudioIntegration\Tools\Bin\RegPkg.exe
-64-bit OS: c:\Program Files (x86)\Microsoft Visual Studio 11.0\VSSDK\VisualStudioIntegration\Tools\Bin\RegPkg.exe
-

You can copy the tool where it suits you.

-

Here is a sample usage of RegPkg:

-
32-bit OS: RegPkg.exe /root:SOFTWARE\Microsoft\VisualStudio\11.0 /codebase SampleVsPackage.dll
-64-bit OS: RegPkg.exe /root:SOFTWARE\Wow6432Node\Microsoft\VisualStudio\11.0 /codebase SampleVsPackage.dll
-

This will write package registration information into the Windows Registry, -hence registers the package. Similar call have to be done by your custom installer in -order to register the package.

-

Instead of writing into registry, RegPkg.exe can gereate a REG file (several -other formats are available) so that you can write package information into -registry using the file. To do that, use /regfile parameter:

-
32-bit OS: RegPkg.exe /root:SOFTWARE\Microsoft\VisualStudio\11.0 /regfile:SampleVsPackage.ref /codebase SampleVsPackage.dll
-64-bit OS: RegPkg.exe /root:SOFTWARE\Wow6432Node\Microsoft\VisualStudio\11.0 /regfile:SampleVsPackage.ref /codebase SampleVsPackage.dll
-

This creates SampleVsPackge.reg file you can use any time -later instead of RegPkg.exe itself.

-

There are two other options for specifying how the package will be registered: -codebase and assembly. When /codebase -parameter is used (as in the sample above), the registry will point to the location on disk where your -package is located (see - -Assembly.CodeBase property for more information).

-

Another option is the /assembly parameter - this assumbes -that your VSPackage assembly is located in GAC (Global Assembly Cache). See -section Installing the Control in GAC for more information.

-

You can check out the registry after the package registration:

-

-

Package Registration for Visual Studio 2012/2013

-

Regrettably, simply registering package is not enough for Visual Studio 2012/2013 to load -it (see this - -blog post). Because of performance optimizations, VS developers removed -feature that looks for changes in VS registry root and thus we need to call

-
devenv.exe /Setup
-

In order to finish package registration.

-

This call can be very time consuming since Visual Studio 2012/2013 goes through all -extensions and looks for changes. On the other hand, I tried running devenv.exe with /Setup -parameter on fresh install of Visual Studio 2012/2013 and it was instant. On older -installation, however, the operation took well over a minute (it behaves just -like Microsoft Windows, which progressively slows down during its lifetime).

-

We can speed things up by a little hack. One of the things the /Setup -does is copying registry keys from HKLM to Visual Studio's 11.0_Config hive (or 12.0_Config, respectively). We can just write registry under this key -instead of calling devenv.exe and avoid possibly lengthy operation.

-

The hive is located in -HKEY_CURRENT_USER\Software\Microsoft\VisualStudio\11.0_Config.

-

So let's open and edit the SampleVsPackage.reg file we have -generated using RegPkg.exe earlier. Here is the modified version where only the -registry root has been changed:

-
-REGEDIT4
-
-[HKEY_CURRENT_USER\Software\Microsoft\VisualStudio\11.0_Config\InstalledProducts\SampleVsPackage]
-@="#110"
-"Package"="{00000000-8fdf-48b6-98f8-4ff21a3a4def}"
-"PID"="1.0"
-"ProductDetails"="#112"
-"LogoID"="#400"
-[HKEY_CURRENT_USER\Software\Microsoft\VisualStudio\11.0_Config\Packages\{00000000-8fdf-48b6-98f8-4ff21a3a4def}]
-@="ComponentOwl.ToolboxIntegration.SampleVsPackage, SampleVsPackage, Version=1.0.0.0, Culture=neutral, PublicKeyToken=30782fc44cbe0af5"
-"InprocServer32"="C:\\Windows\\SYSTEM32\\MSCOREE.DLL"
-"Class"="ComponentOwl.ToolboxIntegration.SampleVsPackage"
-"CodeBase"="C:\\projects\\articles\\2012-10-22 Visual Studio Toolbox Control Integration\\ToolboxIntegration\\SampleVsPackage\\bin\\Debug\\SampleVsPackage.DLL"
-[HKEY_CURRENT_USER\Software\Microsoft\VisualStudio\11.0_Config\Packages\{00000000-8fdf-48b6-98f8-4ff21a3a4def}]
-[HKEY_CURRENT_USER\Software\Microsoft\VisualStudio\11.0_Config\Packages\{00000000-8fdf-48b6-98f8-4ff21a3a4def}\Toolbox]
-"Default Items"=dword:00000001
-
-

The highlighted parts have been edited.

-

So in addition to standard package registration, we also write in the -registry where Visual Studio 2012/2013 user config hive resides. This is sufficient -for our VSPackage to load.

-

However, this is really a hack - editing of user configuration in registry -may cause Visual Studio to not load your user settings and show up as when -running for the first time. I tried this hack on my machine and it worked, but -there may be some hidden glitches. If you want to follow standard procedure, -just call "devenv.exe /Setup".

-

Loading VSPackage

-

If you did all the previous steps, your package should load when you open -Windows Forms Designer and show Toolbox (Cotrol+Alt+X). You can notice your -package name displaying in status bar for a while, then SampleControl should show up in the -Toolbox under "Component Owl" tab:

-

-

Displaying Your Extension in VS About Box

-

If you want information about your extension to be visible in Visual Studio -splash screen and About Box, implement IVsInstalledProduct -interface:

-
-...
-
-public sealed class SampleVsPackage : Package, IVsInstalledProduct
-{
-
-...
-
-	int IVsInstalledProduct.IdBmpSplash(out uint pIdBmp)
-	{
-	    pIdBmp = 0;
-	    return 0;
-	}
-	
-	int IVsInstalledProduct.IdIcoLogoForAboutbox(out uint pIdIco)
-	{
-	    pIdIco = 400;
-	    return 0;
-	}
-	
-	int IVsInstalledProduct.OfficialName(out string pbstrName)
-	{
-	    pbstrName = "ComponentOwl SampleControl";
-	    return 0;
-	}
-	
-	int IVsInstalledProduct.ProductDetails(out string pbstrProductDetails)
-	{
-	    pbstrProductDetails = "SampleControl control.\r\nFor more information see http://www.componentowl.com";
-	    return 0;
-	}
-	
-	int IVsInstalledProduct.ProductID(out string pbstrPID)
-	{
-	    pbstrPID = "3.3.0.0";
-	    return 0;
-	}
-	
-	...
-	
-}
-
-

This code causes the component to show up in the list of "Installed Products" -in Visual Studio about box:

-

-

As for the splash screen, Visual Studio 2008 used to display extensions in -its splash screen, but later version do not:

-

    -    -

-

Troubleshooting Package Load Failures

-

You may encounter this dialog when playing with packages:

-

-

When you click "No", the package will be skipped later when loading packages. -You can re-enable loading all packages by running

-
devenv.exe /ResetSkipPkgs
-

To debug package load problem, you can do just what the dialog says. Run

-
devenv.exe /log
-

and then take a look on the ActivityLog.xml (path is shown -in the dialog). There you can find cause of the problem in one of the "entry" -elements:

-
-...
-<entry>
-  <record>106</record>
-  <time>2012/10/26 06:07:36.920</time>
-  <type>Error</type>
-  <source>VisualStudio</source>
-  <description>CreateInstance failed for package [ComponentOwl.ToolboxIntegration.SampleVSPackage, SampleVSPackage, Version=1.0.0.0, Culture=neutral, PublicKeyToken=87379c2b0cde9bc3]</description>
-  <guid>{761F0CB7-64C1-4695-91D2-6E3C26C12314}</guid>
-  <hr>80070002</hr>
-  <errorinfo>Could not load file or assembly 'file:///C:\projects\articles\2012-10-22 Visual Studio Toolbox Control Integration\ToolboxIntegration\SampleVSPackage\bin\SampleVSPackage.DLL' or one of its dependencies. The system cannot find the file specified.</errorinfo>
-</entry>
-...
-
-

In this particular case, the problem was caused by changing output path from -"bin\SampleVSPackage.dll" to "bin\Debug\SampleVSPackage.dll" -so the file does not longer exist at the location for which it is registered. -The solution is to either change the location back or unregister the package -(i.e. remove the corresponding registry entries - the GUID is provided in the -log).

-

Past Troubles with Package Load Keys

-

The above problem with package load failure happened on Visual Studio 2005 -and 2008 because a Package Load Key (PLK) had to be provided by the VSPackage. -The PLK is basically a hashcode computed from metadata about package (name, -author/company, version). The PLK had to be obtained from a website provided by -Microsoft.

-

I believe PLK caused many troubles and headaches to developers, including -myself.

-

This is no longer relevant for Visual Studio 2010 and newer (requirement for -PLKs removed), so we won't discuss this topic in more depth

-

Update Control Already Installed in Toolbox

-

Suppose we have already integrated SampleControl version 3.3.0.0 in the -Visual Sudio Toolbox:

-

-

We would like to update this control to version 3.4.0.0.

-

First of all, we update assembly information of the SampleControl -project:

-

-

If we "deploy" (copy) SampleControl.dll to the folder with -SampleVsPackage.dll where it is registered, the SampleControl will no longer be -visible in Toolbox, because the control in Toolbox should still be 3.3.0.0 and -this version is no longer to be found.

-

You don't need to increment assembly version of the SampleVsPackage project, -but at least you have to increment parameter of the ProvideToolboxItems attribute:

-
-[PackageRegistration(UseManagedResourcesOnly = true)]
-[InstalledProductRegistration("#110", "#112", "1.0", IconResourceID = 400)]
-[Guid(GuidList.guidSampleVsPackagePkgString)]
-[ProvideToolboxItems(2)]
-public sealed class SampleVsPackage : Package, IVsInstalledProduct
-{
-	...
-}
-
-

The package need to be re-registered (see section Registering the Package) -which will effectively update just the "Default Items" value in the Toolbox key:

-

-

This will cause Visual Studio to update your control in the Toolbox:

-

-

Remove Control from the Toolbox

-

Now we would like to remove control from the Visual Studio Toolbox. This -step can be done by custom uninstaller.

-

One way to do that is to simply unregister the VSPackage using -RegPkg.exe:

-
32-bit OS: RegPkg.exe /unregister /root:SOFTWARE\Microsoft\VisualStudio\10.0 SampleVsPackage.dll
-64-bit OS: RegPkg.exe /First of all, we update assembly information of the unregisFirst of all, we update assembly information of the ter /root:SOFTWARE\Wow6432Node\Microsoft\VisualStudio\10.0 SampleVsPackage.dll
-

You can also do this manually by simply removing the registry entry of the -corresponding package, e.g.:

-
32-bit OS: HKLM\SOFTWARE\Microsoft\VisualStudio\10.0\Packages\{a9696de6-e209-414d-bbec-a0506fb0e924}
-64-bit OS: HKLM\SOFTWARE\Wow6432Node\Microsoft\VisualStudio\10.0\Packages\{a9696de6-e209-414d-bbec-a0506fb0e924}
-

On Visual Studio 2012/2013, the key need to be removed in user config registry -hive or call "devenv.exe /Setup" after removing the registry key in HKLM. For -more information, see section Package Registration for Visual Studio 2012/2013.

-

9. Toolbox Integration using VSIX Packages

-

Microsoft have removed most /po -f the drawbacks of VSI packages by introducing VSIX. The -price is that VSIX is a little bit more complicated and Visual Studio 2008 is no -longer supported.

-

There are two versions of VSIX Schema. Version 1.0 is what Visual Studio 2010 -understand. There is also version 2.0 for Visual Studio 2012/2013. We want a VSIX -Package compatible with both, so we will work in Visual Studio 2010.

-

Create a new Project from Template

-

If you have Visual Studio 2010 SDK installed, you can create a new VSIX -package project with control from a template.

-

Select "File - New - Project.." (Control+Shift+N) and -then select the "Windows Forms Toolbox Control" or "WPF -Toolbox Control" template:

-

-

The projects is basically a VSPackage wrapped in VSIX container after -build. The package assembly also contain the control class named -ToolboxControl.

-

There are three important files generated by the template:

-
    -
  • ProvideToolboxControlAttribute.cs - This is attribute - for ToolboxControl class. We will discuss it later.
  • -
  • source.extension.vsixmanifest - This is manifest XML - file for our VSIX package. It contains all information about the package and - what it contains.
  • -
  • ToolboxControl.cs - This is a sample control to be - installed in Visual Studio Toolbox.
  • -
-

Create a new Project from VSPackage

-

We can also start with VSPackage like the one we have already created in -previous section. I will create a new VSPackage project (as in previous -chapter), name it SampleVsixPackage and configure it according -to "Windows Forms Toolbox Control" template to show you all the differences.

-

The basic configuration of source.extension.vsixmanifest is -the same as in previous chapter.

-

Project properties differs from VSPackage we have created earlier on the VSIX -tab, where we have the first two check boxes checked:

-

-

Update the Manifest File

-

Double-click on the source.extension.vsixmanifest file to -open up the VSIX Manifest Designer:

-

-

If you are not sure about some part of the form, please take a look on -section Create VSPackage Project, where the form is described in more -detail.

-

In addition to previous VSPackage project, I have also filled the following -optional boxes:

-
    -
  • License Terms - If you have EULA or other licence in - TXT or RTF format, you can browse for it.
  • -
  • Icon - You can browse for an icon representing the - extension. It should be 32x32 pixels large, PNG, BMP, JPEG or ICO image - format.
  • -
  • Preview Image - Thumbnail image representing the - extension. It should be 200x200 pixels large, PNG, BMP or JPEG image format.
  • -
  • More Info URL - URL of a website containing more - information about the extension.
  • -
  • Getting Started Guide - URL of a website with - documentation; you can also provide relative path to HTML file with the - local documentation.
  • -
-

Add Control

-

Let's create a new WPF control within the SampleVsixPackage -project itself. I will name it SampleWpfControl to distinguish -it from SampleControl we have created earlier.

-

To ensure our control will show up in Toolbox of Visual Studio 2012/2013, we have -to decorate the SampleWpfControl class by -ProvideToolboxControlAttribute:

-
-[ProvideToolboxControl("SampleWpfControl", true)]
-public partial class SampleWpfControl : UserControl
-{
-	...
-}
-
-

You also have to provide implementation of the attribute class:

-
-[AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = true)]
-[System.Runtime.InteropServices.ComVisibleAttribute(false)]
-public sealed class ProvideToolboxControlAttribute : RegistrationAttribute
-{
-	private const string ToolboxControlsInstallerPath = "ToolboxControlsInstaller";
-
-	public ProvideToolboxControlAttribute(string name, bool isWpfControls)
-	{
-		if (name == null)
-		{
-			throw new ArgumentException("name");
-		}
-
-		this.Name = name;
-		this.IsWpfControls = isWpfControls;
-	}
-
-	private bool IsWpfControls { get; set; }
-	private string Name { get; set; }
-
-	public override void Register(RegistrationAttribute.RegistrationContext context)
-	{
-		if (context == null)
-		{
-			throw new ArgumentNullException("context");
-		}
-
-		using (Key key = context.CreateKey(String.Format(CultureInfo.InvariantCulture, "{0}\\{1}",
-														 ToolboxControlsInstallerPath,
-														 context.ComponentType.Assembly.FullName)))
-		{
-			key.SetValue(String.Empty, this.Name);
-			key.SetValue("Codebase", context.CodeBase);
-			if (this.IsWpfControls)
-			{
-				key.SetValue("WPFControls", "1");
-			}
-		}
-
-	}
-
-	public override void Unregister(RegistrationAttribute.RegistrationContext context)
-	{
-		if (context != null)
-		{
-			context.RemoveKey(String.Format(CultureInfo.InvariantCulture, "{0}\\{1}",
-														 ToolboxControlsInstallerPath,
-														 context.ComponentType.AssemblyQualifiedName));
-		}
-	}
-}
-
-

This code is generated if you create project from template.

-

The project in Solution Explorer should look like this:

-

-

-

Adding Controls from Other Projects

-

What if we would like to use SampleControl.dll as in the VSI -package scenario?

-

Of course, we can click "Add Content" in the VSIX Manifest designer and -simply add "Toolbox Control" content from other project:

-

-

However, this is possible only if the SampleControl project -itself is a package project!

-

Lucklily, since the VSIX package is still just a ZIP archive, we can take a -look on how to add such external DLLs to it manually.

-

Setting Up VSIX Installer

-

The VSIX Installer tool (VsixInstaller.exe) is located in -Visual Studio's binary folder:

-
32-bit OS: c:\Program Files\Microsoft Visual Studio 11.0\Common7\IDE\VSIXInstaller.exe
-64-bit OS: c:\Program Files (x86)\Microsoft Visual Studio 11.0\Common7\IDE\VSIXInstaller.exe
-

You can hit F6 and Visual Studio will build your project to create -SampleVsixPackage.vsix file. This is our VSIX package.

-

The VSIX Installer should be associated with the .VSIX file extension, so it is -usually possible -to just double-click on the file and see the VSIX installer.

-

The installation can fail in the very first step:

-

-

This problem appears if you have invalid manifest file. If this happen, open -source.extension.vsixmanifest and fill in all missing data. -Furthermore, you can check if the XML is valid according to -VSIX Extension -Schema.

-

Now we are able to rebuild and run the VSIX installer again:

-

-

Make the VSIX Package Compatible with Visual Studio 2012/2013

-

To make our VSIX package working with Visual Studio 2012 and newer, we need -to manually update the manifest file. Select the -source.extension.vsixmanifest file and press F7 (View Code):

-
-<?xml version="1.0" encoding="utf-8"?>
-<Vsix xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" Version="1.0.0" xmlns="http://schemas.microsoft.com/developer/vsx-schema/2010">
-  <Identifier Id="ComponentOwl.ToolboxControl.Express">
-    <Name>Component Owl</Name>
-    <Author>ComponentOwl.com</Author>
-    <Version>1.0</Version>
-    <Description xml:space="preserve">Windows Forms Toolbox Control</Description>
-    <Locale>1033</Locale>
-    <MoreInfoUrl>http://www.componentowl.com/toolbox-control</MoreInfoUrl>
-    <License>license.rtf</License>
-    <GettingStartedGuide>http://www.componentowl.com/documentation/toolbox-control</GettingStartedGuide>
-    <Icon>icon.png</Icon>
-    <PreviewImage>overview.jpg</PreviewImage>
-    <SupportedProducts>
-      <VisualStudio Version="10.0">
-        <Edition>Ultimate</Edition>
-        <Edition>Premium</Edition>
-        <Edition>Pro</Edition>
-      </VisualStudio>
-      <VisualStudio Version="11.0">
-        <Edition>Ultimate</Edition>
-        <Edition>Premium</Edition>
-        <Edition>Pro</Edition>
-      </VisualStudio>
-      <VisualStudio Version="12.0">
-        <Edition>Ultimate</Edition>
-        <Edition>Premium</Edition>
-        <Edition>Pro</Edition>
-      </VisualStudio>
-    </SupportedProducts>
-    <SupportedFrameworkRuntimeEdition MinVersion="4.0" MaxVersion="5.0" />
-  </Identifier>
-  <References />
-  <Content>
-    <ToolboxControl>|%CurrentProject%;PkgdefProjectOutputGroup|</ToolboxControl>
-  </Content>
-</Vsix>
-
-

The bolded text have been added. I have simply added a new -VisualStudio element with higher version and all the editions (they are -relevant for VS 2012 and 2013 as its own template also generates these).

-

The VSIX installer will show Visual Studio 2012 options as -well after this update (if installed, of course):

-

-

Please note that Visual Studio 2012/2013 also works with 2.0 version of the -schema, so if you create VSIX package in Visual Studio 2012/2013, it won't be -compatible with 2010. The solution is hence to use 1.0 version of the schema -and add support for newer Visual Studio as described earlier.

-

A great advantage over VSI package is that installation of Toolbox control is -really fast with VSIX.

-

Regrettably, the control won't show up in Visual Studio 2012/2013 Toolbox in its -default configuration. You need to enable loading-per user extensions (this -option is enabled by default in Visual Studio 2010):

-

-

Signing the VSIX Package

-

Unlike older VSI package, there is no nag screen when the package is not -signed. Instead, a label appears informing user that the package is not -signed.

-

To sign a VSIX package, we need PackageSignatureManager from -System.IO.Packaging (WindowsBase.dll). I made a simple command-line application called SignVsix (you can -find it in sample source code) that takes three arguments (VSIX file path, PFX -certificate path and password for the certificate):

-
-using System;
-using System.Collections.Generic;
-using System.IO;
-using System.IO.Packaging;
-using System.Security.Cryptography;
-using System.Security.Cryptography.X509Certificates;
-
-internal class Program
-{
-	private static void Main(string[] args)
-	{
-		// first argument - path to VSIX package
-		string paramPathPackage = args[0].Replace("\"", "");
-		// second argument - path to PFX certificate
-		string paramPathCertificate = args[1].Replace("\"", "");
-		// third argument - password for the certificate
-		string paramPassword = args[2];
-
-		// open VSIX package
-		Package package = Package.Open(paramPathPackage, FileMode.Open);
-
-		// load certificate
-		byte[] certificate = File.ReadAllBytes(paramPathCertificate);
-
-		// sign all parts of the package
-		var signatureManager = new PackageDigitalSignatureManager(package)
-		{
-			CertificateOption = CertificateEmbeddingOption.InSignaturePart
-		};
-
-		List<Uri> partsToSign = new List<Uri>();
-
-		foreach (PackagePart packagePart in package.GetParts())
-		{
-			partsToSign.Add(packagePart.Uri);
-		}
-
-		partsToSign.Add(PackUriHelper.GetRelationshipPartUri(signatureManager.SignatureOrigin));
-		partsToSign.Add(signatureManager.SignatureOrigin);
-		partsToSign.Add(PackUriHelper.GetRelationshipPartUri(new Uri("/", UriKind.RelativeOrAbsolute)));
-
-		try
-		{
-			signatureManager.Sign(partsToSign, new X509Certificate2(certificate, paramPassword));
-		}
-		catch (CryptographicException cryptographicException)
-		{
-			Console.WriteLine("Signing failed: {0}", cryptographicException.Message);
-		}
-	}
-}
-
-

The usage is very simple:

-
SignVsix.exe SampleVsixPackage.vsix certificate.pfx abc123
-

When the file is signed, VSIX Installer shows label "Digital Signature: -<Author Name>" on the first page:

-

-

Dissecting the VSIX Package

-

If you look on the project references, you can see reference to -Microsoft.VisualStudio.Shell.Immutable.10. This reference points to -Visual Studio 2010 SDK and we cannot expect this dependency present on end-user's machine. This -library contains ProvideToolboxControlAttribute class, which is -used by our ToolboxControl.

-

Since a software development company may want to develop many components, it would be nice to have an -universal VSIX package which can be adjusted for any control.

-

Let's take a look on the ToolboxControl.vsix. It is simply a -ZIP archive containing the manifest, resources, ToolboxControl binary and a -ToolboxControl.pkgdef file. If we look through all its content, -we easily generate our own VSIX packages on demand, even without Visual Studio. -There should also be a programmatic way on generating VSIX packages using -classes from System.IO.Packaging.

-

Update Toolbox Control via VSIX Package

-

If you made changes to your control and want to re-install the package, an -error message appear:

-

-

In order to provide an update, you need to increment version number in the -VSIX manifest:

-

-

You can also increment version number in the Package class attribute, but -this is not necessary for the VSIX to perform update:

-
-[InstalledProductRegistration("#110", "#112", "2.0", IconResourceID = 400)]
-[Guid(GuidList.guidSampleVsixPackagePkgString)]
-public sealed class SampleVsixPackage : Package
-{
-	...
-}
-
-

Of course, you can also increment version of the assembly.

-

Uninstall the VSIX Package

-

The VSIX Installer can be used to uninstall control from the Toolbox via -/uninstall parameter followed by package ID (the constant located in -Guids.cs: GuidList.guidSampleVsixPackagePkgString):

-
VSIXInstaller.exe /uninstall:e3dfd099-d0ab-4b8e-b26d-639032c29ad9
-

It is also possible to uninstall VSIX Package manually using -Extension Manager (Tools - Extension Manager...). In Visual Studio -2012/2013, the corresponding dialog is called Extensions and Updates -(Tools - Extensions and Updates...).

-

-

Quiet Mode

-

Both installation and uninstallation can be performed in quiet mode by using /quiet parameter. This will suppress -user interface of the installer, which is handy when you want to automate -Toolbox control integration with your custom installer.

-

10. Supporting Multiple Version of .NET Framework

-

Since .NET Framework is backward-compatible, building a component on lowest -possible framework ensures compatibility with higher versions as well.

-

I heard from several users that the component may not be displayed in Toolbox -although it seems that the Toolbox respects the .NET compatibility and display -.NET 2.0 component even when working in .NET 4.0 (Client Profile) project.

-

There is also a scenario where you want to support additional features from -higher version of .NET (for example, drawing text using GDI+ in .NET 2.0 and -drawing text using WPF in .NET 3.5 and higher). You may also want to add -extensive Windows Forms Designer support, which is not available in Client -Profile framework.

-

The solution to this is to build several DLLs, each with different features -and possibly different target frameworks. Then integrate all the assemblies.

-

This does not pose a problem when DTE approach is used, -alhtough it is better to give each version of the component unique name or place -them in separate tabs (e.g. "Component Owl WinForms - .NET 2.0").

-

When TCI approach is used, each version of the assembly -requires different public key token, because they have to reside in GAC -side-by-side. Furthermore, they need a separate registry key based on the public -key token.

-

The VSI and VSIX approaches require -renaming the component or customizing Toolbox tab in the -ProvideToolboxControlAttribute (see part Toolbox Control Integration using -VSIX Packages for more information).

-

The VSPackage approach allows you to place all the versions -in Visual Studio Toolbox under their respective tabs.

-

When manual approach is used, you can of course add each -version of the assembly separately and also create separate tabs in the Toolbox.

- -

11. Sample Source Code

- -

The attached sample source is a Visual Studio 2010 Solution containing -implementations of all the presented approaches. The binaries are contained -under "bin\Release" subfolders and batch files (.CMD extension) are provided -where appropriate.

- -

-Download sample source code (212 KB) -

- -

You can find the following folders in the archive:

-

DteToolboxInstaller - A command-line application for -installing/uninstalling assemblies in VS Toolbox using Visual Studio Automation -Object Model (DTE). Custom tab name and VS version can be specified. The tool -can be used in real-world application.

-

SampleControl - Windows Forms control for testing the -integration.

-

SampleVsixPackage - VSIX package project (basically a -VSPackage that is further packaged with the sample control), the resulting -package can be installed by VSIX Installer that comes with Visual Studio.

-

SampleVsPackage - VSPackage that is able to install all -control assemblies located in its own folder. Contains batch files for package -registration/unregistration.

-

SignVsix - A command-line application for signing VSIX -packages. Sample batch file is provided. Valid PFX certificate need to be -provided by the user.

-

TciToolboxInstaller - A command-line application for -installing/uninstalling assemblies in VS Toolbox using Toolbox Control Installer -package (but does not depend on it). Custom tab name and VS version can be -specified. The tool can be used in real-world application.

-

VSI - Basic setting for creating VSI package and a sample -VSI package created from the files. Batch file for signing the VSI package is -provided.

-

 

- -

-Download sample source code (212 KB) -

- + + + + +

The Most Complete Guide to Visual Studio Toolbox Control Integration

+

Libor +Tinka, Lead Developer, ComponentOwl.com

+

+

+

Contents

+

1. Introduction
+2. Prerequisites
+3. Creating a Sample Control
+4. Manual Toolbox Integration
+5. Toolbox Integration using TCI
+6. Toolbox Integration using DTE
+7. Toolbox Integration using VSI Packages
+8. Toolbox Integration using VSPackages
+9. Toolbox Integration using VSIX Packages
+10. Supporting Multiple Version of .NET Framework
+11. Sample Source Code

+

1. Introduction

+

This tutorial is intended for developers who would like to distribute their +WPF or WinForms controls and automatically put them into Visual Studio Toolbox +during installation.

+

I struggled with Toolbox integration earlier because there are several possible +approaches (harder to decide between them). Each approach have its own pros and cons and +no overall comparison is provided. I wrote this tutorial to shed some light on the topic +and spare you hours, maybe days of research and experimenting with aspects of +Visual Studio (Toolbox) extensibility.

+

We will first take a look on Toolbox control integration in general to get a +big picture. Each approach will be then discussed in detail and the following +question will be answered:

+
    +
  • How to install control in Visual Studio Toolbox?
  • +
  • How to update the control?
  • +
  • How to uninstall/remove the control?
  • +
  • How to support multiple Visual Studio versions?
  • +

+

There are several options on how to integrate your controls with Visual +Studio Toolbox:

+
    +
  • Manual installation
  • +
  • Toolbox Control Installer (TCI)
  • +
  • Visual Studio Automation Object Model (DTE)
  • +
  • VSPackage
  • +
  • VSI package
  • +
  • VSIX package
  • +
+

Manual installation

+

The simplest way of adding control into Visual Studio Toolbox is from within +the IDE.

+

This approach have one crucial drawback, which is that you leave Toolbox +integration to the user. Many developers are not that experienced with Visual +Studio and when your component is shipped, even if you provide appropriate +step-by-step guide, they may find it too complicated and rather try +another component which "just works". I thought that every developer using +Visual Studio is experienced enough to know how to add new items in VS Toolbox, +but I received few e-mails from users who uninstalled the product just because +the component have not appeared in the Toolbox and they thought it is broken +(without reading our documentation, of course). On the other hand, there is +a group of users who are not experienced developers, but are in charge of trying +some products in a given company (e.g. project managers). These people can +install the component, play with it and they would really appreciate if it just +works. This increases chance they will actually purchase your product.

+

Advantages: zero effort
+Disadvantages: require experienced users, slows user +producitivity, updating controls is not intuitive

+

Toolbox Control Installer (TCI)

+

Visual Studio 2005 SDK contained a VSPackage called Toolbox Control +Installer. This package comes pre-installed with Visual Studio 2008 and newer. +Its job is to simplify the specific task of extending Visual Studio Toolbox. +This approach requires you to install your assembly in GAC (Global Assembly +Cache) and create a key in Windows Registry.

+

Advantages: simple and fast component installation, updating +and removing
+Disadvantages: requires installation in GAC (not always +wanted), VS 2005 supported with SDK only

+

Visual Studio Automation Object Model (DTE)

+

If you are not afraid of COM, you can try DTE (Development Tools Environment) approach. +There is already a project on CodePlex called +Visual Studio Toolbox Manager, +which solves the toolbox integration problem using a simple command-line +application. The project is outdated since it does not support Visual Studio +2010 and newer. I made a project called DteToolboxInstaller, which +is also a command-line application and does support Visual Studio 2013, 2012, 2010, +2008 and 2005. You can use the project as you like. The main disadvantage of DTE +approach is the speed. The installer have to run devenv.exe using the automation interface, create a +fake VS Solution, open Toolbox, add the stuff and then close the Solution. The +whole process take no less than 10 seconds. If you want to integrate with two or +three versions of Visual Studio, it can take well over a minute.

+

Advantages: does not require updating registry or GAC, full +control over Toolbox
+Disadvantages: very slow, separate installation required for +every version of Visual Studio

+

VSPackage

+

A VSPackage seems to be a natural option. VSPackages allow any type +of Visual Studio extension and you can manipulate Toolbox as well. There was a trouble +with VSPackages in providing a Package Load Key (PLK) which can be +generated only manually using web form. The requirement for PLK vanished with +Visual Studio 2010 (hooray!). The nice thing about VSPackage approcach is that it does not slow +down the installation process. The package is loaded and the controls are installed +on-demand (when the Toolbox is opened for the first time after installation). +After trying all the approaches, using VSPackage seems to be fastest and most +universal one.

+

Advantages: quick installation, appearance in About box and +other extensibility features
+Disadvantages: cmplicated setup, each component requires its +own package if shipped separately

+

VSI Package

+

VSI packages are quite old but you can use them for integration with Visual +Studio 2005 and newer. It have very simple structure and you can create one even +without Visual Studio. The only trouble with VSI compared to other +approaches is invoking a wizard form which cannot be suppressed. The +installation just cannot run in "quiet" mode. Another trouble with VSI is that a +digital signature is required in order to get rid of a warning dialog. Your control will be always installed under "My Controls" tab in the +Toolbox, which is not always desirable.

+

Advantages: simple creation, installer provided by Visual +Studio, automated creation and signing requires several specific steps
+Disadvantages: no quiet mode (extra steps when custom installer +is used), manual uninstallation

+

VSIX Package

+

VSIX packages came with Visual Studio 2010 so you can integrate with 2010 or +newer. the .VSI and .VSIX file extensions are associated with Visual Studio so +you can simply double-click it or run it via shell. You can also run +VsixInstaller.exe utility that performs the installation. Good news: No more +nag screens when VSIX is not signed - the installer only contains a dialog with +simple text: "This extension does not contain a digital signature." +Even better news: The VsixInstaller supports quiet mode!

+

Please note that VSI and VSIX package installers contain features like +displaying EULA, choosing which components to install or localization. When +deploying your controls for use in Visual Studio, you won't need an installer on +top of the package.

+

Advantages: installer provided by Visual Studio, quiet mode, +fast installation
+Disadvantages: package project required, automated creation is +complicated, no support for VS 2005 and 2008

+

Comparison of Approaches

+

Here is a table summarizing features of the discussed approaches. As you can +see, the VSPackage approach gives you the most freedom, but is also hardest +to implement. We will discuss every approach so +that you will be able to impement the one that suits you best.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
 20052008201020122013SpeedInstall AutomationUninstall automation 
Manual installationdepends on user
TCIfast 
EnvDTEslow 
VSImoderate 
VSIXmoderate (faster than VSI) 
VSPackagefast 
+ +

2. Prerequisites

+

We will focus on integration with Visual Studio 2010, 2012 and 2013. Hence you will need:

+
    +
  • Visual Studio 2010 (or 2012, 2013)
  • +
  • Visual Studio 2010 SDK (or 2012 SDK, 2013 SDK)
  • +
  • Microsoft Windows SDK
  • +
+

The VS SDK contains regpkg.exe tool and project templates discussed in VSIX +and VSPackage approaches.

+

The Windows SDK contains gacutil.exe, guidgen.exe, signtool.exe and other +useful tools.

+

There are two kinds of versioning used for Visual Studio. One is based on the +release name (e.g. Visual Studio 2008) and the other is a classic version number +(e.g. 8.0). Both will be used, so it should be noted which version numbers +correspond to which versions of Visual Studio:

+ + + + + + + + + + + + + + + + + + + + + + + + + +
Release nameVersion number
Visual Studio 20058.0
Visual Studio 20089.0
Visual Studio 201010.0
Visual Studio 201211.0
Visual Studio 201312.0
+

3. Creating a Sample Control

+

We will start by creating simple WinForms control for integration in VS +Toolbox.

+

You can start with File - New - Project... (Control+Shift+N) and select +Windows Forms Controls Library template.

+

Of course, you can also create empty Class Library project, add references to +System.Drawing and System.Windows.Forms and create a new control. In fact, any +DLL containing public classes derived from Control will +suffice.

+

We want to support .NET Runtime version 4.0 and 4.5, so the control should be +built against .NET 4.0 to ensure compatibility (the lower framework version you +use, the wider range of compatible frameworks since they are backward +compatible). It should be noted that .NET 4.5 is an in-place update of .NET 4.0 +and hence the 4.5 assemblies will work on machines with 4.0 runtime installed +unless you use some feature specific to 4.5.

+

If you have multiple controls in your assembly and don't want to use some of +them in Toolbox, decorate them with ToolboxItem attribute with +defaultType parameter set to false:

+
+[ToolboxItem(false)]
+public class InvisibleControl : UserControl
+{
+  ...
+}
+
+

I have created a very simple control called SampleControl:

+

+

Finally, I set version of the assembly 3.3.0.0 (I chose just something else +than 1.0.0.0 to see where the specific version number appears).

+

Custom Transparent Icon for the Toolbox

+

Icons for Toolbox are 16 by 16 pixel images. Various image formats are supported +(BMP, JPEG, PNG and ICO). However, you need to +create 256-color BMP image to ensure transparency. The transparent color is determined by bottom left +pixel of the icon. Transparency works for magenta (#ff00ff):

+

+

The icon file should have same name as the control class (i.e. +SampleControl.BMP).

+

Finally, use ToolboxBitmapAttribute to link icon with the control class:

+
+[ToolboxBitmap(typeof(SampleControl), "Resources.SampleControl.bmp")]
+public partial class SampleControl : UserControl
+{
+	...
+}
+
+

Note that icon location matters, at least in C#. Since I have added +the icon under custom folder named Resources, I need to reference +Resources.SampleControl.bmp instead of just SampleControl.bmp.

+

Here is the resulting transparent icon in Toolbox:

+

+

Marking the Control as Toolbox Item

+

We can mark control as toolbox item by adding a ToolboxItemAttribute +with defaultType parameter set to true:

+
+[ToolboxItem(true)]
+public partial class SampleControl : UserControl
+...
+
+

This decoration is optional since the controls within assembly are +considered toolbox items by default. However, we can mark certain control +classes with ToolboxItem(false) to hide them from Toolbox. This +comes in handy when we have multiple projects and there are too many controls in +the Toolbox because loaded from all the other projects.

+

Signing the Assembly

+

The assembly containing controls (SampleControl.dll in our +case) should be strongly named if we want them installed in GAC +(Global Assembly Cache) later on. This is optional in most cases, but the Toolbox Controls +Installer approach requires the assembly being installed in GAC, hence the +strong name is necessary there.

+

To give an assembly a strong name, open project properties and find +Signing tab:

+

+

Check the "Sign the assembly" option and select "<New...>" +from the combo box. This will create a new .SNK file in your project which will +be used to sign the assembly. You can also browse for existing key file. If you +want to distribute multiple assemblies with custom controls, it is a best +practice to use same strong name key for each assembly (it is possible to have +one .SNK file located in Solution folder and put just a link to that file in +each project; when we browse for the key under the Signing tab, the link will be +used without copying the file).

+

The SNK (Strong Name Key) file is basically a private key to digitally sign +your assembly. There is also a public key which can be used to verify the +assembly and its shorter variant called "public key token" for assembly +identification.

+

4. Manual Toolbox Integration

+

Installing

+

To install component into Visual Studio Toolbox manually, open some form or +control in designer, open the Toolbox window (Control+Alt+X), right-click on the +Toolbox window and select "Choose Items...":

+

+

The "Choose Toolbox Items" dialog will show up:

+

+

You can browse for DLL file with your component by clicking the "Browse..." +button.

+

This is the simplest way of putting component in the Toolbox without extra +actions required.

+

This can be unpleasant for end-users since it means many clicks they have +to perform. I will explain how to integrate a component a little bit more so that it +will be visible under the ".NET Framework Components" tab in the above dialog box and +possibly show up in Toolbox automatically without extra effort of the user.

+

Making the Control Visible in "Choose Toolbox Items" Dialog Box

+

As you can see on the above picture, the SampleControl component is already +displayed in the dialog box under ".NET Framework Components" tab.

+

This is because the folder containing our control is registered as "assembly folder" in the +registry and hence is searched when the above dialog is populated.

+

You can register your own assembly this way by creating a key in registry:

+
32-bit OS: HKLM\SOFTWARE\Microsoft\.NETFramework\AssemblyFolders\<your control name>
+64-bit OS: HKLM\SOFTWARE\Wow6432Node\Microsoft\.NETFramework\AssemblyFolders\<your control name>
+

You can also create key for specific version of .NET runtime (this comes in +handy if you distribute different components for different versions of .NET):

+
32-bit OS: HKLM\SOFTWARE\Microsoft\.NETFramework\v4.0.30319\AssemblyFoldersEx\<your control name>
+64-bit OS: HKLM\SOFTWARE\Wow6432Node\Microsoft\.NETFramework\v4.0.30319\AssemblyFoldersEx\<your control name>
+

In both cases, the default value for the key is a string with full path to +the folder with your assembly.

+

You can specify Toolbox tab in which the component should show up by adding +subkey named "Toolbox" with single string value "TabName" this value has Toolbox +tab name as data. When you add such control in the Toolbox, it will reside under +new tab with the specified name:

+

+

+

The control should also appear in "Choose Toolbox Items" dialog box if it +is installed in Global Assembly Cache.

+

The control pops up in the Toolbox automatically in +its own tab in Visual Studio 2012/2013.

+

Installing the Control in GAC

+

The benefit of GAC (Global Assembly Cache) is that the user needs not to +browse for your control. He will just select it form the above dialog box +without having to know where it is actually installed (the dialog is populated +by controls from "assembly folders" and from the GAC).

+

The GAC have one useful feature and disadvantage at the same time: It allows +holding multiple versions of the same assembly. When user makes reference to +your control from GAC and set "Specific Version" to true in +Reference Properties window, it will be tied to that version. When you install an +"update", a new version will be added to GAC, but the user will stay with the +older one. Of course, the "Choose Toolbox Items" dialog will show both versions, +so the user can just replace old reference with the new one.

+

You can make the installer removing any older versions from GAC during +installation and add/keep just the newest one. This will force the user to +replace the reference since it breaks the build.

+

You can work with GAC by using tool called gacutil.exe or +from code. We will discuss both approaches.

+

The gacutil.exe is located in Microsoft Windows SDK directory. There are two +such extecutables:

+
c:\Program Files (x86)\Microsoft SDKs\Windows\v7.0A\Bin\gacutil.exe
+c:\Program Files (x86)\Microsoft SDKs\Windows\v7.0A\Bin\NETFX 4.0 Tools\gacutil.exe
+

The former is for .NET Framework up to version 3.5. The latter is for +.NET 4.0 and higher. This is for compatibility reasons as a separate GAC have +been introduced with .NET 4.0.

+

You can install an assembly to GAC by calling:

+
gacutil.exe /i SampleControl.dll
+

To uninstall it, we refer to our assembly by its assembly name, not file +name:

+
gacutil.exe /u SampleControl
+

Finally, you can check if the assembly is installed in GAC by listing any +instances of the provided name:

+
gacutil.exe /l SampleControl
+

It is not wise, however, to use gacutil.exe from a custom +installer as it is located in SDK that user might not have installed. +Furthermore, the SDK license does not allow bundling gacutil.exe +with your installer.

+

Some installers like Inno Setup or MSI allow installing in GAC anyway.

+

You can also work with GAC using +System.EnterpriseServices.Internal.Publish class. The class have two +methods: GacInstall and GacRemove. Both +methods take just path to assembly file as a parameter, so for example:

+
(new Publish()).GacInstall(assemblyPath);
+

will install the specified assembly in GAC.

+

Updating

+

Updating the control depends on how it is installed and referenced.

+

If you have added component in the Toolbox manually via "Choose Toolbox Items" +dialog box and "Browse..." button, i.e. as a file reference, the +default property of such reference is that it simply points to the specified +file no matter which version it have (unless user sets "Specific Version" to +true in reference properties window; the default is +false in this case). Simply replacing the DLL with the control by a newer +file will suffice. If the user have specified "Specific Version" to true, +the build will break because the reference is no longer valid. He needs to +replace the reference by a new one pointing on the same file which now have +newer version.

+

If you have added the component from GAC (these components also appear in the +"Choose Toolbox Items" dialog box), the "Specific Version" property of the +reference is true by default:

+

+

This means that even if you install a newer version of the component in GAC, +the project will still reference the older version and both versions will reside +in GAC.

+

If you remove all versions of the component from GAC (e.g. using +gacutil.exe) and then install just the newest one, the build will break +unless the user changed "Specific Version" property to false.

+

Removing

+

Removing the manually installed control consists of just reverting all the +steps done during the installation.

+

In case of file references, deleting the file is sufficient.

+

In case of tighter integration (GAC, registry), the registry keys need to be +deleted and the control can be removed from GAC (e.g. using gacutil.exe).

+

Resetting Toolbox and Clearing the Toolbox Cache

+

The Toolbox can fall into state where it does not display some items, some are +duplicate and some can be disabled. Sometimes the only remedy is to let Visual +Studio rebuild the +Toolbox from scratch.

+

To do that, right-click on the Toolbox window and select "Reset +Toolbox". Visual Studio will go through all the installed packages and reloads +components into the Toolbox.

+

If this won't help, you can perform hard reset of the Toolbox. Exit +Visual Studio and delete all .TBD files in the following folder:

+
\Users\<user>\AppData\Local\Microsoft\VisualStudio\10.0\
+

It should be up to four files:

+

+

Once removed, start Visual Studio again. After showing the Toolbox, all items +should load instead of loading only the cached versions.

+

5. Toolbox Integration using TCI

+

Installing

+

Toolbox Control Installer is a VS package pre-installed in Visual Studio 2008 and +newer. It looks in Windows registry for components and loads them in the +Toolbox.

+

Before using TCI, one can check if it is installed in the given version of +VS. For example, the following registry key should exist if the Visual Studio +2010 have TCI installed:

+
32-bit OS: HKLM\SOFTWARE\Microsoft\VisualStudio\10.0\Packages\{2c298b35-07da-45f1-96a3-be55d91c8d7a}
+64-bit OS: HKLM\SOFTWARE\Wow6432Node\Microsoft\VisualStudio\10.0\Packages\{2c298b35-07da-45f1-96a3-be55d91c8d7a}
+

The TCI package GUID is always the same so you can make the check for any +version of Visual Studio with the above key (only change the version number from +10.0 to corresponding version number, of course).

+

The only prerequisites for the assembly is that it should have strong name +(i.e. to be signed). See section "Creating the Sample Control" for more +information.

+

The installation consists of putting the control in GAC (see previous +section for more information) and creating registry keys.

+

Suppose we have the SampleControl installed in GAC:

+

+

We will make reference to this assembly from registry by creating the +following key:

+
32-bit OS: HKLM\SOFTWARE\Microsoft\VisualStudio\10.0\ToolboxControlsInstaller\SampleControl, Version=3.7.0.0, Culture=neutral, PublicKeyToken=3cc4c7b61201d46c
+64-bit OS: HKLM\SOFTWARE\Wow6432Node\Microsoft\VisualStudio\10.0\ToolboxControlsInstaller\SampleControl, Version=3.7.0.0, Culture=neutral, PublicKeyToken=3cc4c7b61201d46c
+

The default value for the key is the Toolbox tab name name you would like to +have for the component(s), e.g. "Component Owl".

+

Installing in Visual Studio 2012 and 2013

+

One extra step is required to make this work in Visual Studio 2012/2013, which is +adding the registry key also in its user config hive, i.e.:

+
HKCU\Software\Microsoft\VisualStudio\11.0_Config\ToolboxControlsInstaller\SampleControl, Version=3.7.0.0, Culture=neutral, PublicKeyToken=3cc4c7b61201d46c
+

for VS 2012. Use 12.0_Config for VS 2013.

+

Updating

+

Updating the component is very simple. Just modify the above registry keys by +changing the version number.

+

Removing

+

To remove the component, delete the above registry keys. You should also +remove the corresponding assembly from GAC.

+

Automating Integration with TCI using TciToolboxInstaller

+

I made a simple command-line application called TciToolboxInstaller +which does all the described steps. The usage is simple:

+
TciToolboxInstaller.exe [install|uninstall] [vs2005|vs2008|vs2010|vs2012|vs2013] [tab name] [assembly path]
+

For example, if you like to install SampleControl.dll in Visual Studio 2012 +Toolbox, just call:

+
TciToolboxInstaller.exe install vs2012 "Component Owl" SampleControl.dll
+

You can use quotes for the last two parameters if they contain spaces.

+

The TciToolboxInstaller project is contained in sample +source code.

+

6. Toolbox Integration using DTE

+

Installing

+

The +DTE (Development Tools Environment) approach does not require working +with GAC or registry. It remotely manipulates Visual Studio Toolbox and +adds/removes items as needed.

+

The whole installation is done from (managed) code using COM wrappers. It +works in the following steps:

+
    +
  • Check if an instance of Visual Studio is not running. If not, continue.
  • +
  • Retrieve an EnvDTE.DTE object corresponding to the + version of Visual Studio we want to integrate with.
  • +
  • Create a "dummy" project using the DTE object
  • +
  • Obtain Toolbox window and ToolBox object from it.
  • +
  • Find or create ToolBoxTab object.
  • +
  • Add item in the Toolbox tab (ToolBoxTab.ToolBoxItems.Add).
  • +
  • Wait until current instance of Visual Studio stops running.
  • +
+

Here are some of the step/strongs in C# code - it is an excerpt from +DteToolboxInstaller project provided in sample source code:

+
+// obtain a DTE object
+Type typeDTE = Type.GetTypeFromProgID("VisualStudio.DTE.11.0");
+
+DTE dte = (DTE)Activator.CreateInstance(typeDTE, true);
+
+// create a temporary file
+string tempFile = Path.GetFileNameWithoutExtension(Path.GetTempFileName());
+string tempDirectory = string.Format("{0}{1}", Path.GetTempPath(), tempFile);
+
+// create Visual Studio Solution
+Solution4 solution = (dte.Solution as Solution4);
+
+string templatePath = solution.GetProjectTemplate(TemplateName, "CSharp");
+
+solution.AddFromTemplate(templatePath, tempDirectory, DummyProjectName, false);
+
+// get Toolbox window
+Window window = dte.Windows.Item(Constants.vsWindowKindToolbox);
+
+// get Toolbox
+ToolBox toolBox = (ToolBox)window.Object;
+
+// get Toolbox tab
+ToolBoxTab toolBoxTab = (GetToolBoxTab(toolBox.ToolBoxTabs) ?? toolBox.ToolBoxTabs.Add(this.tabName));
+
+// add new item under the Toolbox tab
+toolBoxTab.ToolBoxItems.Add(assemblyName, this.assemblyPath, vsToolBoxItemFormat.vsToolBoxItemFormatDotNETComponent);
+
+// select the Toolbox tab
+toolBoxTab.Activate();
+
+// cleanup
+dte.Solution.Close(false);
+dte.Quit();
+Marshal.ReleaseComObject(dte);
+
+// wait till Visual Studio turns off completely
+if (IsVisualStudioRunning())
+{
+	Thread.Sleep(VisualStudioProcessTimeout);
+}
+
+

There are several obstacles on implementing the DTE approach.

+

First of all, we need to ensure that Visual Studio is not running during the +installation - this is because we want messages sent to Visual Studio instance +will arrive in the "invisible" one ran from our code and not the one which the +user have currently opened.

+

Similarly, we would like to wait a while until the instance terminates after +installation. This is necessary when integrating with multiple versions of +Visual Studio when just a single instance have to be running at a time. Doing two +installations too quickly in succession may cause the previous one to fail +because a Visual Studio instance is still running.

+

The communication between our code and Visual Studio is mediated by OLE +message filter which needs to be implemented. You can take a look on +DteToolboxInstaller (see below) source code, where is a working installer +implemented that uses this approach.

+

Updating and Removing

+

Since we have full control over the Toolbox with this approach, updating or +removing items/tabs is done with the corresponding DTE objects.

+

Automatic Integration with DTE using DteToolboxInstaller

+

I made a simple command-line application called DteToolboxInstaller +which does all the necessary steps and solves the deals with the discussed +obstacles. The usage is simple:

+
DteToolboxInstaller.exe [install|uninstall] [vs2005|vs2008|vs2010|vs2012|vs2013] [tab name] [assembly path]
+

For example, if you like to install SampleControl.dll in Visual Studio 2012 +Toolbox, just call:

+
DteToolboxInstaller.exe install vs2012 "Component Owl" SampleControl.dll
+

You can use quotes for the last two parameters if they contain spaces.

+

The DteToolboxInstaller project is contained in sample +source code.

+

7. Toolbox Integration using VSI Packages

+

Let's consider you don't have a custom installer and want to distribute your +components in some kind of simple extension package that Visual Studio +understands.

+

Visual Studio contains an installer for so called VSI packages that will +do the integration work for you. If you have Visual Studio installed, the .VSI +extension is already associated with the Visual Studio Content Installer.

+

Creating the VSI Package

+

I have created an empty folder and copied SampleControl.dll in +it. All that is needed to make a VSI package is to create a .VSCONTENT file, +which is simply a XML file satisfying +Visual Studio Content Installer schema:

+
+<VSContent xmlns="http://schemas.microsoft.com/developer/vscontent/2005"> 
+    <Content>
+        <FileName>SampleControl.dll</FileName>
+        <DisplayName>SampleControl</DisplayName>
+        <Description>ComponentOwl.com SampleControl</Description>
+        <FileContentType>Toolbox Control</FileContentType>
+        <ContentVersion>2.0</ContentVersion>
+    </Content>
+</VSContent>
+
+

The content is readable and pretty straightforward. The +ContentVersion element can contain either "1.0" (support for Visual +Studio 2005, 2008 and 2010) or "2.0" (support for Visual Studio 2008, 2010, +2012, 2013).

+

Now we zip the two files and rename extension of the archive to .VSI. We +should end up with the following three files:

+

+

If you double-click the SampleControl.vsi, the Visual Studio +Content Installer opens up. You can start the installer from command line as +well:

+
32-bit OS: C:\Program Files\Common Files\Microsoft Shared\MSEnv\VSContentInstaller.exe SampleControl.vsi
+64-bit OS: C:\Program Files (x86)\Common Files\Microsoft Shared\MSEnv\VSContentInstaller.exe SampleControl.vsi
+

The installer have a form o wizard:

+

+

Signing the VSI Package

+

By default, the VSI package is not signed. This causes showing: "Publisher: +Unknown" label on the first page of the installation wizard and an unpleasant +dialog box later on:

+

+

To avoid this, you need to digitally sign the VSI package. Of course, you +have to own a digital certificate (usually an X.509 certificate stored in .PFX +file).

+

Because we cannot sign ZIP files, we need to convert the .VSI file (which is +actually a ZIP archive with just an altered extension) to self-extracting archive that the Visual Studio Content +Installer recognizes. There is a tool called MakeZipExe +to do this task:

+
MakeZipExe.exe -zipfile:SampleControl.vsi -output:SampleControl-unsigned.vsi -overwrite
+

The MakeZipExe tool is located at Visual Studio's binary +folder:

+
c:\Program Files (x86)\Microsoft Visual Studio 11.0\Common7\IDE\MakeZipExe.exe
+

The second step is signing the .EXE file using signtool.exe. +You can find signtool.exe in Microsoft Windows SDK, i.e.:

+
c:\Program Files (x86)\Microsoft SDKs\Windows\v7.0A\Bin\signtool.exe
+

Here is a sample usage of signtool.exe:

+
signtool.exe sign /du "http://www.componentowl.com/sample-control" /f certificate.pfx /p abc123 /t "http://timestamp.comodoca.com/authenticode" "SampleControl-signed.vsi"
+

When signed, the "Publisher" and "Information URL" labels are filled in the +installer and no dialog box appears. The benefit of signing is obvious - your +users will know they are installing trusted, possibly high-quality software and there +is a higher chance of your software being used more widely (for example, the +government sector usually require such certified software).

+

You can also add an EULA to your VSI package. This can be done by adding a +comment metadata in the archive by ZIP archiver that supports such feature (e.g. +WinZip).

+

Uninstalling the Control from Toolbox

+

As far as I know, the control cannot be removed from the Toolbox +programmatically. You need to delete the control's DLL located at

+
c:\Users\<user>\Documents\Visual Studio 2010\Controls\
+

the same should be done for every version of Visual Studio installed.

+

In Visual Studio, right-click on Toolbox and select "Reset Toolbox". The +component will not be found and disappear. Similarly, you can just +delete the control from the Toolbox or select "Choose Items..." from context +menu and untick the control there:

+

 

+

Drawbacks of Using VSI Package

+

One drawback of using VSI package is that the installer runs every version of +VS IDE you have installed and which is supported by the package. The form will +disappear eventually, but it lowers user experience.

+

Another drawback is that when you want to update your control, the installer +offers whether to rename, replace or skip the file (e.g. SampleControl.dll). User have to decide to +update, which also slows down installation and requires user interaction.

+

You also cannot specify custom Toolbox tab. All controls are installed under +"My Controls" tab:

+

+

8. Toolbox Integration using VSPackages

+

This approach brings full control over the integration and other benefits. The VSPackages are loaded on-demand, so +the integration process won't slow down a custom installer.

+

Although VSPackage and our sample control can be packed within the same +assembly, we will create a separate Visual Studio Package project.

+

When user opens Toolbox in VS for the first time after installation, the IDE +will look in registry for any registered packages and load them (if not loaded +previously).

+

Creating VSPackage Project

+

We would like to have our VSPackage compatible with VS 2010, 2012 +and 2013, so we will work in Visual Studio 2010.

+

Select "File - New - Project.." (Control+Shift+N) and +select the "Visual Studio Package" template:

+

+

This will start a "Visual Studio Package Wizard":

+

+

You can leave most options in the wizard on defaults. Leave all the check boxes unchecked +on "Page 3 of 7" and "Page 7 of 7":

+

+

+

Now we will take a look on the generated files. Open the Guids.cs +file:

+
+// Guids.cs
+// MUST match guids.h
+using System;
+
+namespace ComponentOwl.ToolboxIntegration
+{
+    static class GuidList
+    {
+        public const string GuidSampleVSPackagePkgString = "00000000-8fdf-48b6-98f8-4ff21a3a4def";
+        public const string GuidSampleVSPackageCmdSetString = "def6519d-5ace-4062-95d6-4ee43f4a5de9";
+
+        public static readonly Guid GuidSampleVSPackageCmdSet = new Guid(GuidSampleVSPackageCmdSetString);
+    };
+}
+
+

Here are the GUIDs that +uniquely identify your package. I have edited the first four hex digits of +package identifier to "00000000" so that we can find it more easily later. This is +just for purpose of convenience in our sample project. Always use randomly generated GUID +in a real-world application. Visual Studio will generate a new GUID +whenever you create a new VSPackage project.

+

You can also generate new GUIDs any time, for example using +online GUID +generator or guidgen.exe utility from Windows SDK. When these numbers are changed, your package will be different from +Visual Studio's point of view.

+

Another important file here is source.extension.vsixmanifest. +If you double-click on the file in Solution Explorer, the VSIX Manifest Designer +will show up:

+

+

Not all the fields are mandatory, but I will fill all of them nevertheless:

+
    +
  • ID - Unique product "Identity" - the ID is limited to + 100 characters and the recommended format is "Company.Product.Feature.Name". + We can leave the VSPackage's GUID here.
  • +
  • Product Name - This field is used for Toolbox Tab name, + so I will put "Component Owl Controls" here.
  • +
  • Author - Your name or company name - + "ComponentOwl.com", for example.
  • +
  • Version - This is version of the package and its + contents. The format is same as for assembly versions: + Major.Minor.Build.Revision. I will put "1.4.0.128" here.
  • +
  • Description - Speaks for itself.
  • +
  • Locale - Language for the package.
  • +
  • Supported VS Editions - Here you can specify which + editions of Visual Studio 2010 you would like to support. Of course, it can + support VS 2012/2013 as well, but for now I will just check Ultimate, Premium and + Professional editions.
  • +
  • Supported Framework Runtime - Minimum and maximum .NET + Framework Runtime versions your extension supports. Since my component will + support 4.0 and 4.5 runtime, I will put 4.0 and 4.5 here.
  • +
+

Adding Support for Visual Studio 2012/2013

+

We have specified supported Visual Studio Editions in VSIX Manifest Designer, +through the "Visual Studio Version and Edition" dialog box:

+

+

As you can see, only Visual Studio 2010 is supported here because VSIX is new +to 2010 and of course VS 2010 does not know about 2012/2013. We have to +source.extensions.vsixmanifest file for manual editing. Select the file +in Solution Explorer and press F7 (View Code):

+
+<?xml version="1.0" encoding="utf-8"?>
+<Vsix xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" Version="1.0.0" xmlns="http://schemas.microsoft.com/developer/vsx-schema/2010">
+  <Identifier Id="aaaaaaaa-8fdf-48b6-98f8-4ff21a3a4def">
+    <Name>SampleVsPackage</Name>
+    <Author>ComponentOwl.com</Author>
+    <Version>1.0</Version>
+    <Description xml:space="preserve">Information about my package</Description>
+    <Locale>1033</Locale>
+    <InstalledByMsi>false</InstalledByMsi>
+    <SupportedProducts>
+      <VisualStudio Version="10.0">
+        <Edition>Ultimate</Edition>
+        <Edition>Premium</Edition>
+        <Edition>Pro</Edition>
+      </VisualStudio>
+    </SupportedProducts>
+    <SupportedFrameworkRuntimeEdition MinVersion="4.0" MaxVersion="4.5" />
+  </Identifier>
+  <References>
+    <Reference Id="Microsoft.VisualStudio.MPF" MinVersion="10.0">
+      <Name>Visual Studio MPF</Name>
+    </Reference>
+  </References>
+  <Content>
+    <VsPackage>|%CurrentProject%;PkgdefProjectOutputGroup|</VsPackage>
+  </Content>
+</Vsix>
+
+

Take a look on the Vsix/Identifier/SupportedProducts/VisualStudio +element (highlighted in bold). Copy and paste this element and modify +Version attribute on the second one to "11.0":

+
+<VisualStudio Version="11.0">
+  <Edition>Ultimate</Edition>
+  <Edition>Premium</Edition>
+  <Edition>Pro</Edition>
+</VisualStudio>
+
+

The edition tags are valid for version 11.0 because Visual Studio 2012 +template generates the same edition names.

+

Writing Package Code

+

Now we will take a look on the VSPackage code itself. Open the +SampleVSPackage.cs +file. I kept only the necessary code and added the ProvideToolboxItems attribute:

+
+[PackageRegistration(UseManagedResourcesOnly = true)]
+[InstalledProductRegistration("#110", "#112", "1.0", IconResourceID = 400)]
+[Guid(GuidList.guidSampleVsPackagePkgString)]
+[ProvideToolboxItems(1)]
+public sealed class SampleVsPackage : Package
+{
+}
+
+

Our VSPackage implementation inherits from +Microsoft.VisualStudio.Shell.Package class and is decorated by three +attributes:

+
    +
  • PackageRegistrationAttribute - Specifies that package + registration tool should look for additional attributes (will be discussed + later).
  • +
  • InstalledProductRegistrationAttribute - Provides + information for the Visual Studio splash screen and About box.
  • +
  • GuidAttribute - Provides custom GUID for the class + because automatic GUID is undesirable here (Visual Studio need to be able to trace our + package by its unique ID).
  • +
  • ProvideToolboxItemsAttribute - Specifies that the + package provides toolbox items. There are various uses of VSPackages, but we + are interested in intalling controls to Visual Studio Toolbox, hence this + attribute.
  • +
+

The strings "#110" and "#112" in +InstalledProductRegistrationAttribute refer to keys in +VSPackage.resx. You can open this file and edit package name and +description there:

+

+

Now we write methods within SampleVsPackage class that work with the Toolbox:

+
+private const string ComponentFile = "SampleControl.dll";
+private const string TabName = "Component Owl";
+
+private void InstallToolboxItems()
+{
+    IToolboxService toolboxService = (IToolboxService)GetService(typeof(IToolboxService));
+
+    foreach (ToolboxItem item in ToolboxService.GetToolboxItems(GetAssemblyName()))
+    {
+        toolboxService.AddToolboxItem(item, TabName);
+    }
+}
+
+private void RemoveToolboxItems()
+{
+    IToolboxService toolboxService = (IToolboxService)GetService(typeof(IToolboxService));
+
+    foreach (ToolboxItem item in ToolboxService.GetToolboxItems(GetAssemblyName()))
+    {
+        toolboxService.RemoveToolboxItem(item);
+    }
+}
+
+private AssemblyName GetAssemblyName()
+{
+    string pathAssembly = String.Concat(
+        Path.GetDirectoryName(GetType().Assembly.Location),
+        Path.DirectorySeparatorChar,
+        ComponentFile);
+
+    return AssemblyName.GetAssemblyName(pathAssembly);
+}
+
+

The method names InstallToolboxItems and +RemoveToolboxItems +speak for themselves. Both methods look for SampleControl.dll in the same +location as the VSPackage's assembly. They get all toolbox items from the +assembly and either put them under "Component Owl" tab or remove them.

+

The ToolboxService class comes from +System.Drawing.Design and we need to add reference to this asssembly in +order to use ToolboxService.

+

Building the Package

+

Before building the SampleVsPackage project, open project +properties, find the VSIX tab and uncheck all the options:

+

+

Finally, build the project. Just two files, SampleVsPackage.dll +and SampleVsPackage.pdb, should be generated.

+

Registering the Package

+

Until the package can be loaded by Visual Studio, it needs to be +registered. +The registration is simply writing specific keys into Windows Registry.

+

To do that, find the Package Registration Utility (RegPkg.exe). It should be +located in Visual Studio SDK directory, e.g.:

+
32-bit OS: c:\Program Files\Microsoft Visual Studio 11.0\VSSDK\VisualStudioIntegration\Tools\Bin\RegPkg.exe
+64-bit OS: c:\Program Files (x86)\Microsoft Visual Studio 11.0\VSSDK\VisualStudioIntegration\Tools\Bin\RegPkg.exe
+

You can copy the tool where it suits you.

+

Here is a sample usage of RegPkg:

+
32-bit OS: RegPkg.exe /root:SOFTWARE\Microsoft\VisualStudio\11.0 /codebase SampleVsPackage.dll
+64-bit OS: RegPkg.exe /root:SOFTWARE\Wow6432Node\Microsoft\VisualStudio\11.0 /codebase SampleVsPackage.dll
+

This will write package registration information into the Windows Registry, +hence registers the package. Similar call have to be done by your custom installer in +order to register the package.

+

Instead of writing into registry, RegPkg.exe can gereate a REG file (several +other formats are available) so that you can write package information into +registry using the file. To do that, use /regfile parameter:

+
32-bit OS: RegPkg.exe /root:SOFTWARE\Microsoft\VisualStudio\11.0 /regfile:SampleVsPackage.ref /codebase SampleVsPackage.dll
+64-bit OS: RegPkg.exe /root:SOFTWARE\Wow6432Node\Microsoft\VisualStudio\11.0 /regfile:SampleVsPackage.ref /codebase SampleVsPackage.dll
+

This creates SampleVsPackge.reg file you can use any time +later instead of RegPkg.exe itself.

+

There are two other options for specifying how the package will be registered: +codebase and assembly. When /codebase +parameter is used (as in the sample above), the registry will point to the location on disk where your +package is located (see + +Assembly.CodeBase property for more information).

+

Another option is the /assembly parameter - this assumbes +that your VSPackage assembly is located in GAC (Global Assembly Cache). See +section Installing the Control in GAC for more information.

+

You can check out the registry after the package registration:

+

+

Package Registration for Visual Studio 2012/2013

+

Regrettably, simply registering package is not enough for Visual Studio 2012/2013 to load +it (see this + +blog post). Because of performance optimizations, VS developers removed +feature that looks for changes in VS registry root and thus we need to call

+
devenv.exe /Setup
+

In order to finish package registration.

+

This call can be very time consuming since Visual Studio 2012/2013 goes through all +extensions and looks for changes. On the other hand, I tried running devenv.exe with /Setup +parameter on fresh install of Visual Studio 2012/2013 and it was instant. On older +installation, however, the operation took well over a minute (it behaves just +like Microsoft Windows, which progressively slows down during its lifetime).

+

We can speed things up by a little hack. One of the things the /Setup +does is copying registry keys from HKLM to Visual Studio's 11.0_Config hive (or 12.0_Config, respectively). We can just write registry under this key +instead of calling devenv.exe and avoid possibly lengthy operation.

+

The hive is located in +HKEY_CURRENT_USER\Software\Microsoft\VisualStudio\11.0_Config.

+

So let's open and edit the SampleVsPackage.reg file we have +generated using RegPkg.exe earlier. Here is the modified version where only the +registry root has been changed:

+
+REGEDIT4
+
+[HKEY_CURRENT_USER\Software\Microsoft\VisualStudio\11.0_Config\InstalledProducts\SampleVsPackage]
+@="#110"
+"Package"="{00000000-8fdf-48b6-98f8-4ff21a3a4def}"
+"PID"="1.0"
+"ProductDetails"="#112"
+"LogoID"="#400"
+[HKEY_CURRENT_USER\Software\Microsoft\VisualStudio\11.0_Config\Packages\{00000000-8fdf-48b6-98f8-4ff21a3a4def}]
+@="ComponentOwl.ToolboxIntegration.SampleVsPackage, SampleVsPackage, Version=1.0.0.0, Culture=neutral, PublicKeyToken=30782fc44cbe0af5"
+"InprocServer32"="C:\\Windows\\SYSTEM32\\MSCOREE.DLL"
+"Class"="ComponentOwl.ToolboxIntegration.SampleVsPackage"
+"CodeBase"="C:\\projects\\articles\\2012-10-22 Visual Studio Toolbox Control Integration\\ToolboxIntegration\\SampleVsPackage\\bin\\Debug\\SampleVsPackage.DLL"
+[HKEY_CURRENT_USER\Software\Microsoft\VisualStudio\11.0_Config\Packages\{00000000-8fdf-48b6-98f8-4ff21a3a4def}]
+[HKEY_CURRENT_USER\Software\Microsoft\VisualStudio\11.0_Config\Packages\{00000000-8fdf-48b6-98f8-4ff21a3a4def}\Toolbox]
+"Default Items"=dword:00000001
+
+

The highlighted parts have been edited.

+

So in addition to standard package registration, we also write in the +registry where Visual Studio 2012/2013 user config hive resides. This is sufficient +for our VSPackage to load.

+

However, this is really a hack - editing of user configuration in registry +may cause Visual Studio to not load your user settings and show up as when +running for the first time. I tried this hack on my machine and it worked, but +there may be some hidden glitches. If you want to follow standard procedure, +just call "devenv.exe /Setup".

+

Loading VSPackage

+

If you did all the previous steps, your package should load when you open +Windows Forms Designer and show Toolbox (Cotrol+Alt+X). You can notice your +package name displaying in status bar for a while, then SampleControl should show up in the +Toolbox under "Component Owl" tab:

+

+

Displaying Your Extension in VS About Box

+

If you want information about your extension to be visible in Visual Studio +splash screen and About Box, implement IVsInstalledProduct +interface:

+
+...
+
+public sealed class SampleVsPackage : Package, IVsInstalledProduct
+{
+
+...
+
+	int IVsInstalledProduct.IdBmpSplash(out uint pIdBmp)
+	{
+	    pIdBmp = 0;
+	    return 0;
+	}
+	
+	int IVsInstalledProduct.IdIcoLogoForAboutbox(out uint pIdIco)
+	{
+	    pIdIco = 400;
+	    return 0;
+	}
+	
+	int IVsInstalledProduct.OfficialName(out string pbstrName)
+	{
+	    pbstrName = "ComponentOwl SampleControl";
+	    return 0;
+	}
+	
+	int IVsInstalledProduct.ProductDetails(out string pbstrProductDetails)
+	{
+	    pbstrProductDetails = "SampleControl control.\r\nFor more information see http://www.componentowl.com";
+	    return 0;
+	}
+	
+	int IVsInstalledProduct.ProductID(out string pbstrPID)
+	{
+	    pbstrPID = "3.3.0.0";
+	    return 0;
+	}
+	
+	...
+	
+}
+
+

This code causes the component to show up in the list of "Installed Products" +in Visual Studio about box:

+

+

As for the splash screen, Visual Studio 2008 used to display extensions in +its splash screen, but later version do not:

+

    +    +

+

Troubleshooting Package Load Failures

+

You may encounter this dialog when playing with packages:

+

+

When you click "No", the package will be skipped later when loading packages. +You can re-enable loading all packages by running

+
devenv.exe /ResetSkipPkgs
+

To debug package load problem, you can do just what the dialog says. Run

+
devenv.exe /log
+

and then take a look on the ActivityLog.xml (path is shown +in the dialog). There you can find cause of the problem in one of the "entry" +elements:

+
+...
+<entry>
+  <record>106</record>
+  <time>2012/10/26 06:07:36.920</time>
+  <type>Error</type>
+  <source>VisualStudio</source>
+  <description>CreateInstance failed for package [ComponentOwl.ToolboxIntegration.SampleVSPackage, SampleVSPackage, Version=1.0.0.0, Culture=neutral, PublicKeyToken=87379c2b0cde9bc3]</description>
+  <guid>{761F0CB7-64C1-4695-91D2-6E3C26C12314}</guid>
+  <hr>80070002</hr>
+  <errorinfo>Could not load file or assembly 'file:///C:\projects\articles\2012-10-22 Visual Studio Toolbox Control Integration\ToolboxIntegration\SampleVSPackage\bin\SampleVSPackage.DLL' or one of its dependencies. The system cannot find the file specified.</errorinfo>
+</entry>
+...
+
+

In this particular case, the problem was caused by changing output path from +"bin\SampleVSPackage.dll" to "bin\Debug\SampleVSPackage.dll" +so the file does not longer exist at the location for which it is registered. +The solution is to either change the location back or unregister the package +(i.e. remove the corresponding registry entries - the GUID is provided in the +log).

+

Past Troubles with Package Load Keys

+

The above problem with package load failure happened on Visual Studio 2005 +and 2008 because a Package Load Key (PLK) had to be provided by the VSPackage. +The PLK is basically a hashcode computed from metadata about package (name, +author/company, version). The PLK had to be obtained from a website provided by +Microsoft.

+

I believe PLK caused many troubles and headaches to developers, including +myself.

+

This is no longer relevant for Visual Studio 2010 and newer (requirement for +PLKs removed), so we won't discuss this topic in more depth

+

Update Control Already Installed in Toolbox

+

Suppose we have already integrated SampleControl version 3.3.0.0 in the +Visual Sudio Toolbox:

+

+

We would like to update this control to version 3.4.0.0.

+

First of all, we update assembly information of the SampleControl +project:

+

+

If we "deploy" (copy) SampleControl.dll to the folder with +SampleVsPackage.dll where it is registered, the SampleControl will no longer be +visible in Toolbox, because the control in Toolbox should still be 3.3.0.0 and +this version is no longer to be found.

+

You don't need to increment assembly version of the SampleVsPackage project, +but at least you have to increment parameter of the ProvideToolboxItems attribute:

+
+[PackageRegistration(UseManagedResourcesOnly = true)]
+[InstalledProductRegistration("#110", "#112", "1.0", IconResourceID = 400)]
+[Guid(GuidList.guidSampleVsPackagePkgString)]
+[ProvideToolboxItems(2)]
+public sealed class SampleVsPackage : Package, IVsInstalledProduct
+{
+	...
+}
+
+

The package need to be re-registered (see section Registering the Package) +which will effectively update just the "Default Items" value in the Toolbox key:

+

+

This will cause Visual Studio to update your control in the Toolbox:

+

+

Remove Control from the Toolbox

+

Now we would like to remove control from the Visual Studio Toolbox. This +step can be done by custom uninstaller.

+

One way to do that is to simply unregister the VSPackage using +RegPkg.exe:

+
32-bit OS: RegPkg.exe /unregister /root:SOFTWARE\Microsoft\VisualStudio\10.0 SampleVsPackage.dll
+64-bit OS: RegPkg.exe /First of all, we update assembly information of the unregisFirst of all, we update assembly information of the ter /root:SOFTWARE\Wow6432Node\Microsoft\VisualStudio\10.0 SampleVsPackage.dll
+

You can also do this manually by simply removing the registry entry of the +corresponding package, e.g.:

+
32-bit OS: HKLM\SOFTWARE\Microsoft\VisualStudio\10.0\Packages\{a9696de6-e209-414d-bbec-a0506fb0e924}
+64-bit OS: HKLM\SOFTWARE\Wow6432Node\Microsoft\VisualStudio\10.0\Packages\{a9696de6-e209-414d-bbec-a0506fb0e924}
+

On Visual Studio 2012/2013, the key need to be removed in user config registry +hive or call "devenv.exe /Setup" after removing the registry key in HKLM. For +more information, see section Package Registration for Visual Studio 2012/2013.

+

9. Toolbox Integration using VSIX Packages

+

Microsoft have removed most /po +f the drawbacks of VSI packages by introducing VSIX. The +price is that VSIX is a little bit more complicated and Visual Studio 2008 is no +longer supported.

+

There are two versions of VSIX Schema. Version 1.0 is what Visual Studio 2010 +understand. There is also version 2.0 for Visual Studio 2012/2013. We want a VSIX +Package compatible with both, so we will work in Visual Studio 2010.

+

Create a new Project from Template

+

If you have Visual Studio 2010 SDK installed, you can create a new VSIX +package project with control from a template.

+

Select "File - New - Project.." (Control+Shift+N) and +then select the "Windows Forms Toolbox Control" or "WPF +Toolbox Control" template:

+

+

The projects is basically a VSPackage wrapped in VSIX container after +build. The package assembly also contain the control class named +ToolboxControl.

+

There are three important files generated by the template:

+
    +
  • ProvideToolboxControlAttribute.cs - This is attribute + for ToolboxControl class. We will discuss it later.
  • +
  • source.extension.vsixmanifest - This is manifest XML + file for our VSIX package. It contains all information about the package and + what it contains.
  • +
  • ToolboxControl.cs - This is a sample control to be + installed in Visual Studio Toolbox.
  • +
+

Create a new Project from VSPackage

+

We can also start with VSPackage like the one we have already created in +previous section. I will create a new VSPackage project (as in previous +chapter), name it SampleVsixPackage and configure it according +to "Windows Forms Toolbox Control" template to show you all the differences.

+

The basic configuration of source.extension.vsixmanifest is +the same as in previous chapter.

+

Project properties differs from VSPackage we have created earlier on the VSIX +tab, where we have the first two check boxes checked:

+

+

Update the Manifest File

+

Double-click on the source.extension.vsixmanifest file to +open up the VSIX Manifest Designer:

+

+

If you are not sure about some part of the form, please take a look on +section Create VSPackage Project, where the form is described in more +detail.

+

In addition to previous VSPackage project, I have also filled the following +optional boxes:

+
    +
  • License Terms - If you have EULA or other licence in + TXT or RTF format, you can browse for it.
  • +
  • Icon - You can browse for an icon representing the + extension. It should be 32x32 pixels large, PNG, BMP, JPEG or ICO image + format.
  • +
  • Preview Image - Thumbnail image representing the + extension. It should be 200x200 pixels large, PNG, BMP or JPEG image format.
  • +
  • More Info URL - URL of a website containing more + information about the extension.
  • +
  • Getting Started Guide - URL of a website with + documentation; you can also provide relative path to HTML file with the + local documentation.
  • +
+

Add Control

+

Let's create a new WPF control within the SampleVsixPackage +project itself. I will name it SampleWpfControl to distinguish +it from SampleControl we have created earlier.

+

To ensure our control will show up in Toolbox of Visual Studio 2012/2013, we have +to decorate the SampleWpfControl class by +ProvideToolboxControlAttribute:

+
+[ProvideToolboxControl("SampleWpfControl", true)]
+public partial class SampleWpfControl : UserControl
+{
+	...
+}
+
+

You also have to provide implementation of the attribute class:

+
+[AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = true)]
+[System.Runtime.InteropServices.ComVisibleAttribute(false)]
+public sealed class ProvideToolboxControlAttribute : RegistrationAttribute
+{
+	private const string ToolboxControlsInstallerPath = "ToolboxControlsInstaller";
+
+	public ProvideToolboxControlAttribute(string name, bool isWpfControls)
+	{
+		if (name == null)
+		{
+			throw new ArgumentException("name");
+		}
+
+		this.Name = name;
+		this.IsWpfControls = isWpfControls;
+	}
+
+	private bool IsWpfControls { get; set; }
+	private string Name { get; set; }
+
+	public override void Register(RegistrationAttribute.RegistrationContext context)
+	{
+		if (context == null)
+		{
+			throw new ArgumentNullException("context");
+		}
+
+		using (Key key = context.CreateKey(String.Format(CultureInfo.InvariantCulture, "{0}\\{1}",
+														 ToolboxControlsInstallerPath,
+														 context.ComponentType.Assembly.FullName)))
+		{
+			key.SetValue(String.Empty, this.Name);
+			key.SetValue("Codebase", context.CodeBase);
+			if (this.IsWpfControls)
+			{
+				key.SetValue("WPFControls", "1");
+			}
+		}
+
+	}
+
+	public override void Unregister(RegistrationAttribute.RegistrationContext context)
+	{
+		if (context != null)
+		{
+			context.RemoveKey(String.Format(CultureInfo.InvariantCulture, "{0}\\{1}",
+														 ToolboxControlsInstallerPath,
+														 context.ComponentType.AssemblyQualifiedName));
+		}
+	}
+}
+
+

This code is generated if you create project from template.

+

The project in Solution Explorer should look like this:

+

+

+

Adding Controls from Other Projects

+

What if we would like to use SampleControl.dll as in the VSI +package scenario?

+

Of course, we can click "Add Content" in the VSIX Manifest designer and +simply add "Toolbox Control" content from other project:

+

+

However, this is possible only if the SampleControl project +itself is a package project!

+

Lucklily, since the VSIX package is still just a ZIP archive, we can take a +look on how to add such external DLLs to it manually.

+

Setting Up VSIX Installer

+

The VSIX Installer tool (VsixInstaller.exe) is located in +Visual Studio's binary folder:

+
32-bit OS: c:\Program Files\Microsoft Visual Studio 11.0\Common7\IDE\VSIXInstaller.exe
+64-bit OS: c:\Program Files (x86)\Microsoft Visual Studio 11.0\Common7\IDE\VSIXInstaller.exe
+

You can hit F6 and Visual Studio will build your project to create +SampleVsixPackage.vsix file. This is our VSIX package.

+

The VSIX Installer should be associated with the .VSIX file extension, so it is +usually possible +to just double-click on the file and see the VSIX installer.

+

The installation can fail in the very first step:

+

+

This problem appears if you have invalid manifest file. If this happen, open +source.extension.vsixmanifest and fill in all missing data. +Furthermore, you can check if the XML is valid according to +VSIX Extension +Schema.

+

Now we are able to rebuild and run the VSIX installer again:

+

+

Make the VSIX Package Compatible with Visual Studio 2012/2013

+

To make our VSIX package working with Visual Studio 2012 and newer, we need +to manually update the manifest file. Select the +source.extension.vsixmanifest file and press F7 (View Code):

+
+<?xml version="1.0" encoding="utf-8"?>
+<Vsix xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" Version="1.0.0" xmlns="http://schemas.microsoft.com/developer/vsx-schema/2010">
+  <Identifier Id="ComponentOwl.ToolboxControl.Express">
+    <Name>Component Owl</Name>
+    <Author>ComponentOwl.com</Author>
+    <Version>1.0</Version>
+    <Description xml:space="preserve">Windows Forms Toolbox Control</Description>
+    <Locale>1033</Locale>
+    <MoreInfoUrl>http://www.componentowl.com/toolbox-control</MoreInfoUrl>
+    <License>license.rtf</License>
+    <GettingStartedGuide>http://www.componentowl.com/documentation/toolbox-control</GettingStartedGuide>
+    <Icon>icon.png</Icon>
+    <PreviewImage>overview.jpg</PreviewImage>
+    <SupportedProducts>
+      <VisualStudio Version="10.0">
+        <Edition>Ultimate</Edition>
+        <Edition>Premium</Edition>
+        <Edition>Pro</Edition>
+      </VisualStudio>
+      <VisualStudio Version="11.0">
+        <Edition>Ultimate</Edition>
+        <Edition>Premium</Edition>
+        <Edition>Pro</Edition>
+      </VisualStudio>
+      <VisualStudio Version="12.0">
+        <Edition>Ultimate</Edition>
+        <Edition>Premium</Edition>
+        <Edition>Pro</Edition>
+      </VisualStudio>
+    </SupportedProducts>
+    <SupportedFrameworkRuntimeEdition MinVersion="4.0" MaxVersion="5.0" />
+  </Identifier>
+  <References />
+  <Content>
+    <ToolboxControl>|%CurrentProject%;PkgdefProjectOutputGroup|</ToolboxControl>
+  </Content>
+</Vsix>
+
+

The bolded text have been added. I have simply added a new +VisualStudio element with higher version and all the editions (they are +relevant for VS 2012 and 2013 as its own template also generates these).

+

The VSIX installer will show Visual Studio 2012 options as +well after this update (if installed, of course):

+

+

Please note that Visual Studio 2012/2013 also works with 2.0 version of the +schema, so if you create VSIX package in Visual Studio 2012/2013, it won't be +compatible with 2010. The solution is hence to use 1.0 version of the schema +and add support for newer Visual Studio as described earlier.

+

A great advantage over VSI package is that installation of Toolbox control is +really fast with VSIX.

+

Regrettably, the control won't show up in Visual Studio 2012/2013 Toolbox in its +default configuration. You need to enable loading-per user extensions (this +option is enabled by default in Visual Studio 2010):

+

+

Signing the VSIX Package

+

Unlike older VSI package, there is no nag screen when the package is not +signed. Instead, a label appears informing user that the package is not +signed.

+

To sign a VSIX package, we need PackageSignatureManager from +System.IO.Packaging (WindowsBase.dll). I made a simple command-line application called SignVsix (you can +find it in sample source code) that takes three arguments (VSIX file path, PFX +certificate path and password for the certificate):

+
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.IO.Packaging;
+using System.Security.Cryptography;
+using System.Security.Cryptography.X509Certificates;
+
+internal class Program
+{
+	private static void Main(string[] args)
+	{
+		// first argument - path to VSIX package
+		string paramPathPackage = args[0].Replace("\"", "");
+		// second argument - path to PFX certificate
+		string paramPathCertificate = args[1].Replace("\"", "");
+		// third argument - password for the certificate
+		string paramPassword = args[2];
+
+		// open VSIX package
+		Package package = Package.Open(paramPathPackage, FileMode.Open);
+
+		// load certificate
+		byte[] certificate = File.ReadAllBytes(paramPathCertificate);
+
+		// sign all parts of the package
+		var signatureManager = new PackageDigitalSignatureManager(package)
+		{
+			CertificateOption = CertificateEmbeddingOption.InSignaturePart
+		};
+
+		List<Uri> partsToSign = new List<Uri>();
+
+		foreach (PackagePart packagePart in package.GetParts())
+		{
+			partsToSign.Add(packagePart.Uri);
+		}
+
+		partsToSign.Add(PackUriHelper.GetRelationshipPartUri(signatureManager.SignatureOrigin));
+		partsToSign.Add(signatureManager.SignatureOrigin);
+		partsToSign.Add(PackUriHelper.GetRelationshipPartUri(new Uri("/", UriKind.RelativeOrAbsolute)));
+
+		try
+		{
+			signatureManager.Sign(partsToSign, new X509Certificate2(certificate, paramPassword));
+		}
+		catch (CryptographicException cryptographicException)
+		{
+			Console.WriteLine("Signing failed: {0}", cryptographicException.Message);
+		}
+	}
+}
+
+

The usage is very simple:

+
SignVsix.exe SampleVsixPackage.vsix certificate.pfx abc123
+

When the file is signed, VSIX Installer shows label "Digital Signature: +<Author Name>" on the first page:

+

+

Dissecting the VSIX Package

+

If you look on the project references, you can see reference to +Microsoft.VisualStudio.Shell.Immutable.10. This reference points to +Visual Studio 2010 SDK and we cannot expect this dependency present on end-user's machine. This +library contains ProvideToolboxControlAttribute class, which is +used by our ToolboxControl.

+

Since a software development company may want to develop many components, it would be nice to have an +universal VSIX package which can be adjusted for any control.

+

Let's take a look on the ToolboxControl.vsix. It is simply a +ZIP archive containing the manifest, resources, ToolboxControl binary and a +ToolboxControl.pkgdef file. If we look through all its content, +we easily generate our own VSIX packages on demand, even without Visual Studio. +There should also be a programmatic way on generating VSIX packages using +classes from System.IO.Packaging.

+

Update Toolbox Control via VSIX Package

+

If you made changes to your control and want to re-install the package, an +error message appear:

+

+

In order to provide an update, you need to increment version number in the +VSIX manifest:

+

+

You can also increment version number in the Package class attribute, but +this is not necessary for the VSIX to perform update:

+
+[InstalledProductRegistration("#110", "#112", "2.0", IconResourceID = 400)]
+[Guid(GuidList.guidSampleVsixPackagePkgString)]
+public sealed class SampleVsixPackage : Package
+{
+	...
+}
+
+

Of course, you can also increment version of the assembly.

+

Uninstall the VSIX Package

+

The VSIX Installer can be used to uninstall control from the Toolbox via +/uninstall parameter followed by package ID (the constant located in +Guids.cs: GuidList.guidSampleVsixPackagePkgString):

+
VSIXInstaller.exe /uninstall:e3dfd099-d0ab-4b8e-b26d-639032c29ad9
+

It is also possible to uninstall VSIX Package manually using +Extension Manager (Tools - Extension Manager...). In Visual Studio +2012/2013, the corresponding dialog is called Extensions and Updates +(Tools - Extensions and Updates...).

+

+

Quiet Mode

+

Both installation and uninstallation can be performed in quiet mode by using /quiet parameter. This will suppress +user interface of the installer, which is handy when you want to automate +Toolbox control integration with your custom installer.

+

10. Supporting Multiple Version of .NET Framework

+

Since .NET Framework is backward-compatible, building a component on lowest +possible framework ensures compatibility with higher versions as well.

+

I heard from several users that the component may not be displayed in Toolbox +although it seems that the Toolbox respects the .NET compatibility and display +.NET 2.0 component even when working in .NET 4.0 (Client Profile) project.

+

There is also a scenario where you want to support additional features from +higher version of .NET (for example, drawing text using GDI+ in .NET 2.0 and +drawing text using WPF in .NET 3.5 and higher). You may also want to add +extensive Windows Forms Designer support, which is not available in Client +Profile framework.

+

The solution to this is to build several DLLs, each with different features +and possibly different target frameworks. Then integrate all the assemblies.

+

This does not pose a problem when DTE approach is used, +alhtough it is better to give each version of the component unique name or place +them in separate tabs (e.g. "Component Owl WinForms - .NET 2.0").

+

When TCI approach is used, each version of the assembly +requires different public key token, because they have to reside in GAC +side-by-side. Furthermore, they need a separate registry key based on the public +key token.

+

The VSI and VSIX approaches require +renaming the component or customizing Toolbox tab in the +ProvideToolboxControlAttribute (see part Toolbox Control Integration using +VSIX Packages for more information).

+

The VSPackage approach allows you to place all the versions +in Visual Studio Toolbox under their respective tabs.

+

When manual approach is used, you can of course add each +version of the assembly separately and also create separate tabs in the Toolbox.

+ +

11. Sample Source Code

+ +

The attached sample source is a Visual Studio 2010 Solution containing +implementations of all the presented approaches. The binaries are contained +under "bin\Release" subfolders and batch files (.CMD extension) are provided +where appropriate.

+ +

+Download sample source code (212 KB) +

+ +

You can find the following folders in the archive:

+

DteToolboxInstaller - A command-line application for +installing/uninstalling assemblies in VS Toolbox using Visual Studio Automation +Object Model (DTE). Custom tab name and VS version can be specified. The tool +can be used in real-world application.

+

SampleControl - Windows Forms control for testing the +integration.

+

SampleVsixPackage - VSIX package project (basically a +VSPackage that is further packaged with the sample control), the resulting +package can be installed by VSIX Installer that comes with Visual Studio.

+

SampleVsPackage - VSPackage that is able to install all +control assemblies located in its own folder. Contains batch files for package +registration/unregistration.

+

SignVsix - A command-line application for signing VSIX +packages. Sample batch file is provided. Valid PFX certificate need to be +provided by the user.

+

TciToolboxInstaller - A command-line application for +installing/uninstalling assemblies in VS Toolbox using Toolbox Control Installer +package (but does not depend on it). Custom tab name and VS version can be +specified. The tool can be used in real-world application.

+

VSI - Basic setting for creating VSI package and a sample +VSI package created from the files. Batch file for signing the VSI package is +provided.

+

 

+ +

+Download sample source code (212 KB) +

+ Creative Commons License
This work is licensed under a Creative Commons Attribution 3.0 Unported License.Component Owl WinForms - .NET 2.0
@@ -1668,7 +1668,7 @@ provided.

- + diff --git a/src/data/better-listview-express/comparison-with-full-version.html b/src/data/better-listview-express/comparison-with-full-version.html index 95a9675..b3ff78a 100644 --- a/src/data/better-listview-express/comparison-with-full-version.html +++ b/src/data/better-listview-express/comparison-with-full-version.html @@ -41,16 +41,16 @@ var t = {"antispam":"capek-rulz","purchase_email":"valid purchase email","valid_ - icon Better ListView
Ultimate ListView control for .NET
+ icon Better ListView
Ultimate ListView control for .NET
- icon Better Thumbnail Browser
Thumbnail loading and browsing control for .NET
+ icon Better Thumbnail Browser
Thumbnail loading and browsing control for .NET
- icon Better SplitButton
Free customizable dropdown button control
+ icon Better SplitButton
Free customizable dropdown button control
- icon Better ListView Express
Free edition with less features
+ icon Better ListView Express
Free edition with less features
@@ -117,570 +117,570 @@ var t = {"antispam":"capek-rulz","purchase_email":"valid purchase email","valid_ - - + diff --git a/src/data/blog/better-thumbnail-browser-component-released/index.html b/src/data/blog/better-thumbnail-browser-component-released/index.html index 3b9260c..23a94d0 100644 --- a/src/data/blog/better-thumbnail-browser-component-released/index.html +++ b/src/data/blog/better-thumbnail-browser-component-released/index.html @@ -79,7 +79,7 @@ img.emoji {

 

We have released a whole new WinForms component called Better Thumbnail Browser. This control is useful for anyone developing photo management software or any kind of image database:

-
Better Thumbnail Browser Overview

Better Thumbnail Browser Overview

+
Better Thumbnail Browser Overview

Better Thumbnail Browser Overview

The control is capable of loading image thumbnails on background and does all the dirty job of threading and synchronization for you.

My motivation to make such component as lead developer at ComponentOwl.com was to have something that can smoothly integrate in my photo management software.

Since we already have Better ListView component, which is quite mature (three major releases over two years of development), I decided to build upon it and finally make control for image thumbnails that is both extensible and powerful and have native look and feel.

@@ -182,24 +182,24 @@ img.emoji {
- - - - - - - + +
+ @@ -304,11 +304,11 @@ img.emoji { - - \ No newline at end of file diff --git a/src/data/blog/category/announcements/feed/index.html b/src/data/blog/category/announcements/feed/index.html index 87a9e63..d1bb6a6 100644 --- a/src/data/blog/category/announcements/feed/index.html +++ b/src/data/blog/category/announcements/feed/index.html @@ -81,7 +81,7 @@  

We have released a whole new WinForms component called Better Thumbnail Browser. This control is useful for anyone developing photo management software or any kind of image database:

-
Better Thumbnail Browser Overview

Better Thumbnail Browser Overview

+
Better Thumbnail Browser Overview

Better Thumbnail Browser Overview

The control is capable of loading image thumbnails on background and does all the dirty job of threading and synchronization for you.

My motivation to make such component as lead developer at ComponentOwl.com was to have something that can smoothly integrate in my photo management software.

Since we already have Better ListView component, which is quite mature (three major releases over two years of development), I decided to build upon it and finally make control for image thumbnails that is both extensible and powerful and have native look and feel.

@@ -318,11 +318,11 @@ - - \ No newline at end of file diff --git a/src/data/blog/category/components/feed/index.html b/src/data/blog/category/components/feed/index.html index bd39381..3f91a17 100644 --- a/src/data/blog/category/components/feed/index.html +++ b/src/data/blog/category/components/feed/index.html @@ -523,7 +523,7 @@ End Sub
 

We have released a whole new WinForms component called Better Thumbnail Browser. This control is useful for anyone developing photo management software or any kind of image database:

-
Better Thumbnail Browser Overview

Better Thumbnail Browser Overview

+
Better Thumbnail Browser Overview

Better Thumbnail Browser Overview

The control is capable of loading image thumbnails on background and does all the dirty job of threading and synchronization for you.

My motivation to make such component as lead developer at ComponentOwl.com was to have something that can smoothly integrate in my photo management software.

Since we already have Better ListView component, which is quite mature (three major releases over two years of development), I decided to build upon it and finally make control for image thumbnails that is both extensible and powerful and have native look and feel.

@@ -729,11 +729,11 @@ Me.listView.LoadContentBinary(stream)
- - \ No newline at end of file diff --git a/src/data/blog/page/6/index.html b/src/data/blog/page/6/index.html index 09abe62..0e2977f 100644 --- a/src/data/blog/page/6/index.html +++ b/src/data/blog/page/6/index.html @@ -53,16 +53,16 @@ height="0" width="0" style="display:none;visibility:hidden"> - icon Better ListView
Ultimate ListView control for .NET
+ icon Better ListView
Ultimate ListView control for .NET
- icon Better Thumbnail Browser
Thumbnail loading and browsing control for .NET
+ icon Better Thumbnail Browser
Thumbnail loading and browsing control for .NET
- icon Better SplitButton
Free customizable dropdown button control
+ icon Better SplitButton
Free customizable dropdown button control
- icon Better ListView Express
Free edition with less features
+ icon Better ListView Express
Free edition with less features
@@ -135,236 +135,236 @@ height="0" width="0" style="display:none;visibility:hidden"> - @@ -121,7 +121,7 @@ var t = {"antispam":"capek-rulz","purchase_email":"valid purchase email","valid_
- 0000-angry_web_1312217558 + 0000-angry_web_1312217558
@@ -287,19 +287,19 @@ Copyright © 2018 ComponentOwl.com, Dextronet.com. All rights reserved. Read - + diff --git a/src/data/comics/10.html b/src/data/comics/10.html index b420b58..6677093 100644 --- a/src/data/comics/10.html +++ b/src/data/comics/10.html @@ -24,7 +24,7 @@ - + @@ -49,16 +49,16 @@ var t = {"antispam":"capek-rulz","purchase_email":"valid purchase email","valid_ - icon Better ListView
Ultimate ListView control for .NET
+ icon Better ListView
Ultimate ListView control for .NET
- icon Better Thumbnail Browser
Thumbnail loading and browsing control for .NET
+ icon Better Thumbnail Browser
Thumbnail loading and browsing control for .NET
- icon Better SplitButton
Free customizable dropdown button control
+ icon Better SplitButton
Free customizable dropdown button control
- icon Better ListView Express
Free edition with less features
+ icon Better ListView Express
Free edition with less features
@@ -121,7 +121,7 @@ var t = {"antispam":"capek-rulz","purchase_email":"valid purchase email","valid_
- 0003-qa-black-magic_web_web_1312973269 + 0003-qa-black-magic_web_web_1312973269
@@ -287,19 +287,19 @@ Copyright © 2018 ComponentOwl.com, Dextronet.com. All rights reserved. Read - + diff --git a/src/data/comics/11.html b/src/data/comics/11.html index 4c719ca..a101b0c 100644 --- a/src/data/comics/11.html +++ b/src/data/comics/11.html @@ -24,7 +24,7 @@ - + @@ -49,16 +49,16 @@ var t = {"antispam":"capek-rulz","purchase_email":"valid purchase email","valid_ - icon Better ListView
Ultimate ListView control for .NET
+ icon Better ListView
Ultimate ListView control for .NET
- icon Better Thumbnail Browser
Thumbnail loading and browsing control for .NET
+ icon Better Thumbnail Browser
Thumbnail loading and browsing control for .NET
- icon Better SplitButton
Free customizable dropdown button control
+ icon Better SplitButton
Free customizable dropdown button control
- icon Better ListView Express
Free edition with less features
+ icon Better ListView Express
Free edition with less features
@@ -121,7 +121,7 @@ var t = {"antispam":"capek-rulz","purchase_email":"valid purchase email","valid_
- 0004-dark-intellisense_web_web_1313141785 + 0004-dark-intellisense_web_web_1313141785
@@ -287,19 +287,19 @@ Copyright © 2018 ComponentOwl.com, Dextronet.com. All rights reserved. Read - + diff --git a/src/data/comics/12.html b/src/data/comics/12.html index c9a2eaf..e83191d 100644 --- a/src/data/comics/12.html +++ b/src/data/comics/12.html @@ -24,7 +24,7 @@ - + @@ -49,16 +49,16 @@ var t = {"antispam":"capek-rulz","purchase_email":"valid purchase email","valid_ - icon Better ListView
Ultimate ListView control for .NET
+ icon Better ListView
Ultimate ListView control for .NET
- icon Better Thumbnail Browser
Thumbnail loading and browsing control for .NET
+ icon Better Thumbnail Browser
Thumbnail loading and browsing control for .NET
- icon Better SplitButton
Free customizable dropdown button control
+ icon Better SplitButton
Free customizable dropdown button control
- icon Better ListView Express
Free edition with less features
+ icon Better ListView Express
Free edition with less features
@@ -121,7 +121,7 @@ var t = {"antispam":"capek-rulz","purchase_email":"valid purchase email","valid_
- 0005-who-takes-the-credit_web_web_1313244880 + 0005-who-takes-the-credit_web_web_1313244880
@@ -287,19 +287,19 @@ Copyright © 2018 ComponentOwl.com, Dextronet.com. All rights reserved. Read - + diff --git a/src/data/comics/13.html b/src/data/comics/13.html index e662355..a7d60b0 100644 --- a/src/data/comics/13.html +++ b/src/data/comics/13.html @@ -24,7 +24,7 @@ - + @@ -49,16 +49,16 @@ var t = {"antispam":"capek-rulz","purchase_email":"valid purchase email","valid_ - icon Better ListView
Ultimate ListView control for .NET
+ icon Better ListView
Ultimate ListView control for .NET
- icon Better Thumbnail Browser
Thumbnail loading and browsing control for .NET
+ icon Better Thumbnail Browser
Thumbnail loading and browsing control for .NET
- icon Better SplitButton
Free customizable dropdown button control
+ icon Better SplitButton
Free customizable dropdown button control
- icon Better ListView Express
Free edition with less features
+ icon Better ListView Express
Free edition with less features
@@ -121,7 +121,7 @@ var t = {"antispam":"capek-rulz","purchase_email":"valid purchase email","valid_
- 0006-ergonomic-chairs_web_web_1313244999 + 0006-ergonomic-chairs_web_web_1313244999
@@ -287,19 +287,19 @@ Copyright © 2018 ComponentOwl.com, Dextronet.com. All rights reserved. Read - + diff --git a/src/data/comics/14.html b/src/data/comics/14.html index 0403415..1c53c27 100644 --- a/src/data/comics/14.html +++ b/src/data/comics/14.html @@ -24,7 +24,7 @@ - + @@ -49,16 +49,16 @@ var t = {"antispam":"capek-rulz","purchase_email":"valid purchase email","valid_ - icon Better ListView
Ultimate ListView control for .NET
+ icon Better ListView
Ultimate ListView control for .NET
- icon Better Thumbnail Browser
Thumbnail loading and browsing control for .NET
+ icon Better Thumbnail Browser
Thumbnail loading and browsing control for .NET
- icon Better SplitButton
Free customizable dropdown button control
+ icon Better SplitButton
Free customizable dropdown button control
- icon Better ListView Express
Free edition with less features
+ icon Better ListView Express
Free edition with less features
@@ -121,7 +121,7 @@ var t = {"antispam":"capek-rulz","purchase_email":"valid purchase email","valid_
- 0007-the-meaningful-deadline_web_web_1313685127 + 0007-the-meaningful-deadline_web_web_1313685127
@@ -287,19 +287,19 @@ Copyright © 2018 ComponentOwl.com, Dextronet.com. All rights reserved. Read - + diff --git a/src/data/comics/15.html b/src/data/comics/15.html index 2c80ca6..6e0aa82 100644 --- a/src/data/comics/15.html +++ b/src/data/comics/15.html @@ -24,7 +24,7 @@ - + @@ -49,16 +49,16 @@ var t = {"antispam":"capek-rulz","purchase_email":"valid purchase email","valid_ - icon Better ListView
Ultimate ListView control for .NET
+ icon Better ListView
Ultimate ListView control for .NET
- icon Better Thumbnail Browser
Thumbnail loading and browsing control for .NET
+ icon Better Thumbnail Browser
Thumbnail loading and browsing control for .NET
- icon Better SplitButton
Free customizable dropdown button control
+ icon Better SplitButton
Free customizable dropdown button control
- icon Better ListView Express
Free edition with less features
+ icon Better ListView Express
Free edition with less features
@@ -121,7 +121,7 @@ var t = {"antispam":"capek-rulz","purchase_email":"valid purchase email","valid_
- 0008-green-productivity_web_web_1314037931 + 0008-green-productivity_web_web_1314037931
@@ -287,19 +287,19 @@ Copyright © 2018 ComponentOwl.com, Dextronet.com. All rights reserved. Read - + diff --git a/src/data/comics/16.html b/src/data/comics/16.html index 6f2e0ec..5ed9134 100644 --- a/src/data/comics/16.html +++ b/src/data/comics/16.html @@ -24,7 +24,7 @@ - + @@ -49,16 +49,16 @@ var t = {"antispam":"capek-rulz","purchase_email":"valid purchase email","valid_ - icon Better ListView
Ultimate ListView control for .NET
+ icon Better ListView
Ultimate ListView control for .NET
- icon Better Thumbnail Browser
Thumbnail loading and browsing control for .NET
+ icon Better Thumbnail Browser
Thumbnail loading and browsing control for .NET
- icon Better SplitButton
Free customizable dropdown button control
+ icon Better SplitButton
Free customizable dropdown button control
- icon Better ListView Express
Free edition with less features
+ icon Better ListView Express
Free edition with less features
@@ -121,7 +121,7 @@ var t = {"antispam":"capek-rulz","purchase_email":"valid purchase email","valid_
- 0009-from-scratch_web_web_1314809417 + 0009-from-scratch_web_web_1314809417
@@ -287,19 +287,19 @@ Copyright © 2018 ComponentOwl.com, Dextronet.com. All rights reserved. Read - + diff --git a/src/data/comics/17.html b/src/data/comics/17.html index f24b833..5c6c259 100644 --- a/src/data/comics/17.html +++ b/src/data/comics/17.html @@ -24,7 +24,7 @@ - + @@ -49,16 +49,16 @@ var t = {"antispam":"capek-rulz","purchase_email":"valid purchase email","valid_ - icon Better ListView
Ultimate ListView control for .NET
+ icon Better ListView
Ultimate ListView control for .NET
- icon Better Thumbnail Browser
Thumbnail loading and browsing control for .NET
+ icon Better Thumbnail Browser
Thumbnail loading and browsing control for .NET
- icon Better SplitButton
Free customizable dropdown button control
+ icon Better SplitButton
Free customizable dropdown button control
- icon Better ListView Express
Free edition with less features
+ icon Better ListView Express
Free edition with less features
@@ -121,7 +121,7 @@ var t = {"antispam":"capek-rulz","purchase_email":"valid purchase email","valid_
- 0010-a-reward_web_web_1316015834 + 0010-a-reward_web_web_1316015834
@@ -287,19 +287,19 @@ Copyright © 2018 ComponentOwl.com, Dextronet.com. All rights reserved. Read - + diff --git a/src/data/comics/18.html b/src/data/comics/18.html index 15e0017..9efa479 100644 --- a/src/data/comics/18.html +++ b/src/data/comics/18.html @@ -24,7 +24,7 @@ - + @@ -49,16 +49,16 @@ var t = {"antispam":"capek-rulz","purchase_email":"valid purchase email","valid_ - icon Better ListView
Ultimate ListView control for .NET
+ icon Better ListView
Ultimate ListView control for .NET
- icon Better Thumbnail Browser
Thumbnail loading and browsing control for .NET
+ icon Better Thumbnail Browser
Thumbnail loading and browsing control for .NET
- icon Better SplitButton
Free customizable dropdown button control
+ icon Better SplitButton
Free customizable dropdown button control
- icon Better ListView Express
Free edition with less features
+ icon Better ListView Express
Free edition with less features
@@ -121,7 +121,7 @@ var t = {"antispam":"capek-rulz","purchase_email":"valid purchase email","valid_
- 0011-hard-discipline_web_web_1318625423 + 0011-hard-discipline_web_web_1318625423
@@ -287,19 +287,19 @@ Copyright © 2018 ComponentOwl.com, Dextronet.com. All rights reserved. Read - + diff --git a/src/data/comics/19.html b/src/data/comics/19.html index 24f1bef..c99406a 100644 --- a/src/data/comics/19.html +++ b/src/data/comics/19.html @@ -24,7 +24,7 @@ - + @@ -49,16 +49,16 @@ var t = {"antispam":"capek-rulz","purchase_email":"valid purchase email","valid_ - icon Better ListView
Ultimate ListView control for .NET
+ icon Better ListView
Ultimate ListView control for .NET
- icon Better Thumbnail Browser
Thumbnail loading and browsing control for .NET
+ icon Better Thumbnail Browser
Thumbnail loading and browsing control for .NET
- icon Better SplitButton
Free customizable dropdown button control
+ icon Better SplitButton
Free customizable dropdown button control
- icon Better ListView Express
Free edition with less features
+ icon Better ListView Express
Free edition with less features
@@ -121,7 +121,7 @@ var t = {"antispam":"capek-rulz","purchase_email":"valid purchase email","valid_
- 0012-breaking-the-nda-web_web_1321141101 + 0012-breaking-the-nda-web_web_1321141101
@@ -287,19 +287,19 @@ Copyright © 2018 ComponentOwl.com, Dextronet.com. All rights reserved. Read - + diff --git a/src/data/comics/2.html b/src/data/comics/2.html index 19aabca..a6e6fca 100644 --- a/src/data/comics/2.html +++ b/src/data/comics/2.html @@ -24,7 +24,7 @@ - + @@ -49,16 +49,16 @@ var t = {"antispam":"capek-rulz","purchase_email":"valid purchase email","valid_ - icon Better ListView
Ultimate ListView control for .NET
+ icon Better ListView
Ultimate ListView control for .NET
- icon Better Thumbnail Browser
Thumbnail loading and browsing control for .NET
+ icon Better Thumbnail Browser
Thumbnail loading and browsing control for .NET
- icon Better SplitButton
Free customizable dropdown button control
+ icon Better SplitButton
Free customizable dropdown button control
- icon Better ListView Express
Free edition with less features
+ icon Better ListView Express
Free edition with less features
@@ -121,7 +121,7 @@ var t = {"antispam":"capek-rulz","purchase_email":"valid purchase email","valid_
- 01-boss_and_the_worker-out_web_1312287061 + 01-boss_and_the_worker-out_web_1312287061
@@ -287,19 +287,19 @@ Copyright © 2018 ComponentOwl.com, Dextronet.com. All rights reserved. Read - + diff --git a/src/data/comics/20.html b/src/data/comics/20.html index 3335754..aff2185 100644 --- a/src/data/comics/20.html +++ b/src/data/comics/20.html @@ -24,7 +24,7 @@ - + @@ -49,16 +49,16 @@ var t = {"antispam":"capek-rulz","purchase_email":"valid purchase email","valid_ - icon Better ListView
Ultimate ListView control for .NET
+ icon Better ListView
Ultimate ListView control for .NET
- icon Better Thumbnail Browser
Thumbnail loading and browsing control for .NET
+ icon Better Thumbnail Browser
Thumbnail loading and browsing control for .NET
- icon Better SplitButton
Free customizable dropdown button control
+ icon Better SplitButton
Free customizable dropdown button control
- icon Better ListView Express
Free edition with less features
+ icon Better ListView Express
Free edition with less features
@@ -121,7 +121,7 @@ var t = {"antispam":"capek-rulz","purchase_email":"valid purchase email","valid_
- 0013-thorough-nda-web_web_1321359683 + 0013-thorough-nda-web_web_1321359683
@@ -287,19 +287,19 @@ Copyright © 2018 ComponentOwl.com, Dextronet.com. All rights reserved. Read - + diff --git a/src/data/comics/21.html b/src/data/comics/21.html index 1898a26..e3abf1b 100644 --- a/src/data/comics/21.html +++ b/src/data/comics/21.html @@ -24,7 +24,7 @@ - + @@ -49,16 +49,16 @@ var t = {"antispam":"capek-rulz","purchase_email":"valid purchase email","valid_ - icon Better ListView
Ultimate ListView control for .NET
+ icon Better ListView
Ultimate ListView control for .NET
- icon Better Thumbnail Browser
Thumbnail loading and browsing control for .NET
+ icon Better Thumbnail Browser
Thumbnail loading and browsing control for .NET
- icon Better SplitButton
Free customizable dropdown button control
+ icon Better SplitButton
Free customizable dropdown button control
- icon Better ListView Express
Free edition with less features
+ icon Better ListView Express
Free edition with less features
@@ -121,7 +121,7 @@ var t = {"antispam":"capek-rulz","purchase_email":"valid purchase email","valid_
- 0014-santa-courier-web_web_1322411181 + 0014-santa-courier-web_web_1322411181
@@ -287,19 +287,19 @@ Copyright © 2018 ComponentOwl.com, Dextronet.com. All rights reserved. Read - + diff --git a/src/data/comics/22.html b/src/data/comics/22.html index a595a0a..eee6722 100644 --- a/src/data/comics/22.html +++ b/src/data/comics/22.html @@ -24,7 +24,7 @@ - + @@ -49,16 +49,16 @@ var t = {"antispam":"capek-rulz","purchase_email":"valid purchase email","valid_ - icon Better ListView
Ultimate ListView control for .NET
+ icon Better ListView
Ultimate ListView control for .NET
- icon Better Thumbnail Browser
Thumbnail loading and browsing control for .NET
+ icon Better Thumbnail Browser
Thumbnail loading and browsing control for .NET
- icon Better SplitButton
Free customizable dropdown button control
+ icon Better SplitButton
Free customizable dropdown button control
- icon Better ListView Express
Free edition with less features
+ icon Better ListView Express
Free edition with less features
@@ -121,7 +121,7 @@ var t = {"antispam":"capek-rulz","purchase_email":"valid purchase email","valid_
- 0015-write-it-a-thousand-times-web_web_1322855667 + 0015-write-it-a-thousand-times-web_web_1322855667
@@ -287,19 +287,19 @@ Copyright © 2018 ComponentOwl.com, Dextronet.com. All rights reserved. Read - + diff --git a/src/data/comics/23.html b/src/data/comics/23.html index 94a75cf..f34a73c 100644 --- a/src/data/comics/23.html +++ b/src/data/comics/23.html @@ -24,7 +24,7 @@ - + @@ -49,16 +49,16 @@ var t = {"antispam":"capek-rulz","purchase_email":"valid purchase email","valid_ - icon Better ListView
Ultimate ListView control for .NET
+ icon Better ListView
Ultimate ListView control for .NET
- icon Better Thumbnail Browser
Thumbnail loading and browsing control for .NET
+ icon Better Thumbnail Browser
Thumbnail loading and browsing control for .NET
- icon Better SplitButton
Free customizable dropdown button control
+ icon Better SplitButton
Free customizable dropdown button control
- icon Better ListView Express
Free edition with less features
+ icon Better ListView Express
Free edition with less features
@@ -121,7 +121,7 @@ var t = {"antispam":"capek-rulz","purchase_email":"valid purchase email","valid_
- 0016-touch-the-tiles-web_web_1323309221 + 0016-touch-the-tiles-web_web_1323309221
@@ -287,19 +287,19 @@ Copyright © 2018 ComponentOwl.com, Dextronet.com. All rights reserved. Read - + diff --git a/src/data/comics/24.html b/src/data/comics/24.html index 5f2ee94..bf7a074 100644 --- a/src/data/comics/24.html +++ b/src/data/comics/24.html @@ -24,7 +24,7 @@ - + @@ -49,16 +49,16 @@ var t = {"antispam":"capek-rulz","purchase_email":"valid purchase email","valid_ - icon Better ListView
Ultimate ListView control for .NET
+ icon Better ListView
Ultimate ListView control for .NET
- icon Better Thumbnail Browser
Thumbnail loading and browsing control for .NET
+ icon Better Thumbnail Browser
Thumbnail loading and browsing control for .NET
- icon Better SplitButton
Free customizable dropdown button control
+ icon Better SplitButton
Free customizable dropdown button control
- icon Better ListView Express
Free edition with less features
+ icon Better ListView Express
Free edition with less features
@@ -121,7 +121,7 @@ var t = {"antispam":"capek-rulz","purchase_email":"valid purchase email","valid_
- 0017-lazy-evaluation-web_web_1323736761 + 0017-lazy-evaluation-web_web_1323736761
@@ -287,19 +287,19 @@ Copyright © 2018 ComponentOwl.com, Dextronet.com. All rights reserved. Read - + diff --git a/src/data/comics/25.html b/src/data/comics/25.html index e3043a6..e8ac0e6 100644 --- a/src/data/comics/25.html +++ b/src/data/comics/25.html @@ -24,7 +24,7 @@ - + @@ -49,16 +49,16 @@ var t = {"antispam":"capek-rulz","purchase_email":"valid purchase email","valid_ - icon Better ListView
Ultimate ListView control for .NET
+ icon Better ListView
Ultimate ListView control for .NET
- icon Better Thumbnail Browser
Thumbnail loading and browsing control for .NET
+ icon Better Thumbnail Browser
Thumbnail loading and browsing control for .NET
- icon Better SplitButton
Free customizable dropdown button control
+ icon Better SplitButton
Free customizable dropdown button control
- icon Better ListView Express
Free edition with less features
+ icon Better ListView Express
Free edition with less features
@@ -121,7 +121,7 @@ var t = {"antispam":"capek-rulz","purchase_email":"valid purchase email","valid_
- 0018-replacement-with-a-script-web_web_1324658954 + 0018-replacement-with-a-script-web_web_1324658954
@@ -287,19 +287,19 @@ Copyright © 2018 ComponentOwl.com, Dextronet.com. All rights reserved. Read - + diff --git a/src/data/comics/26.html b/src/data/comics/26.html index 1b8c426..c1b101d 100644 --- a/src/data/comics/26.html +++ b/src/data/comics/26.html @@ -24,7 +24,7 @@ - + @@ -49,16 +49,16 @@ var t = {"antispam":"capek-rulz","purchase_email":"valid purchase email","valid_ - icon Better ListView
Ultimate ListView control for .NET
+ icon Better ListView
Ultimate ListView control for .NET
- icon Better Thumbnail Browser
Thumbnail loading and browsing control for .NET
+ icon Better Thumbnail Browser
Thumbnail loading and browsing control for .NET
- icon Better SplitButton
Free customizable dropdown button control
+ icon Better SplitButton
Free customizable dropdown button control
- icon Better ListView Express
Free edition with less features
+ icon Better ListView Express
Free edition with less features
@@ -121,7 +121,7 @@ var t = {"antispam":"capek-rulz","purchase_email":"valid purchase email","valid_
- 0019-human-resources-web_web_1325082644 + 0019-human-resources-web_web_1325082644
@@ -287,19 +287,19 @@ Copyright © 2018 ComponentOwl.com, Dextronet.com. All rights reserved. Read - + diff --git a/src/data/comics/27.html b/src/data/comics/27.html index 9657ec6..db6621c 100644 --- a/src/data/comics/27.html +++ b/src/data/comics/27.html @@ -24,7 +24,7 @@ - + @@ -49,16 +49,16 @@ var t = {"antispam":"capek-rulz","purchase_email":"valid purchase email","valid_ - icon Better ListView
Ultimate ListView control for .NET
+ icon Better ListView
Ultimate ListView control for .NET
- icon Better Thumbnail Browser
Thumbnail loading and browsing control for .NET
+ icon Better Thumbnail Browser
Thumbnail loading and browsing control for .NET
- icon Better SplitButton
Free customizable dropdown button control
+ icon Better SplitButton
Free customizable dropdown button control
- icon Better ListView Express
Free edition with less features
+ icon Better ListView Express
Free edition with less features
@@ -121,7 +121,7 @@ var t = {"antispam":"capek-rulz","purchase_email":"valid purchase email","valid_
- 0020-nonstop-dev-team_web_web_1330007563 + 0020-nonstop-dev-team_web_web_1330007563
@@ -287,19 +287,19 @@ Copyright © 2018 ComponentOwl.com, Dextronet.com. All rights reserved. Read - + diff --git a/src/data/comics/28.html b/src/data/comics/28.html index 3472563..67d1d8f 100644 --- a/src/data/comics/28.html +++ b/src/data/comics/28.html @@ -24,7 +24,7 @@ - + @@ -49,16 +49,16 @@ var t = {"antispam":"capek-rulz","purchase_email":"valid purchase email","valid_ - icon Better ListView
Ultimate ListView control for .NET
+ icon Better ListView
Ultimate ListView control for .NET
- icon Better Thumbnail Browser
Thumbnail loading and browsing control for .NET
+ icon Better Thumbnail Browser
Thumbnail loading and browsing control for .NET
- icon Better SplitButton
Free customizable dropdown button control
+ icon Better SplitButton
Free customizable dropdown button control
- icon Better ListView Express
Free edition with less features
+ icon Better ListView Express
Free edition with less features
@@ -121,7 +121,7 @@ var t = {"antispam":"capek-rulz","purchase_email":"valid purchase email","valid_
- 0021-lsd_web_web_1335527057 + 0021-lsd_web_web_1335527057
@@ -287,19 +287,19 @@ Copyright © 2018 ComponentOwl.com, Dextronet.com. All rights reserved. Read - + diff --git a/src/data/comics/29.html b/src/data/comics/29.html index 2d41695..d1f46d6 100644 --- a/src/data/comics/29.html +++ b/src/data/comics/29.html @@ -24,7 +24,7 @@ - + @@ -49,16 +49,16 @@ var t = {"antispam":"capek-rulz","purchase_email":"valid purchase email","valid_ - icon Better ListView
Ultimate ListView control for .NET
+ icon Better ListView
Ultimate ListView control for .NET
- icon Better Thumbnail Browser
Thumbnail loading and browsing control for .NET
+ icon Better Thumbnail Browser
Thumbnail loading and browsing control for .NET
- icon Better SplitButton
Free customizable dropdown button control
+ icon Better SplitButton
Free customizable dropdown button control
- icon Better ListView Express
Free edition with less features
+ icon Better ListView Express
Free edition with less features
@@ -121,7 +121,7 @@ var t = {"antispam":"capek-rulz","purchase_email":"valid purchase email","valid_
- 0022-badge-of-shame-web_web_1336135809 + 0022-badge-of-shame-web_web_1336135809
@@ -287,19 +287,19 @@ Copyright © 2018 ComponentOwl.com, Dextronet.com. All rights reserved. Read - + diff --git a/src/data/comics/3.html b/src/data/comics/3.html index d7b4ac0..df09d47 100644 --- a/src/data/comics/3.html +++ b/src/data/comics/3.html @@ -24,7 +24,7 @@ - + @@ -49,16 +49,16 @@ var t = {"antispam":"capek-rulz","purchase_email":"valid purchase email","valid_ - icon Better ListView
Ultimate ListView control for .NET
+ icon Better ListView
Ultimate ListView control for .NET
- icon Better Thumbnail Browser
Thumbnail loading and browsing control for .NET
+ icon Better Thumbnail Browser
Thumbnail loading and browsing control for .NET
- icon Better SplitButton
Free customizable dropdown button control
+ icon Better SplitButton
Free customizable dropdown button control
- icon Better ListView Express
Free edition with less features
+ icon Better ListView Express
Free edition with less features
@@ -121,7 +121,7 @@ var t = {"antispam":"capek-rulz","purchase_email":"valid purchase email","valid_
- 03-whole-food-honey-out_web_1312377904 + 03-whole-food-honey-out_web_1312377904
@@ -287,19 +287,19 @@ Copyright © 2018 ComponentOwl.com, Dextronet.com. All rights reserved. Read - + diff --git a/src/data/comics/30.html b/src/data/comics/30.html index 06b4531..f1ad9f2 100644 --- a/src/data/comics/30.html +++ b/src/data/comics/30.html @@ -24,7 +24,7 @@ - + @@ -49,16 +49,16 @@ var t = {"antispam":"capek-rulz","purchase_email":"valid purchase email","valid_ - icon Better ListView
Ultimate ListView control for .NET
+ icon Better ListView
Ultimate ListView control for .NET
- icon Better Thumbnail Browser
Thumbnail loading and browsing control for .NET
+ icon Better Thumbnail Browser
Thumbnail loading and browsing control for .NET
- icon Better SplitButton
Free customizable dropdown button control
+ icon Better SplitButton
Free customizable dropdown button control
- icon Better ListView Express
Free edition with less features
+ icon Better ListView Express
Free edition with less features
@@ -121,7 +121,7 @@ var t = {"antispam":"capek-rulz","purchase_email":"valid purchase email","valid_
- 0023-bloody-cartridge-web_web_1336498077 + 0023-bloody-cartridge-web_web_1336498077
@@ -287,19 +287,19 @@ Copyright © 2018 ComponentOwl.com, Dextronet.com. All rights reserved. Read - + diff --git a/src/data/comics/31.html b/src/data/comics/31.html index 48176ea..1c54372 100644 --- a/src/data/comics/31.html +++ b/src/data/comics/31.html @@ -24,7 +24,7 @@ - + @@ -49,16 +49,16 @@ var t = {"antispam":"capek-rulz","purchase_email":"valid purchase email","valid_ - icon Better ListView
Ultimate ListView control for .NET
+ icon Better ListView
Ultimate ListView control for .NET
- icon Better Thumbnail Browser
Thumbnail loading and browsing control for .NET
+ icon Better Thumbnail Browser
Thumbnail loading and browsing control for .NET
- icon Better SplitButton
Free customizable dropdown button control
+ icon Better SplitButton
Free customizable dropdown button control
- icon Better ListView Express
Free edition with less features
+ icon Better ListView Express
Free edition with less features
@@ -121,7 +121,7 @@ var t = {"antispam":"capek-rulz","purchase_email":"valid purchase email","valid_
- 0024-from-the-ground-up-web_web_1336955366 + 0024-from-the-ground-up-web_web_1336955366
@@ -287,19 +287,19 @@ Copyright © 2018 ComponentOwl.com, Dextronet.com. All rights reserved. Read - + diff --git a/src/data/comics/32.html b/src/data/comics/32.html index c766f0a..bb70e29 100644 --- a/src/data/comics/32.html +++ b/src/data/comics/32.html @@ -24,7 +24,7 @@ - + @@ -49,16 +49,16 @@ var t = {"antispam":"capek-rulz","purchase_email":"valid purchase email","valid_ - icon Better ListView
Ultimate ListView control for .NET
+ icon Better ListView
Ultimate ListView control for .NET
- icon Better Thumbnail Browser
Thumbnail loading and browsing control for .NET
+ icon Better Thumbnail Browser
Thumbnail loading and browsing control for .NET
- icon Better SplitButton
Free customizable dropdown button control
+ icon Better SplitButton
Free customizable dropdown button control
- icon Better ListView Express
Free edition with less features
+ icon Better ListView Express
Free edition with less features
@@ -121,7 +121,7 @@ var t = {"antispam":"capek-rulz","purchase_email":"valid purchase email","valid_
- 0025-boxed-office-web_web_1337198604 + 0025-boxed-office-web_web_1337198604
@@ -287,19 +287,19 @@ Copyright © 2018 ComponentOwl.com, Dextronet.com. All rights reserved. Read - + diff --git a/src/data/comics/33.html b/src/data/comics/33.html index 4c45a57..3cd72a2 100644 --- a/src/data/comics/33.html +++ b/src/data/comics/33.html @@ -24,7 +24,7 @@ - + @@ -49,16 +49,16 @@ var t = {"antispam":"capek-rulz","purchase_email":"valid purchase email","valid_ - icon Better ListView
Ultimate ListView control for .NET
+ icon Better ListView
Ultimate ListView control for .NET
- icon Better Thumbnail Browser
Thumbnail loading and browsing control for .NET
+ icon Better Thumbnail Browser
Thumbnail loading and browsing control for .NET
- icon Better SplitButton
Free customizable dropdown button control
+ icon Better SplitButton
Free customizable dropdown button control
- icon Better ListView Express
Free edition with less features
+ icon Better ListView Express
Free edition with less features
@@ -121,7 +121,7 @@ var t = {"antispam":"capek-rulz","purchase_email":"valid purchase email","valid_
- 0026-pet-scanner-web_web_1337979080 + 0026-pet-scanner-web_web_1337979080
@@ -287,19 +287,19 @@ Copyright © 2018 ComponentOwl.com, Dextronet.com. All rights reserved. Read - + diff --git a/src/data/comics/34.html b/src/data/comics/34.html index 4efe412..7d21c2e 100644 --- a/src/data/comics/34.html +++ b/src/data/comics/34.html @@ -24,7 +24,7 @@ - + @@ -49,16 +49,16 @@ var t = {"antispam":"capek-rulz","purchase_email":"valid purchase email","valid_ - icon Better ListView
Ultimate ListView control for .NET
+ icon Better ListView
Ultimate ListView control for .NET
- icon Better Thumbnail Browser
Thumbnail loading and browsing control for .NET
+ icon Better Thumbnail Browser
Thumbnail loading and browsing control for .NET
- icon Better SplitButton
Free customizable dropdown button control
+ icon Better SplitButton
Free customizable dropdown button control
- icon Better ListView Express
Free edition with less features
+ icon Better ListView Express
Free edition with less features
@@ -121,7 +121,7 @@ var t = {"antispam":"capek-rulz","purchase_email":"valid purchase email","valid_
- 0027-skyscraper-web_web_1338077520 + 0027-skyscraper-web_web_1338077520
@@ -287,19 +287,19 @@ Copyright © 2018 ComponentOwl.com, Dextronet.com. All rights reserved. Read - + diff --git a/src/data/comics/35.html b/src/data/comics/35.html index d8a41ef..5654248 100644 --- a/src/data/comics/35.html +++ b/src/data/comics/35.html @@ -24,7 +24,7 @@ - + @@ -49,16 +49,16 @@ var t = {"antispam":"capek-rulz","purchase_email":"valid purchase email","valid_ - icon Better ListView
Ultimate ListView control for .NET
+ icon Better ListView
Ultimate ListView control for .NET
- icon Better Thumbnail Browser
Thumbnail loading and browsing control for .NET
+ icon Better Thumbnail Browser
Thumbnail loading and browsing control for .NET
- icon Better SplitButton
Free customizable dropdown button control
+ icon Better SplitButton
Free customizable dropdown button control
- icon Better ListView Express
Free edition with less features
+ icon Better ListView Express
Free edition with less features
@@ -121,7 +121,7 @@ var t = {"antispam":"capek-rulz","purchase_email":"valid purchase email","valid_
- 0028-coin-machine-web_web_1338424277 + 0028-coin-machine-web_web_1338424277
@@ -287,19 +287,19 @@ Copyright © 2018 ComponentOwl.com, Dextronet.com. All rights reserved. Read - + diff --git a/src/data/comics/36.html b/src/data/comics/36.html index ec90bf7..569601a 100644 --- a/src/data/comics/36.html +++ b/src/data/comics/36.html @@ -24,7 +24,7 @@ - + @@ -49,16 +49,16 @@ var t = {"antispam":"capek-rulz","purchase_email":"valid purchase email","valid_ - icon Better ListView
Ultimate ListView control for .NET
+ icon Better ListView
Ultimate ListView control for .NET
- icon Better Thumbnail Browser
Thumbnail loading and browsing control for .NET
+ icon Better Thumbnail Browser
Thumbnail loading and browsing control for .NET
- icon Better SplitButton
Free customizable dropdown button control
+ icon Better SplitButton
Free customizable dropdown button control
- icon Better ListView Express
Free edition with less features
+ icon Better ListView Express
Free edition with less features
@@ -121,7 +121,7 @@ var t = {"antispam":"capek-rulz","purchase_email":"valid purchase email","valid_
- 0029-amphetamine-coffee-web_web_1338592639 + 0029-amphetamine-coffee-web_web_1338592639
@@ -287,19 +287,19 @@ Copyright © 2018 ComponentOwl.com, Dextronet.com. All rights reserved. Read - + diff --git a/src/data/comics/37.html b/src/data/comics/37.html index adbfc8b..6a1f62c 100644 --- a/src/data/comics/37.html +++ b/src/data/comics/37.html @@ -24,7 +24,7 @@ - + @@ -49,16 +49,16 @@ var t = {"antispam":"capek-rulz","purchase_email":"valid purchase email","valid_ - icon Better ListView
Ultimate ListView control for .NET
+ icon Better ListView
Ultimate ListView control for .NET
- icon Better Thumbnail Browser
Thumbnail loading and browsing control for .NET
+ icon Better Thumbnail Browser
Thumbnail loading and browsing control for .NET
- icon Better SplitButton
Free customizable dropdown button control
+ icon Better SplitButton
Free customizable dropdown button control
- icon Better ListView Express
Free edition with less features
+ icon Better ListView Express
Free edition with less features
@@ -121,7 +121,7 @@ var t = {"antispam":"capek-rulz","purchase_email":"valid purchase email","valid_
- 0030-office-animals-web_web_1339281061 + 0030-office-animals-web_web_1339281061
@@ -287,19 +287,19 @@ Copyright © 2018 ComponentOwl.com, Dextronet.com. All rights reserved. Read - + diff --git a/src/data/comics/38.html b/src/data/comics/38.html index 216ae59..4f94f4f 100644 --- a/src/data/comics/38.html +++ b/src/data/comics/38.html @@ -24,7 +24,7 @@ - + @@ -49,16 +49,16 @@ var t = {"antispam":"capek-rulz","purchase_email":"valid purchase email","valid_ - icon Better ListView
Ultimate ListView control for .NET
+ icon Better ListView
Ultimate ListView control for .NET
- icon Better Thumbnail Browser
Thumbnail loading and browsing control for .NET
+ icon Better Thumbnail Browser
Thumbnail loading and browsing control for .NET
- icon Better SplitButton
Free customizable dropdown button control
+ icon Better SplitButton
Free customizable dropdown button control
- icon Better ListView Express
Free edition with less features
+ icon Better ListView Express
Free edition with less features
@@ -121,7 +121,7 @@ var t = {"antispam":"capek-rulz","purchase_email":"valid purchase email","valid_
- 0031-project-triangle-web_web_1340062832 + 0031-project-triangle-web_web_1340062832
@@ -287,19 +287,19 @@ Copyright © 2018 ComponentOwl.com, Dextronet.com. All rights reserved. Read - + diff --git a/src/data/comics/39.html b/src/data/comics/39.html index a3eab78..b442003 100644 --- a/src/data/comics/39.html +++ b/src/data/comics/39.html @@ -24,7 +24,7 @@ - + @@ -49,16 +49,16 @@ var t = {"antispam":"capek-rulz","purchase_email":"valid purchase email","valid_ - icon Better ListView
Ultimate ListView control for .NET
+ icon Better ListView
Ultimate ListView control for .NET
- icon Better Thumbnail Browser
Thumbnail loading and browsing control for .NET
+ icon Better Thumbnail Browser
Thumbnail loading and browsing control for .NET
- icon Better SplitButton
Free customizable dropdown button control
+ icon Better SplitButton
Free customizable dropdown button control
- icon Better ListView Express
Free edition with less features
+ icon Better ListView Express
Free edition with less features
@@ -121,7 +121,7 @@ var t = {"antispam":"capek-rulz","purchase_email":"valid purchase email","valid_
- 0032-investment-cloud-web_web_1340911880 + 0032-investment-cloud-web_web_1340911880
@@ -287,19 +287,19 @@ Copyright © 2018 ComponentOwl.com, Dextronet.com. All rights reserved. Read - + diff --git a/src/data/comics/4.html b/src/data/comics/4.html index b270b19..c08f15d 100644 --- a/src/data/comics/4.html +++ b/src/data/comics/4.html @@ -24,7 +24,7 @@ - + @@ -49,16 +49,16 @@ var t = {"antispam":"capek-rulz","purchase_email":"valid purchase email","valid_ - icon Better ListView
Ultimate ListView control for .NET
+ icon Better ListView
Ultimate ListView control for .NET
- icon Better Thumbnail Browser
Thumbnail loading and browsing control for .NET
+ icon Better Thumbnail Browser
Thumbnail loading and browsing control for .NET
- icon Better SplitButton
Free customizable dropdown button control
+ icon Better SplitButton
Free customizable dropdown button control
- icon Better ListView Express
Free edition with less features
+ icon Better ListView Express
Free edition with less features
@@ -121,7 +121,7 @@ var t = {"antispam":"capek-rulz","purchase_email":"valid purchase email","valid_
- 0007-bugs_web_1312448241 + 0007-bugs_web_1312448241
@@ -287,19 +287,19 @@ Copyright © 2018 ComponentOwl.com, Dextronet.com. All rights reserved. Read - + diff --git a/src/data/comics/40.html b/src/data/comics/40.html index bcb5a5a..ded89a5 100644 --- a/src/data/comics/40.html +++ b/src/data/comics/40.html @@ -24,7 +24,7 @@ - + @@ -49,16 +49,16 @@ var t = {"antispam":"capek-rulz","purchase_email":"valid purchase email","valid_ - icon Better ListView
Ultimate ListView control for .NET
+ icon Better ListView
Ultimate ListView control for .NET
- icon Better Thumbnail Browser
Thumbnail loading and browsing control for .NET
+ icon Better Thumbnail Browser
Thumbnail loading and browsing control for .NET
- icon Better SplitButton
Free customizable dropdown button control
+ icon Better SplitButton
Free customizable dropdown button control
- icon Better ListView Express
Free edition with less features
+ icon Better ListView Express
Free edition with less features
@@ -121,7 +121,7 @@ var t = {"antispam":"capek-rulz","purchase_email":"valid purchase email","valid_
- 0033-the-smoker-web_web_1346260357 + 0033-the-smoker-web_web_1346260357
@@ -287,19 +287,19 @@ Copyright © 2018 ComponentOwl.com, Dextronet.com. All rights reserved. Read - + diff --git a/src/data/comics/41.html b/src/data/comics/41.html index 11aecfe..6f95afb 100644 --- a/src/data/comics/41.html +++ b/src/data/comics/41.html @@ -24,7 +24,7 @@ - + @@ -49,16 +49,16 @@ var t = {"antispam":"capek-rulz","purchase_email":"valid purchase email","valid_ - icon Better ListView
Ultimate ListView control for .NET
+ icon Better ListView
Ultimate ListView control for .NET
- icon Better Thumbnail Browser
Thumbnail loading and browsing control for .NET
+ icon Better Thumbnail Browser
Thumbnail loading and browsing control for .NET
- icon Better SplitButton
Free customizable dropdown button control
+ icon Better SplitButton
Free customizable dropdown button control
- icon Better ListView Express
Free edition with less features
+ icon Better ListView Express
Free edition with less features
@@ -121,7 +121,7 @@ var t = {"antispam":"capek-rulz","purchase_email":"valid purchase email","valid_
- 0034-the-assassin-web_web_1349211995 + 0034-the-assassin-web_web_1349211995
@@ -287,19 +287,19 @@ Copyright © 2018 ComponentOwl.com, Dextronet.com. All rights reserved. Read - + diff --git a/src/data/comics/42.html b/src/data/comics/42.html index 58bd7f4..58f653c 100644 --- a/src/data/comics/42.html +++ b/src/data/comics/42.html @@ -24,7 +24,7 @@ - + @@ -49,16 +49,16 @@ var t = {"antispam":"capek-rulz","purchase_email":"valid purchase email","valid_ - icon Better ListView
Ultimate ListView control for .NET
+ icon Better ListView
Ultimate ListView control for .NET
- icon Better Thumbnail Browser
Thumbnail loading and browsing control for .NET
+ icon Better Thumbnail Browser
Thumbnail loading and browsing control for .NET
- icon Better SplitButton
Free customizable dropdown button control
+ icon Better SplitButton
Free customizable dropdown button control
- icon Better ListView Express
Free edition with less features
+ icon Better ListView Express
Free edition with less features
@@ -121,7 +121,7 @@ var t = {"antispam":"capek-rulz","purchase_email":"valid purchase email","valid_
- 0035-extra-dimension-web_web_1352715455 + 0035-extra-dimension-web_web_1352715455
@@ -287,19 +287,19 @@ Copyright © 2018 ComponentOwl.com, Dextronet.com. All rights reserved. Read - + diff --git a/src/data/comics/43.html b/src/data/comics/43.html index fd2ef0d..81f2ad7 100644 --- a/src/data/comics/43.html +++ b/src/data/comics/43.html @@ -24,7 +24,7 @@ - + @@ -49,16 +49,16 @@ var t = {"antispam":"capek-rulz","purchase_email":"valid purchase email","valid_ - icon Better ListView
Ultimate ListView control for .NET
+ icon Better ListView
Ultimate ListView control for .NET
- icon Better Thumbnail Browser
Thumbnail loading and browsing control for .NET
+ icon Better Thumbnail Browser
Thumbnail loading and browsing control for .NET
- icon Better SplitButton
Free customizable dropdown button control
+ icon Better SplitButton
Free customizable dropdown button control
- icon Better ListView Express
Free edition with less features
+ icon Better ListView Express
Free edition with less features
@@ -121,7 +121,7 @@ var t = {"antispam":"capek-rulz","purchase_email":"valid purchase email","valid_
- 0036-budget-cuts-web_web_1354427969 + 0036-budget-cuts-web_web_1354427969
@@ -287,19 +287,19 @@ Copyright © 2018 ComponentOwl.com, Dextronet.com. All rights reserved. Read - + diff --git a/src/data/comics/5.html b/src/data/comics/5.html index 9ac3d89..1faaabc 100644 --- a/src/data/comics/5.html +++ b/src/data/comics/5.html @@ -24,7 +24,7 @@ - + @@ -49,16 +49,16 @@ var t = {"antispam":"capek-rulz","purchase_email":"valid purchase email","valid_ - icon Better ListView
Ultimate ListView control for .NET
+ icon Better ListView
Ultimate ListView control for .NET
- icon Better Thumbnail Browser
Thumbnail loading and browsing control for .NET
+ icon Better Thumbnail Browser
Thumbnail loading and browsing control for .NET
- icon Better SplitButton
Free customizable dropdown button control
+ icon Better SplitButton
Free customizable dropdown button control
- icon Better ListView Express
Free edition with less features
+ icon Better ListView Express
Free edition with less features
@@ -121,7 +121,7 @@ var t = {"antispam":"capek-rulz","purchase_email":"valid purchase email","valid_
- 0008-food-chain_web_1312543561 + 0008-food-chain_web_1312543561
@@ -287,19 +287,19 @@ Copyright © 2018 ComponentOwl.com, Dextronet.com. All rights reserved. Read - + diff --git a/src/data/comics/6.html b/src/data/comics/6.html index 809db38..6ff8eac 100644 --- a/src/data/comics/6.html +++ b/src/data/comics/6.html @@ -24,7 +24,7 @@ - + @@ -49,16 +49,16 @@ var t = {"antispam":"capek-rulz","purchase_email":"valid purchase email","valid_ - icon Better ListView
Ultimate ListView control for .NET
+ icon Better ListView
Ultimate ListView control for .NET
- icon Better Thumbnail Browser
Thumbnail loading and browsing control for .NET
+ icon Better Thumbnail Browser
Thumbnail loading and browsing control for .NET
- icon Better SplitButton
Free customizable dropdown button control
+ icon Better SplitButton
Free customizable dropdown button control
- icon Better ListView Express
Free edition with less features
+ icon Better ListView Express
Free edition with less features
@@ -121,7 +121,7 @@ var t = {"antispam":"capek-rulz","purchase_email":"valid purchase email","valid_
- 0009-mono_web_1312634072 + 0009-mono_web_1312634072
@@ -287,19 +287,19 @@ Copyright © 2018 ComponentOwl.com, Dextronet.com. All rights reserved. Read - + diff --git a/src/data/comics/7.html b/src/data/comics/7.html index e0cfc63..fca8db2 100644 --- a/src/data/comics/7.html +++ b/src/data/comics/7.html @@ -24,7 +24,7 @@ - + @@ -49,16 +49,16 @@ var t = {"antispam":"capek-rulz","purchase_email":"valid purchase email","valid_ - icon Better ListView
Ultimate ListView control for .NET
+ icon Better ListView
Ultimate ListView control for .NET
- icon Better Thumbnail Browser
Thumbnail loading and browsing control for .NET
+ icon Better Thumbnail Browser
Thumbnail loading and browsing control for .NET
- icon Better SplitButton
Free customizable dropdown button control
+ icon Better SplitButton
Free customizable dropdown button control
- icon Better ListView Express
Free edition with less features
+ icon Better ListView Express
Free edition with less features
@@ -121,7 +121,7 @@ var t = {"antispam":"capek-rulz","purchase_email":"valid purchase email","valid_
- 0011-a-toilet-paper_web_1312711686 + 0011-a-toilet-paper_web_1312711686
@@ -287,19 +287,19 @@ Copyright © 2018 ComponentOwl.com, Dextronet.com. All rights reserved. Read - + diff --git a/src/data/comics/8.html b/src/data/comics/8.html index e68a9c2..9c2cce6 100644 --- a/src/data/comics/8.html +++ b/src/data/comics/8.html @@ -24,7 +24,7 @@ - + @@ -49,16 +49,16 @@ var t = {"antispam":"capek-rulz","purchase_email":"valid purchase email","valid_ - icon Better ListView
Ultimate ListView control for .NET
+ icon Better ListView
Ultimate ListView control for .NET
- icon Better Thumbnail Browser
Thumbnail loading and browsing control for .NET
+ icon Better Thumbnail Browser
Thumbnail loading and browsing control for .NET
- icon Better SplitButton
Free customizable dropdown button control
+ icon Better SplitButton
Free customizable dropdown button control
- icon Better ListView Express
Free edition with less features
+ icon Better ListView Express
Free edition with less features
@@ -121,7 +121,7 @@ var t = {"antispam":"capek-rulz","purchase_email":"valid purchase email","valid_
- 0001-a-diagram-web_web_1312798348 + 0001-a-diagram-web_web_1312798348
@@ -287,19 +287,19 @@ Copyright © 2018 ComponentOwl.com, Dextronet.com. All rights reserved. Read - + diff --git a/src/data/comics/9.html b/src/data/comics/9.html index 8c9580a..4da53d4 100644 --- a/src/data/comics/9.html +++ b/src/data/comics/9.html @@ -24,7 +24,7 @@ - + @@ -49,16 +49,16 @@ var t = {"antispam":"capek-rulz","purchase_email":"valid purchase email","valid_ - icon Better ListView
Ultimate ListView control for .NET
+ icon Better ListView
Ultimate ListView control for .NET
- icon Better Thumbnail Browser
Thumbnail loading and browsing control for .NET
+ icon Better Thumbnail Browser
Thumbnail loading and browsing control for .NET
- icon Better SplitButton
Free customizable dropdown button control
+ icon Better SplitButton
Free customizable dropdown button control
- icon Better ListView Express
Free edition with less features
+ icon Better ListView Express
Free edition with less features
@@ -121,7 +121,7 @@ var t = {"antispam":"capek-rulz","purchase_email":"valid purchase email","valid_
- 0002-owl-dimensionality-web_web_1312882080 + 0002-owl-dimensionality-web_web_1312882080
@@ -287,19 +287,19 @@ Copyright © 2018 ComponentOwl.com, Dextronet.com. All rights reserved. Read - + diff --git a/src/data/download/better-listview.html b/src/data/download/better-listview.html index 33ca3db..40c02c4 100644 --- a/src/data/download/better-listview.html +++ b/src/data/download/better-listview.html @@ -41,16 +41,16 @@ var t = {"antispam":"capek-rulz","purchase_email":"valid purchase email","valid_ - icon Better ListView
Ultimate ListView control for .NET
+ icon Better ListView
Ultimate ListView control for .NET
- icon Better Thumbnail Browser
Thumbnail loading and browsing control for .NET
+ icon Better Thumbnail Browser
Thumbnail loading and browsing control for .NET
- icon Better SplitButton
Free customizable dropdown button control
+ icon Better SplitButton
Free customizable dropdown button control
- icon Better ListView Express
Free edition with less features
+ icon Better ListView Express
Free edition with less features
@@ -248,19 +248,19 @@ Copyright © 2018 ComponentOwl.com, Dextronet.com. All rights reserved. Read - + diff --git a/src/pages/better-listview-express.astro b/src/pages/better-listview-express.astro index fbd372b..13e96cd 100644 --- a/src/pages/better-listview-express.astro +++ b/src/pages/better-listview-express.astro @@ -66,25 +66,25 @@ with their Better ListView has done it. Love its native feel. Groups in Better ListView Express are much more powerful, flexible and easier to use than in the regular listview. Groups are also focusable and support images. -
Focusable Groups With Image Support (Focusable) In Better ListView
+
Focusable Groups With Image Support (Focusable) In Better ListView

Images in column headers, sub-items, groups

You can use images in column headers, sub-items, items, groups. Custom image sizes are supported. Regular listview for .NET included with Visual Studio supports only one image per item, and doesn't support sub-item images. Better ListView removes these limitations and has excellent image support. -
Column Images, Sub-Item Images, Groups Images in Better ListView
+
Column Images, Sub-Item Images, Groups Images in Better ListView

Background image support

Display background image in Better ListView easily using the BackgroundImage property. Many layouts (stretch, tile, none), alignments (top, bottom, left, right, center and combinations) are supported, as well as customizable opacity. -
Background Image
+
Background Image

Checkboxes in all views

You can have checkboxes in LargeIcons view, SmallIcons view, List view, Thumbnails view and of course also in the Details view. -
Checkboxes In LargeIcons View
+
Checkboxes In LargeIcons View

Uses current Windows theme

@@ -102,24 +102,24 @@ Better ListView Express is smooth. Regular listview requires multiple anti-flick Better ListView Express allows you to draw over the client area, items and column headers. Contrary to .NET ListView, owner drawing is fully operational even when the system uses Aero theme. You can draw separately to background and foreground parts of Better ListView Express without worrying about proper drawing order. Owner drawing events provide rich data, including exact item state and areas of every item part. -
List View Owner Drawing Background Gradient
+
List View Owner Drawing Background Gradient

Label-edit for sub-items

Take advantage of the inbuilt label editing support, which includes not just textbox edit, but also combobox edit and date picker edit. -
Sub-Item Label Edit With Inbult Combobox Editor in Better ListView
+
Sub-Item Label Edit With Inbult Combobox Editor in Better ListView

Embedded controls for custom label edit

Not only you can use the inbuilt label-editing controls, you can also create your own controls to edit items and sub-items. -
Custom Label Edit for Sub-Items With Embedded Control
+
Custom Label Edit for Sub-Items With Embedded Control

Advanced hit-test with detailed information

The hit test in Better ListView returns very detailed information. It tells you not only the location (Client Area, Sub-Item, Sub-Item Text, Sub-Item Image, Checkbox, Column Header Image, and many more), but it also tells you the state of the item, and part of the item (left or right). -
Advanced Hit-Test With Detailed Information
+
Advanced Hit-Test With Detailed Information

Inbuilt sorting

diff --git a/src/pages/better-listview.astro b/src/pages/better-listview.astro index 1a80d6d..6fec8e8 100644 --- a/src/pages/better-listview.astro +++ b/src/pages/better-listview.astro @@ -49,7 +49,7 @@ const rawContent = `
  • Tested in the real world by thousands of users
  • -
    Better ListView control
    +
    Better ListView control

    Extra features summary

    @@ -87,7 +87,7 @@ Simply put, Better ListView is smooth. Regular listview requires multiple anti-f You can use images in column headers. Custom image sizes are supported. -
    Column Header Images
    +
    Column Header Images

    Sub-item images

    @@ -105,7 +105,7 @@ You can use any image size in the list view. Better ListView can also automatica Highly customizable drag-drop for both internal and external drag-drop. You can use drop highlight or insertion mark drag drop modes. -
    List View Item Reordering Mark Preview
    +
    List View Item Reordering Mark Preview

    List view item reordering

    @@ -115,7 +115,7 @@ Better ListView has inbuilt item reordering and item drag & drop inserting a Better ListView has inbuilt easy drag & drop column header reordering that is much easier to use than in the regular list view. Insertion mark is shown, auto-scrolling is supported. -
    Column Header Reordering With Insertion Mark
    +
    Column Header Reordering With Insertion Mark

    Auto-scroll for column header reordering and item reordering

    @@ -125,7 +125,7 @@ Better ListView has inbuilt auto-scrolling for column header and item reordering Better ListView can display column headers in all views - Details, SmallIcons, LargeIcons, List, Tile, Thumbnails. This allows users to sort items in all views. Additionally, you can also hide the column headers even in the details view. -
    Column Headers in LargeIcons View
    +
    Column Headers in LargeIcons View

    Thumbnails view mode

    @@ -136,13 +136,13 @@ All images in Better ListView can have border or shadow specified. You can also Image shadows like in Windows 7 theme are supported. Windows Explorer uses very similar shadows for image thumbnails. -
    ListView Image Shadows and Image Borders
    +
    ListView Image Shadows and Image Borders

    Multi-column sorting

    You can sort by multiple columns in Better ListView. Simply shift+click a secondary (or third, etc) column to add it to the current sort. Zero code needed. Additionally, the background of the primary (first) sort column can be highlighted. -
    Multi Column Sort in List View
    +
    Multi Column Sort in List View

    Inbuilt sorting and natural sorting

    @@ -156,24 +156,24 @@ Many events have richer event data that allow you to do extra operations or tell You can have checkboxes in LargeIcons view, SmallIcons view, List view, Thumbnails view and of course also in the Details view. -
    Checkboxes In LargeIcons View
    +
    Checkboxes In LargeIcons View

    Three state checkboxes

    Three state checkboxes are supported in Better ListView: -
    Three-State Checkboxes in List View
    +
    Three-State Checkboxes in List View

    Hide or show checkboxes of specific ListView Items

    You can hide checkbox for any ListViewItem. You can also show checkboxes only for specified items. All list items in Better ListView have "AllowShowCheckBox" property. -
    Show or hide checkboxes for specific listview items
    +
    Show or hide checkboxes for specific listview items

    Powerful list view tooltips

    You can display tooltips for nearly any part of Better ListView - tooltips for items, sub-items, checkboxes, item images, sub-item images, column headers, column header images, column header borders, and even for custom areas (regions). Owner-drawn tooltips are supported. -
    List View Regional Tooltips and Owner Drawn Tooltips
    +
    List View Regional Tooltips and Owner Drawn Tooltips

    Uses current Windows theme

    @@ -187,30 +187,30 @@ Every part of Better ListView (items, sub-items, column headers) can be both bin Better ListView allows you to draw over the client area, items and column headers. Contrary to .NET ListView, owner drawing is fully operational even when the system uses Aero theme. You can draw separately to background and foreground parts of Better ListView without worrying about proper drawing order. Owner drawing events provide rich data, including exact item state and areas of every item part. -
    List View Owner Drawing Background Gradient
    +
    List View Owner Drawing Background Gradient

    Multi-line items

    Better ListView supports multi-line items. Items with very long text can be displayed on multiple lines. Highly customizable and powerful: Focused items can have custom number of lines; hard line breaks supported as well. Foreground overlay "watermark" images are easily achievable using owner-drawing. -
    Multi-line items
    +
    Multi-line items

    Background image support

    Display background image in Better ListView easily using the BackgroundImage property. Many layouts (stretch, tile, none), alignments (top, bottom, left, right, center and combinations) are supported, as well as customizable opacity. -
    ListView Background Image
    +
    ListView Background Image

    Context menu for column headers, list items, and empty area

    Better ListView supports 3 types of context menus: Column header context menu, list view items context menu, and empty area context menu (when right-clicking white space). -
    Column Header Context Menu in List View
    +
    Column Header Context Menu in List View

    Advanced hit-test with detailed information

    The hit test in Better ListView returns very detailed information. It tells you not only the location (Client Area, Sub-Item, Sub-Item Text, Sub-Item Image, Checkbox, Column Header Image, and many more), but it also tells you the state of the item, and part of the item (left or right). -
    Advanced Hit-Test With Detailed Information
    +
    Advanced Hit-Test With Detailed Information

    Customizable search-by-typing

    @@ -219,12 +219,12 @@ Better ListView has excellent customization functionality for find-as-you-type i

    Display text when the list view is empty

    You can display a gray text centered in the list view if it's empty to hint or educate users. This will make your software more user friendly. -
    Show Text When List View is Empty
    +
    Show Text When List View is Empty

    Embed controls for item editing

    Inbuilt in-line editing support includes label edit, combobox edit, date picker edit. You can also embed any custom control for in-line editing. Sub-item editing is supported. Highly customizable. -
    Custom Embedded Control in List View for Editing
    +
    Custom Embedded Control in List View for Editing

    ListView item text formatting

    @@ -233,7 +233,7 @@ Supports both text trimming and auto-ellipsis for text that's too long. You can

    Focusable ListView sub-items and groups

    Focus sub-items or groups in Better ListView easily with keyboard. Just use the arrow keys. (This is impossible with the regular .NET ListView) -
    Focusable sub-items in Better ListView
    +
    Focusable sub-items in Better ListView

    Automatic list view layout

    @@ -243,7 +243,7 @@ Better ListView can auto-size item images, item text, column header images, colu You can set custom sizes for item text area and item images. You can also set custom size for column header text area and column header images. (Text area size is different from font size, text area size basically defines the size of the list view item.) This enables you to make tiny/huge column headers or list view items. -
    Custom Item Size in List View
    +
    Custom Item Size in List View
    It's an odd thing when you're inspired by a form component, but Component Owl @@ -293,7 +293,7 @@ In addition to creating a new List View control to incorporate broader flexib
    -

    Better ListView

    +

    Better ListView

    -

    Thumbnails

    +

    Thumbnails

    -

    Multi-line Items

    +

    Multi-line Items

    -

    Item Hierarchy

    +

    Item Hierarchy

    diff --git a/src/pages/better-splitbutton.astro b/src/pages/better-splitbutton.astro index d417a58..bc018fd 100644 --- a/src/pages/better-splitbutton.astro +++ b/src/pages/better-splitbutton.astro @@ -35,7 +35,7 @@ const rawContent = `
  • Free for non-commercial use, cheap license for commercial use with included source code.
  • -

    +

    Features

      @@ -116,7 +116,7 @@ const rawContent = `
      -

      Better SplitButton (Dropdown button) for .NET overview

      +

      Better SplitButton (Dropdown button) for .NET overview