2009-04-01 21 views
1

У меня есть PropertyGrid в моем приложении, которое используется для редактирования произвольных объектов. Мне нужно иметь возможность запускать произвольную подпрограмму в другом потоке, который также смотрит на эти объекты (функция поиска, если вам интересно). Очевидная проблема заключается в том, что пользователь может редактировать один из этих объектов, в то время как моя поисковая строка читает его, что было бы предпочтительнее избегать (хотя это, вероятно, не приведет к чему-либо критическому, поскольку моя строка поиска просто читает, не писать)..Net PropertyGrid Thread-security

Вызов lock(obj) достаточно легко из моей поисковой темы, но после просмотра документации и краткого обезжиренного с помощью кода PropertyDescriptorGridEntry в отражателе, я не могу найти аналогичное место, чтобы использовать System.Threading.Monitor.Enter()/Exit() вызов на объекте в вопросе о PropertyGrid. Я надеялся, что будут события BeginEdit и EndEdit, которые сделают это достаточно простым, но я не могу найти ничего подобного. Я бы предпочел не блокировать весь объект, пока он отображается в PropertyGrid, поскольку это, очевидно, блокирует мой поток поиска, пока не будет выбран другой объект.

Я немного новичок в модели Threading для Windows Forms, поэтому я надеюсь, что есть некоторые очевидные ответы, которые я просто забыл. Любая помощь?

Edit: Синхронно клонировать мои объекты перед запуском поиска асинхронно, вероятно, будет достаточно неэффективным, что я мог бы также запустить сам поиск синхронно - точка запуска асинхронно, конечно, чтобы позволить своим пользователям продолжать работать некоторое время выполняется поиск. Поиск должен хорошо масштабироваться, поскольку набор данных, который я собираюсь пройти, в конечном итоге окажется сколь угодно большим, что делает синхронное клонирование похожим на то, что это вызовет проблему удобства использования, которую я пытаюсь избежать.

ответ

0

Я думаю, вам придется сделать для этого немало работы.

Во-первых, вам нужно будет создать реализацию ICustomTypeDescriptor, которая будет основывать свою реализацию на любом TypeDescriptor, который вы обычно получите для этого типа.

Затем в реализациях методов, которые раскрывают дескрипторы элементов, которые вы хотите заблокировать, вы должны предоставить подклассы, которые вытекают из этих дескрипторов, и переопределять соответствующие методы для обертывания блокировки.

Итак, для свойства, вы должны реализовать GetProperties, чтобы возвращать ваши подклассы PropertyDescriptor. Эти подклассы будут переопределять методы GetValue и SetValue (и другие) и использовать блокировку при доступе к этим переменным.

Следует упомянуть, что блокирование, подобное этому в потоке пользовательского интерфейса, вероятно, является плохой идеей, поскольку вы не хотите произвольно блокировать операции над этим потоком. Возможно, было бы лучше создать клон объекта, а затем создать метод, который будет обновлять хранилище объектов, когда вы закончите.

+0

На самом деле, в случае с PropertyGrid вы можете сделать это проще, подклассифицируя PropertyTab и переопределяя GetProperties. Все еще ** много ** работы, но на самом деле вам не нужно проталкивать через ICustomTypeDescriptor (и TypeDescriptionProvider) –

+0

@Marc Gravell: You все еще нужно создавать подклассы, которые происходят из PropertyDescriptor, и делать то, что я указал с переопределением GetValue и SetValue. Это примерно такое же количество работы. Однако для реализации ICustomTypeDescriptor существует более общее использование, поэтому я бы пошел с этим. – casperOne

+0

Но с ICustomTypeDescriptor вам нужно контролировать отображаемый тип, а не только сетку. –

0

Это действительно не будет потокобезопасным. Вы могли бы маршировать биты кода поиска в поток пользовательского интерфейса, но это замедлит работу и, возможно, победит точку потока ...

Как быстро должен быть поиск? Можете ли вы работать против клона? и т. д.

+0

Я знал, что я не пошел в подробность;) –

+0

