Microsoft должна была реализовать что-то быстрое INotifyPropertyChanged
, например, в автоматических свойствах, просто укажите, {get; set; notify;}
я думаю, что это имеет смысл делать. Или есть какие-то осложнения для этого?
Можем ли мы сами реализовать что-то вроде «уведомить» в наших свойствах. Есть ли изящное решение для реализации INotifyPropertyChanged
в вашем классе или единственный способ сделать это - вызвать PropertyChanged
событие в каждом свойстве.
Если нет, то можем ли мы написать что-нибудь, чтобы автоматически сгенерировать кусок кода, чтобы вызвать PropertyChanged
событие?
Ответы:
Без использования что-то вроде postsharp, минимальная версия, которую я использую, использует что-то вроде:
Каждое свойство тогда просто что-то вроде:
который не огромен; его также можно использовать как базовый класс, если хотите.
bool
Возвращение изSetField
говорит вам , если это не было не-оп, в случае , если вы хотите применить другую логику.или даже проще с C # 5:
который можно назвать так:
с помощью которого компилятор добавит
"Name"
автоматически.C # 6.0 облегчает реализацию:
... а теперь с C # 7:
источник
[CallerMemberName]
Начиная с .Net 4.5, наконец-то есть простой способ сделать это.
.Net 4.5 представляет новые атрибуты информации о вызывающем абоненте.
Вероятно, это хорошая идея, чтобы добавить в функцию компаратор.
Больше примеров здесь и здесь
Также см. Информацию о вызывающем абоненте (C # и Visual Basic)
источник
Мне действительно нравится решение Марка, но я думаю, что его можно немного улучшить, чтобы избежать использования «волшебной строки» (которая не поддерживает рефакторинг). Вместо использования имени свойства в качестве строки легко сделать его лямбда-выражением:
Просто добавьте следующие методы к коду Марка, он сделает свое дело:
Кстати, это было вдохновлено
этим сообщением в блогеобновленный URLисточник
Есть также Fody, который имеет надстройку PropertyChanged , которая позволяет вам написать это:
... и во время компиляции вставляет свойство измененных уведомлений.
источник
"Fody/.*?:",LogCustom2,True
выделяет его цветом «Custom 2». Я сделал его ярко-розовым, так что его легко найти. Просто Fody все, это самый лучший способ сделать что-нибудь, что имеет много повторяющихся печатать.Я думаю, что люди должны уделять немного больше внимания производительности; это действительно влияет на пользовательский интерфейс, когда нужно связать много объектов (например, сетку с 10 000+ строками) или если значение объекта часто меняется (приложение для мониторинга в реальном времени).
Я взял различные реализации, найденные здесь и в других местах, и сделал сравнение; проверить это сравнение производительности реализации INotifyPropertyChanged .
Вот взгляд на результат
источник
Я представляю класс Bindable в своем блоге по адресу http://timoch.com/blog/2013/08/annoyed-with-inotifypropertychange/. Bindable использует словарь в качестве пакета свойств. Достаточно просто добавить необходимые перегрузки для подкласса, чтобы управлять его собственным полем поддержки, используя параметры ref.
Код:
Это можно использовать так:
источник
protected T Get<T>(T defaultValue, [CallerMemberName] string name = null)
а также проверитьif (_properties.ContainsKey(name) && Equals(value, Get<T>(default(T), name)))
в Set (чтобы поднять и сохранить, когда первый раз установил значение по умолчанию)На самом деле у меня еще не было возможности попробовать это самостоятельно, но в следующий раз я настраиваю проект с большим требованием для INotifyPropertyChanged. Я намереваюсь написать атрибут Postsharp, который будет внедрять код во время компиляции. Что-то вроде:
Станет:
Я не уверен, сработает ли это на практике, и мне нужно сесть и попробовать, но я не понимаю, почему нет. Мне может понадобиться, чтобы он принимал некоторые параметры для ситуаций, когда нужно запускать более одного OnPropertyChanged (если, например, у меня было свойство FullName в классе выше)
В настоящее время я использую собственный шаблон в Resharper, но даже после этого мне надоели все мои свойства так долго.
Ах, быстрый поиск в Google (который я должен был сделать до того, как написал это) показывает, что по крайней мере один человек сделал что-то подобное здесь раньше . Не совсем то, что я имел в виду, но достаточно близко, чтобы показать, что теория хороша.
источник
Да, лучший способ, безусловно, существует. Вот:
Шаг за шагом, учебник сжался мной, основываясь на этой полезной статье .
NotifierInterceptor
ProxyCreator
-
Поместите привязки в xaml:
Поместите строку кода в файл с выделенным кодом MainWindow.xaml.cs следующим образом:
DataContext = ProxyCreator.MakeINotifyPropertyChanged<MainViewModel>();
Внимание!!! Все ограниченные свойства должны быть украшены виртуальным ключевым словом, потому что они используются прокси-замком для переопределения.
источник
type
,interfaces to apply
,interceptors
.CreateClassProxy<T>
метод. Сильно отличается ... хм, интересно, почему так ограничен с помощью общего метода. :(Очень похожий на AOP подход заключается в том, чтобы внедрить материал INotifyPropertyChanged в уже созданный объект на лету. Вы можете сделать это с чем-то вроде Castle DynamicProxy. Вот статья, которая объясняет технику:
Добавление INotifyPropertyChanged к существующему объекту
источник
Посмотрите здесь: http://dotnet-forum.de/blogs/thearchitect/archive/2012/11/01/die-optimale-implementierung-des-inotifypropertychanged-interfaces.aspx
Он написан на немецком языке, но вы можете скачать ViewModelBase.cs. Все комментарии в CS-файле написаны на английском языке.
С помощью этого ViewModelBase-Class можно реализовать привязываемые свойства, подобные хорошо известным свойствам зависимости:
источник
Основываясь на ответе Томаса, который был адаптирован из ответа Марка, я превратил измененный код свойства отражения в базовый класс:
Использование такое же, как и у ответа Томаса, за исключением того, что вы можете передать дополнительные свойства для уведомления. Это было необходимо для обработки вычисляемых столбцов, которые необходимо обновить в сетке.
У меня есть это вождение коллекции элементов, хранящихся в BindingList, представленных через DataGridView. Это избавило меня от необходимости делать ручные вызовы Refresh () в сетку.
источник
Позвольте мне представить свой собственный подход под названием Yappi . Он принадлежит генераторам производных классов Runtime proxy |, добавляя новые функциональные возможности к существующему объекту или типу, например, к Dynamic Proxy Caste Project.
Это позволяет реализовать INotifyPropertyChanged один раз в базовом классе, а затем объявить производные классы в следующем стиле, все еще поддерживая INotifyPropertyChanged для новых свойств:
Сложность конструкции производного класса или прокси может быть скрыта за следующей строкой:
И вся работа по реализации INotifyPropertyChanged может быть выполнена следующим образом:
Он полностью безопасен для рефакторинга, не использует отражения после создания типа и достаточно быстр.
источник
TDeclaration
параметр типаPropertyImplementation
? Конечно, вы можете найти подходящий тип для вызова (не callvirt) геттер / сеттер только сTImplementation
?Все эти ответы очень хороши.
Мое решение заключается в использовании фрагментов кода для выполнения этой работы.
При этом используется простейший вызов события PropertyChanged.
Сохраните этот фрагмент и используйте его как фрагмент «fullprop».
Вы можете изменить вызов по своему усмотрению (использовать вышеуказанные решения)
источник
Если вы используете динамику в .NET 4.5, вам не о чем беспокоиться
INotifyPropertyChanged
.если имя привязано к какому-либо элементу управления, оно просто отлично работает.
источник
Другое комбинированное решение использует StackFrame:
Применение:
источник
get_Foo
метод в режиме Release.Я создал метод расширения в моей базовой библиотеке для повторного использования:
Это работает с .Net 4.5 из-за CallerMemberNameAttribute . Если вы хотите использовать его с более ранней версией .Net, вы должны изменить объявление метода с:
...,[CallerMemberName] string propertyName = "", ...
на...,string propertyName, ...
Применение:
источник
Я решил таким образом (это немного трудоемко, но, безусловно, быстрее во время выполнения).
В VB (извините, но я думаю, что это не сложно перевести на C #), я делаю эту замену с помощью RE:
с:
Это transofrm весь код, как это:
В
И если я хочу иметь более читаемый код, я могу быть наоборот, просто сделав следующую замену:
С
Я бросаю, чтобы заменить код IL метода set, но я не могу написать много скомпилированного кода в IL ... Если я напишу день, я скажу вам!
источник
Я держу это как фрагмент. C # 6 добавляет хороший синтаксис для вызова обработчика.
источник
Вот версия NotifyPropertyChanged для Unity3D или не CallerMemberName
Этот код позволяет вам писать поля поддержки свойств следующим образом:
Кроме того, в resharper, если вы создадите фрагмент шаблона / поиска, вы также можете автоматизировать рабочий процесс, преобразовав простые поля проп в вышеуказанную основу.
Шаблон поиска:
Заменить шаблон:
источник
Я написал статью, которая помогает с этим ( https://msdn.microsoft.com/magazine/mt736453 ). Вы можете использовать пакет NuSet SolSoft.DataBinding. Тогда вы можете написать код так:
Льготы:
источник
Хотя, очевидно, существует множество способов сделать это, за исключением магических ответов AOP, ни один из ответов, похоже, не рассматривает установку свойства Model непосредственно из модели представления без наличия локального поля для ссылки.
Проблема в том, что вы не можете ссылаться на недвижимость. Однако вы можете использовать Action для установки этого свойства.
Это можно использовать как следующий фрагмент кода.
Ознакомьтесь с этим репозиторием BitBucket для полной реализации метода и нескольких различных способов достижения того же результата, включая метод, который использует LINQ, и метод, который использует отражение. Обратите внимание, что эти методы медленнее по производительности.
источник
Другие вещи, которые вы, возможно, захотите учесть при реализации этих видов свойств, это то, что INotifyPropertyChang * ed *ing оба используют классы аргументов события.
Если у вас установлено большое количество свойств, то количество экземпляров класса аргумента события может быть огромным, вам следует рассмотреть возможность их кэширования, поскольку они являются одной из областей, в которых может произойти взрыв строки.
Взгляните на эту реализацию и объясните, почему она была задумана.
Блог Джоша Смита
источник
Я только что нашел ActiveSharp - автоматический INotifyPropertyChanged , я еще не использовал его, но выглядит хорошо.
Цитировать с его веб-сайта ...
Вместо этого напишите такие свойства:
Обратите внимание, что нет необходимости включать имя свойства в виде строки. ActiveSharp надежно и правильно вычисляет это для себя. Это работает на основе того факта, что ваша реализация свойства передает поле поддержки (_foo) по ссылке. (ActiveSharp использует этот вызов «по ссылке», чтобы определить, какое поле поддержки было передано, и из поля оно идентифицирует свойство).
источник
Идея с использованием отражения:
источник
Я понимаю, что на этот вопрос уже есть миллиард ответов, но ни один из них не показался мне вполне подходящим. Моя проблема в том, что я не хочу никаких хитов производительности и готов мириться с небольшим многословием только по этой причине. Я также не слишком беспокоюсь об автоматических свойствах, что привело меня к следующему решению:
Другими словами, вышеприведенное решение удобно, если вы не возражаете против этого:
Pros
Cons
Увы, это все же лучше, чем делать это,
Для каждого свойства, которое становится кошмаром с дополнительным многословием ;-(
Обратите внимание, я не утверждаю, что это решение лучше с точки зрения производительности по сравнению с другими, просто это жизнеспособное решение для тех, кому не нравятся другие представленные решения.
источник
Я придумал этот базовый класс для реализации наблюдаемого паттерна, который в значительной степени делает то, что вам нужно ( «автоматически» реализуя set и get). Я потратил на это целый час в качестве прототипа, поэтому он не имеет много модульных тестов, но подтверждает концепцию. Обратите внимание, что он использует
Dictionary<string, ObservablePropertyContext>
для удаления необходимости в закрытых полях.Вот использование
источник
Я предлагаю использовать ReactiveProperty. Это самый короткий метод, кроме Fody.
вместо
( DOCS )
источник
Другая идея ...
источник
=> здесь мое решение со следующими функциями
источник
Использовать этот
}
источник