none
Автообновление PropertyGrid RRS feed

  • Вопрос

  • Необходимо реализовать автообновление PropertyGrid, т.е. если значение свойства меняется не в PropertyGrid, а извне, то чтобы PropertyGrid обновлялось без явного Refresh. Добавление атрибутов RefreshPropertiesAttribute(RefreshProperties.All) к свойствам не помогает.
     Встретил только такую подсказку:
     "на самом деле, там несколько тоньше: нужно установить PropertyGrid.Site такой, чтобы он отвечал на GetService(typeof(IDesignerHost))
     только в таком случае PropertyGrid начинает запрашивать другие сервисы, в том числе IComponentChangeService.
     Вообще говоря, похоже на некоторую нестыковку у микрософта — с одной стороны, PropertyDescriptor поддерживает в принципе оповещения об изменении значения, с другой — PropertyGrid на него забивает и использует сервис. Похоже, в ходе разработки поняли, что нужны транзакции для нормальной скорости работы всех связки — и сделали IComponentChangeService."

     Но как это реализовать не очень понятно.
     Всем заранее спасибо за любую помощь)

    18 апреля 2011 г. 14:50

Ответы

  • В .NET нет встроенного механизма для уведомления об изменении свойств. Только разработчик класса знает, что происходит при вызове сеттера. И полностью на его совести уведомлять кого-то о том, что в результате вызова сеттера поменяется результат следующего вызова геттера (т.к. "свойство поменяется").
    My blog | My pet project
    • Помечено в качестве ответа Abolmasov Dmitry 25 апреля 2011 г. 10:34
    20 апреля 2011 г. 12:15
  • В .NET нет механизма для мониторинга прохода по get и set для любого класса. Точнее, есть, но это внешний по отношению к коду подход - отладка, использование profiling api и прочее. Проще проверять значения свойств по таймеру, раз в N секунд, и рефрешить если они поменялись.
    My blog | My pet project
    • Помечено в качестве ответа Abolmasov Dmitry 25 апреля 2011 г. 10:34
    20 апреля 2011 г. 14:26

