none
Можно ли из свойства вызывать метод? RRS feed

  • Вопрос

  • Добрый день.

    Скажите, пожалуйста, можно ли вызывать метод из сеттера свойства не посредственно перед вызовом OnPropertyChanged для этого свойства? Например:

    private Int32 myVar;
    public Int32 MyProp
    {
       get{return myVar;}
       set
       {
           if(value == myVar)
                return;
           myVar = value;
           SomeAction();
           OnPropertyChanged("MyProp");
       }
    }
    
    void SomeAction()
    {
        // Некоторые вычисления.
    }

    И вообще - не вредно ли нагружать свойство вычислительными операциями?

    • Перемещено YatajgaEditor 22 августа 2013 г. 8:40
    24 июля 2013 г. 11:00

Ответы

  • Обещанный пример.

    Как я уже сказал выше, свойство должно быть быстром. Но что делать, если
    изменение свойства это медленная операция?
    Давайте рассмотрим вот такой класс:

    class Person : INotifyPropertyChanged
    {
        private string _lastName = null;
    
    
        public string LastName
        {
            get
            {
                return _lastName;
            }
            set
            {
                if (value != _lastName)
                 {
                    _lastName = value;
                    SlowOperation(_lastName);
                    OnProeprtyChanged("LastName");
                }
            }
        }
     
        void SlowOperation(string p_value)
        {
            // Медленная операция с p_value
            Thread.Sleep(2000);
        }
     
        public event PropertyChangedEventHandler PropertyChanged;
     
        protected void OnProeprtyChanged(string p_propertyName)
        {
            var handler = PropertyChanged;
            if (handler != null)
            {
                handler(this, new PropertyChangedEventArgs(p_propertyName));
            }
        }
    }
    

    Понятно, что при присвоении приложение будет зависать. Самый простой способ побороть зависание сделать вызов вот так:

    Task.Factory.StartNew(() => SlowOperation(_lastName));

    Если присвоения будут идти с большим интервалом, чем время работы медленного метода, но если это будет не так, то начнуться проблемы. Т.е. у нас еще не отработал предыдущий медленный метод, а у нас уже запускается онже еще раз. Метод начнет работаь с неправильным состоянием объекта.

    Избежать этого можно применив, например, lock:

    object locker = new object();
     
    void SlowOperation(string p_value)
    {
        lock(locker)
        {
            // Код метода
        }
    }

    В этом случае методы будут работать в отдельных потоках, но последовательно.

    Более подробно, с демонстрацией проблемы запуска в несколько потоков без блокировок, можно посмотреть здесь.

    • Помечено в качестве ответа TownSparrow 6 сентября 2013 г. 7:00
    5 сентября 2013 г. 17:57
    Отвечающий

Все ответы

  • Добрый день.

    Можно. Если метод "быстрый" то можно. Если метод долгий, то лучше его вызывать в обработчике события.

    • Помечено в качестве ответа TownSparrow 24 июля 2013 г. 12:45
    • Снята пометка об ответе TownSparrow 22 августа 2013 г. 8:27
    24 июля 2013 г. 11:19
    Отвечающий
  • И, кстати, OnPropertyChanged - тоже метод... "быстрый"...
    24 июля 2013 г. 11:38
  • Спасибо большое, Алексей и Кирилл. Понятно.
    • Изменено TownSparrow 24 июля 2013 г. 12:47 исправлено
    24 июля 2013 г. 12:45
  • Добрый день.

    Можно. Если метод "быстрый" то можно. Если метод долгий, то лучше его вызывать в обработчике события.


    Если возможно, то покажите, пожалуйста, на примере. Очень прошу.
    • Изменено TownSparrow 22 августа 2013 г. 8:29
    22 августа 2013 г. 8:28
  • Если, как в вашем коде, вы меняете значение, а потом выполняете некоторые расчеты, которые на значение уже не влияют, то вызывайте сразу событий, а в отдельном потоке запускайте обработку. Если результат обработки может изменить значение, то я бы делал вообще по другому. Так влияют результаты расчетов или нет?
    22 августа 2013 г. 9:24
    Отвечающий
  • если на ваш вопрос ответили, поставьте отметку! ! !

    22 августа 2013 г. 12:53
  • Извините, пожалуйста, за задержку с ответом. Был занят. Ешё раз извините. Нет. На значение свойства результаты рассчётов не влияют. Т.е. вы, Алексей, говорите, что нужно вызывать обработчик событий, а из него отдельный поток? Например, TPL task? Но как определить обработчик события для свойства? В OnPropertyChanged ведь это делать нельзя?

    5 сентября 2013 г. 8:40
  • если на ваш вопрос ответили, поставьте отметку! ! !


    Нет, извините. Я жду ответ. Просто долго не откликался из за того, что был занят. Извините, пожалуйста.
    5 сентября 2013 г. 8:42
  • Давайте я вам вечером примерчик накидаю, сейчас времени нет на нормальный пример...
    5 сентября 2013 г. 9:32
    Отвечающий
  • OK. Заранее благодарю.

    5 сентября 2013 г. 10:13
  • Обещанный пример.

    Как я уже сказал выше, свойство должно быть быстром. Но что делать, если
    изменение свойства это медленная операция?
    Давайте рассмотрим вот такой класс:

    class Person : INotifyPropertyChanged
    {
        private string _lastName = null;
    
    
        public string LastName
        {
            get
            {
                return _lastName;
            }
            set
            {
                if (value != _lastName)
                 {
                    _lastName = value;
                    SlowOperation(_lastName);
                    OnProeprtyChanged("LastName");
                }
            }
        }
     
        void SlowOperation(string p_value)
        {
            // Медленная операция с p_value
            Thread.Sleep(2000);
        }
     
        public event PropertyChangedEventHandler PropertyChanged;
     
        protected void OnProeprtyChanged(string p_propertyName)
        {
            var handler = PropertyChanged;
            if (handler != null)
            {
                handler(this, new PropertyChangedEventArgs(p_propertyName));
            }
        }
    }
    

    Понятно, что при присвоении приложение будет зависать. Самый простой способ побороть зависание сделать вызов вот так:

    Task.Factory.StartNew(() => SlowOperation(_lastName));

    Если присвоения будут идти с большим интервалом, чем время работы медленного метода, но если это будет не так, то начнуться проблемы. Т.е. у нас еще не отработал предыдущий медленный метод, а у нас уже запускается онже еще раз. Метод начнет работаь с неправильным состоянием объекта.

    Избежать этого можно применив, например, lock:

    object locker = new object();
     
    void SlowOperation(string p_value)
    {
        lock(locker)
        {
            // Код метода
        }
    }

    В этом случае методы будут работать в отдельных потоках, но последовательно.

    Более подробно, с демонстрацией проблемы запуска в несколько потоков без блокировок, можно посмотреть здесь.

    • Помечено в качестве ответа TownSparrow 6 сентября 2013 г. 7:00
    5 сентября 2013 г. 17:57
    Отвечающий
  • Спасибо огромное, Алексей. Статью в вашем блоге прочитал, теперь буду смотреть, как использовать полученную информацию у себя в приложении. Но сначала решу имеющиеся у меня проблемы с UI, а после этого уже займусь свойствами. Ещё раз спасибо большое.

    С уважением  Евгений.

    • Помечено в качестве ответа TownSparrow 6 сентября 2013 г. 7:00
    • Снята пометка об ответе TownSparrow 6 сентября 2013 г. 7:00
    • Изменено TownSparrow 6 сентября 2013 г. 7:01
    6 сентября 2013 г. 7:00