Ответ
INotifyPropertyChanged — это ключевой интерфейс в .NET для реализации шаблона наблюдатель (Observer) при связывании данных (Data Binding). Он позволяет объекту (например, ViewModel) уведомлять UI-слой (View) об изменении значения своего свойства, что автоматически приводит к обновлению интерфейса.
Базовая реализация:
using System.ComponentModel;
using System.Runtime.CompilerServices;
public class ProductViewModel : INotifyPropertyChanged
{
private decimal _price;
public decimal Price
{
get => _price;
set
{
// Проверка на реальное изменение значения для оптимизации
if (_price == value) return;
_price = value;
// Уведомление системы привязки данных
OnPropertyChanged();
// Можно вызвать связанные вычисления
OnPropertyChanged(nameof(PriceWithTax));
}
}
public decimal PriceWithTax => _price * 1.20m;
public event PropertyChangedEventHandler? PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string? propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
Практические советы:
- Используйте
[CallerMemberName]: Этот атрибут автоматически подставляет имя свойства, из которого был вызван метод, исключая ошибки из-за опечаток в строковых литералах. - Сравнивайте значения: Всегда проверяйте, изменилось ли значение свойства, перед вызовом
OnPropertyChanged(). Это предотвращает бесконечные циклы обновления и повышает производительность. - Уведомление для вычисляемых свойств: Если свойство
Bзависит от свойстваA, при измененииAнужно вызвать уведомление и дляB. - Библиотеки для упрощения: В больших проектах используйте
CommunityToolkit.Mvvm(атрибут[ObservableProperty]) или Fody/PropertyChanged для автоматической генерации шаблонного кода.
Ответ 18+ 🔞
А, INotifyPropertyChanged, классика жанра! Ну, слушай сюда, это же та самая магия, которая заставляет твой интерфейс не отставать от логики, когда данные меняются. Без неё — пиздец, вручную всё обновлять, как в каменном веке.
Вот смотри, основа основ. Берёшь свой класс, например, для товара, и делаешь вот такую штуку:
using System.ComponentModel;
using System.Runtime.CompilerServices;
public class ProductViewModel : INotifyPropertyChanged
{
private decimal _price;
public decimal Price
{
get => _price;
set
{
// Сначала проверь, а поменялось ли что-то вообще? Чтобы не дрочить систему попусту.
if (_price == value) return;
_price = value;
// А вот тут кричи на всю деревню, что значение обновилось!
OnPropertyChanged();
// И заодно крикни, что свойство, которое от цены зависит, тоже надо пересчитать!
OnPropertyChanged(nameof(PriceWithTax));
}
}
// Вот это свойство считает цену с налогом. Оно зависит от Price.
public decimal PriceWithTax => _price * 1.20m;
// А это самое главное событие. На него подписывается интерфейс и ждёт, когда его позовут.
public event PropertyChangedEventHandler? PropertyChanged;
// И этот метод его зовёт. Красота!
protected virtual void OnPropertyChanged([CallerMemberName] string? propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
Теперь по дельным советам, чтобы не наступать на грабли:
[CallerMemberName]— твой лучший друг. Этот атрибут — просто волшебство. Ты вызываешьOnPropertyChanged()без параметров, а он сам, как хитрая жопа, подставляет имя свойства, откуда его вызвали. Никаких опечаток в строках, ебать колотить!- Сравнивай значения, блядь! Обязательно делай проверку
if (_price == value) return;. Иначе будешь слать уведомления почём зря, производительность просядет, а в сложных связках можно и в бесконечный цикл угодить. Овердохуища проблем на ровном месте. - Не забывай про вычисляемые свойства. Если у тебя есть свойство
PriceWithTax, которое считается изPrice, то при измененииPriceнадо крикнуть не только за себя, но и за него:OnPropertyChanged(nameof(PriceWithTax));. Иначе интерфейс так и будет показывать старую сумму с налогом, доверия к нему будет ноль ебать. - Не изобретай велосипед на больших проектах. Писать эту лапшу для каждого свойства — терпения ебать ноль. Бери готовые инструменты: CommunityToolkit.Mvvm с его атрибутом
[ObservableProperty]или Fody/PropertyChanged. Они эту рутину за тебя сгенерируют, и жить станет проще. Честно.
Вот и вся философия. Сделал правильно — и интерфейс летает, данные синхронны. Сделал криво — получаешь тормоза и баги, от которых волосы дыбом встают. Удачи!