Все ответы

  • Неужто никому никогда не нужно было реализовать автообновление значений свойств в PropertyGrid?!

    Если не понятны детали, показываю на пальцах. Например, у объекта есть свойство Location типа PointF, к нему добавлен атрибут RefreshProperties(RefreshProperties.All). Отображаю этот объект (и соответственно данное свойство) в PropertyGrid. Меняю значение Location не из PropertyGrid (например, перемещаю объект мышкой), нужно чтобы при этом менялось значение в PropertyGrid, т.е. происходило автообновление PropertyGrid. Т.к. пока что PropertyGrid обновляется только с помощью Refresh.
    Есть всем известный вариант с реализацией каждым объектом интерфейса INotifyChanged, и при измененении значения того или иного свойства в объекте вызывать событие PropertyChanged, и там уже делать PropertyGrid.Refresh(). Вариант работающий, но в частности не для случаев, когда есть внешняя сборка, и нужно извлечь из нее типы, создать объекты и отображать их свойства в реальном времени.

    19 апреля 2011 г. 18:41
  • Можно еще попробовать перезадавать SelectedObject. Если не поможет, то тогда скорее всего один путь - самостоятельно вызывать Refresh.


    Для связи [mail]
    20 апреля 2011 г. 5:24
  • Можно еще попробовать перезадавать SelectedObject. Если не поможет, то тогда скорее всего один путь - самостоятельно вызывать Refresh.


    Ну, ясное дело, что можно) Но это даже хуже, чем ручной Refresh. И тема в заголовке начинается со слова "Автообновление") И решение же, вроде, есть, связанное с изменением Site у PropertyGrid, но как это делается, как видно, знают единицы.
    Причем я не писал, но думал, что это всем известно: если после изменения выделить мышкой соответствующую строчку в PropertyGrid, то значение изменится, значит, PropertyGrid настроен на прослушивание изменений своих свойств, но не в реальном режиме, и весь вопрос в том, как режим работы в реальном времени включить.
    20 апреля 2011 г. 11:38
  • В .NET нет встроенного механизма для уведомления об изменении свойств. Только разработчик класса знает, что происходит при вызове сеттера. И полностью на его совести уведомлять кого-то о том, что в результате вызова сеттера поменяется результат следующего вызова геттера (т.к. "свойство поменяется").
    My blog | My pet project
    • Помечено в качестве ответа Abolmasov Dmitry 25 апреля 2011 г. 10:34
    20 апреля 2011 г. 12:15
  • В .NET нет встроенного механизма для уведомления об изменении свойств. Только разработчик класса знает, что происходит при вызове сеттера. И полностью на его совести уведомлять кого-то о том, что в результате вызова сеттера поменяется результат следующего вызова геттера (т.к. "свойство поменяется").
    My blog | My pet project


    И все-таки, похоже, что некоторым удавалось это обойти с помощью установки свойства Site так, чтобы PropertyGrid начал прослушивать сервис IComponentChangeService и др.

    Вот реализация Site в PropertyGrid:

    public override ISite Site
    {
      get
      {
        return base.Site;
      }
      set
      {
        base.SuspendAllLayout(this);
        base.Site = value;
        this.gridView.ServiceProvider = value;
        if (value == null)
        {
          this.ActiveDesigner = null;
        }
        else
        {
          this.ActiveDesigner = (IDesignerHost) value.GetService(typeof(IDesignerHost));
        }
        base.ResumeAllLayout(this, true);
      }
    }

    Видно, что нужно установить Site в нужный ISite, вот только как получить этот объект ISite или как реализовать наследник от ISite, непонятно.

    Ну, и тогда вообще непонятно в чем смысл атрибута RefreshPropertiesAttribute. Может кто-то объяснить?

    20 апреля 2011 г. 12:58
  • Не знаю кому и что удавалось, но в задача "есть внешняя сборка, и нужно извлечь из нее типы, создать объекты и отображать их свойства в реальном времени." (из кросспоста c gotdotnet) не решаема в общем случае. Потому что отследить изменения свойства класса невозможно. Потому что нет общего определения "изменения свойства". Например, как должен вести себя грид на объекте такого вот класса?

     

    sealed class SomeClass
    {
     private Random rand = new Random();
     public int MyProperty
     {
      get   
      {
       return rand.Next();
      }
      set
      {
       rand = new Random();
      }
     }
    }
    

     


    My blog | My pet project
    20 апреля 2011 г. 13:10
  • Например, как должен вести себя грид на объекте такого вот класса?

    В принципе все так, хотя есть вариант считать изменением свойства уже сам проход через set, и обновлять его через get. Но это детали.

    Все-таки, хотелось бы услышать ответы на такие вопросы:

    1) как назначить PropertyGrid.Site;

    2) в чем смысл атрибута RefreshPropertiesAttribute.

    20 апреля 2011 г. 13:29
  • RefreshPropertiesAttribute с All заставляет грид перезапросить у контрола не только измененное свойство, но и все остальные. Вот пример из гугла:

    http://www.bluevisionsoftware.com/WebSite/TipsAndTricksDetails.aspx?Name=RefreshPropertiesAttribute


    My blog | My pet project
    20 апреля 2011 г. 13:58
  • RefreshPropertiesAttribute с All заставляет грид перезапросить у контрола не только измененное свойство, но и все остальные. Вот пример из гугла:

    http://www.bluevisionsoftware.com/WebSite/TipsAndTricksDetails.aspx?Name=RefreshPropertiesAttribute


    My blog | My pet project


    У него еще и значение Repaint есть, только для собственного обновления. Это и так понятно. Вопрос в том, КОГДА он "заставляет грид перезапросить у контрола не только измененное свойство", т.е. влияет ли он на автообновление PropertyGrid? Потому что у меня так получается, что нет.


    20 апреля 2011 г. 14:11
  • В тот момент, когда он узнает об изменении свойства, ес-но. В примере по ссылке - когда свойство изменено из самого PropertyGrid.

    Т.е. никак не влияет на автообновление. Которого нет.


    My blog | My pet project
    20 апреля 2011 г. 14:20
  • Т.е. никак не влияет на автообновление. Которого нет.

    Да, понятно, что дело туго) В любом случае спасибо за ответы.

    20 апреля 2011 г. 14:26
  • В .NET нет механизма для мониторинга прохода по get и set для любого класса. Точнее, есть, но это внешний по отношению к коду подход - отладка, использование profiling api и прочее. Проще проверять значения свойств по таймеру, раз в N секунд, и рефрешить если они поменялись.
    My blog | My pet project
    • Помечено в качестве ответа Abolmasov Dmitry 25 апреля 2011 г. 10:34
    20 апреля 2011 г. 14:26
  • Да, мезанизмов для ручного обновления хватает. Просто подумалось, что имеются встроенные механизмы для подобных действий на основе тех же сервисов.

    20 апреля 2011 г. 14:30
  • В любом случае есть варианты. Например, генерить на лету обертки поверх классов из сторонней dll, и подсовывать их в property grid.
    My blog | My pet project
    20 апреля 2011 г. 15:28
  • Да, есть такой вариант. В 4-м фреймворке есть класс DynamicObject. А вот какие пути создания таких оберток на лету есть в младших фреймворках?

    Или вы имеете в виду такие варианты (где все значения свойств объекта устанавливаются методом SetValue), вроде этого:

      class DynamicObject
      {
        public object Object
        {
          get;
          set;
        }
    
        public event EventHandler ValueChanged;
    
        public void SetValue(string propertyName, object value)
        {
          this.Object.GetType().GetProperty(propertyName).SetValue(this.Object, value, null);
          if (this.ValueChanged != null)
            this.ValueChanged(this, EventArgs.Empty);
        } 
      }
    
    20 апреля 2011 г. 17:56
  • В старых фреймворках - кодогенерация, через Reflection.Emit. Или CodeDom. Есть готовые вещи, типа http://www.castleproject.org/dynamicproxy/index.html, которые можно дописать в нужную сторону.
    My blog | My pet project
    20 апреля 2011 г. 20:02