В IuiToolkit встала необходимость заиметь такое свойство, которому уже в дизайнере можно было бы присвоить следующие значения:
- Экземпляра любого класса соответствующего типа (при наличии конструктора без параметров, конечно же)
Возвращаемого значения любого статического метода (также без параметров)
.. статического свойства
.. статического поля
+ Создавался еще custom CollectionEditor для хранения задач.
В процессе разработки всего этого пришлось познакомиться со следующими прелестями дизайнера:
Если из UITypeEditor'а возвращается ссылка на тот же объект, он не сериализуется
Это проявилось в дизайнере коллекции, т.к. коллекция, передаваемая в редактор, только меняла свое содержимое, объект оставался тот же самый и сравнив их по ссылкам, дизайнер не сериализовал "не изменившуюся" коллекцию.Для решения нужно использовать методы ITypeDescriptorContext.OnComponentChanging и ITypeDescriptorContext.OnComponentChanged, следующим образом:
public class TasksEditor : UITypeEditor |
В статьях MSDN, посвященных UITypeEditor упоминаний этого не нашел и попался. Благо, гугл затем направил на верный путь.
Асинхронные вызовы в UITypeEditor'е
В диалоге редактора асинхронно перебирались Reflection'ом сборки. И выполнялось это, естественно, асинхронно.
Поначало с помощью BackgroundWorker'а, который ввел себя несовсем предсказуемо. В какой-то момент времени по завершении DoWork диалог просто закрывался без каких либо пояснений. К сожалению отладка дизайнера в Express-студии ограничена, а MessageBox'ами выяснилось только то, что при этом не вызывается ни OnRunWorkerCompleted, ни даже FormClosing.
ОК, с BackgroundWorker'ом нам не по пути, реализовал асинхронность вручную с помощью делегатов и BeginInvoke. Результат из метода возвращался с помощью IAsyncResult. Здесь лучше не стало, в тот момент, когда метод завершал работу, студия просто валилась с предложением др.Ватсона отправить отчет.
С чувством, что меня здесь не ждали, реализовал следующее: выбросил IAsyncResult и организовал передачу в асинхронный метод делегата EndProcessingCallback, который вызывался в конце метода. И... заработало!)
Сложности отладки designtime-компонентов
Если единожды воспользоваться в дизайнере таким компонентом и изменить его состояние, то при следующем билде компонента, и открывании дизайнера того компонента, в котором используется наш designtime-компонент, студия может заявить, что не может привести тип X к типу X. Почему?
Как выяснилось, designtime-компонент закешировался в (LocalApplicationData)\Microsoft\(Visual Studio | VCSExpress | VBExpress)\8.0\ProjectAssemblies и будет там оставаться неизменным по перезапуска студии. И никакие Cleanup'ы и Rebuild'ы здесь не помогут.
MSB4018: The "GenerateResource" task failed unexpectedly.
Также, если сильно увлечься designtime'ом можно словить и такую ошибку. Это баг в MSBuild, лечится только переустановкой .NET Framweork'а. Связана эта ошибка, как понятно, с ресурсами, у меня таким образом MSBuild не нашел понимания в находящимися там System.Reflection.Runtime[Constructor|Field|Method|Property]Info, сериализующимися наследниками System.Reflection.[Constructor|Field|Method|Property]Info, запиханными туда дизайнером студии.
И не нужно спешить добавлять в файл проекта ноду GenerateResourceNeverLockTypeAssemblies, как предложено на форуме MSDN — я добавил было — не помогло, переставил фреймворк — та же фигня. И лишь после удаления этого ключа, MSBuild дал добро.