Edited вопрос - клонирование синхронно, скорее всего, поражение цели резьбы :( –

0

Можете ли вы клонировать данные перед их отображением и получить свою поисковую цепочку для работы с клоном? Если вы хотите, чтобы поисковая цепочка «увидела» изменения, вы можете ответить на события на PropertyGrid и, возможно, сделать контролируемыми изменениями клонов как-то. (Возможно, проще просто использовать «устаревшие» данные.)

Я знаю, что клонирующие данные звучат ужасно неэффективно, но нарезка, конечно, проще, когда каждый поток работает на полностью независимых данных (или только все потоки только читают).

+0

Edited вопрос - клонирование синхронно, скорее всего, поражение цели резьбы :( –

0

Я мог ошибаться, но мне кажется, что вы исходите из неправильного конца.

Существует два различных вопроса, которые необходимо решить.

Во-первых, убедитесь, что PropertyGrid доступен только в потоке пользовательского интерфейса. Если какой-либо из его методов (включая свойства getter/seters) будет доступен из других потоков, вы будете испытывать боль таинственными способами. Исключение составляют, конечно, InvokeRequired() и Invoke.

Во-вторых, убедитесь, что ваша поисковая строка может работать должным образом.

Чтобы решить первую проблему, либо убедитесь, что ваши объекты никогда не изменяются кроме в потоке пользовательского интерфейса, или сделать все ваши события вызывает нить в курсе, так что ваши объекты событие (например, PropertyChanged) является только когда-либо срабатывает в потоке пользовательского интерфейса.

Вторая проблема проще - до тех пор, пока ваша поисковая строка только ЧИТАЕТ от ваших основных объектов, все должно работать нормально. Да, ваша поисковая строка может непреднамеренно увидеть некоторые частично обновленные данные, но это действительно проблема?

Несколько заключительных мыслей ...

  • Не осуществлять поиск по перебирать самой PropertyGrid; получить список объектов впереди (им не нужно быть клонами) и проделать это вместо этого.

  • Рассматривали ли вы использование Idle Processing для поиска? Объект Application запускает событие каждый раз, когда приложение заканчивает обработку сообщений - вы можете подключиться к нему и выполнять 1 шаг поиска при каждом запуске события. Вид бедной мантии, но без каких-либо головных болей в мьютексе/замке/семафоне. Я использовал это для очень хорошего эффекта в прошлом.

Update: Если я правильно помню, PropertyGrid уважает интерфейс IEditableObject, называя BeginEdit как только вы начинаете изменять строку, и EndEdit при переходе на другую строку. Вы можете использовать это, чтобы предотвратить, что ваша поисковая цепочка увидит неполные изменения.

Update 2: После вверх, я обнаружил, что вы уже знали - что PropertyGrid не уважать интерфейс IEditableObject.

У меня есть другое предложение - хотя это может быть больше работы, чем вы хотите инвестировать.

В то время, когда пространство имен System.Transactions было внедрено в .NET 2.0, я увидел статью об использовании внешней транзакции для обеспечения изоляции потоков для объектов. Идея заключается в том, что ваши свойства объекта имеют двойное хранилище.Сначала у вас есть фиксированное значение, видимое для всех потоков, и у вас есть локальная переменная потока, используемая для хранения незафиксированных значений по каждому потоку. Когда свойство изменено, объект завершается любой внешней транзакцией, сохраняя новое значение в потоке локально. Когда транзакция совершает или откатывается, значение для потока сохраняется или отбрасывается.

К сожалению, я не могу найти оригинальную статью, хотя кажется, что CSLA предоставляет эту поддержку. Надеюсь это поможет.

+0

«Ваша поисковая строка может непреднамеренно увидеть некоторые частично обновленные данные» - это проблема * только *, с которой я связан, и предпочел бы избегать; ничто другое не является проблемой (я знаю, что я делаю ... в основном). Обработка бездействия могла бы работать, если бы мое приложение не было столь тяжелым. –

+0

Я не верю, что вы правильно отзываетесь - как ваши ссылки, так и моя память указывают, что IEditableObject с BeginEdit и EndEdit используется DataGridView, а не PropertyGrid. –

Смежные вопросы