What is a propertychangedeventhandler delegate?

Forstå PropertyChanged-hændelsen i C#

05/06/2009

Rating: 3.97 (2823 votes)

I en verden af moderne softwareudvikling med C# er det afgørende at skabe en flydende og responsiv brugeroplevelse. En af de største udfordringer er at sikre, at brugergrænsefladen (UI) altid afspejler den seneste tilstand af applikationens data. Forestil dig en indkøbskurv, hvor totalprisen ikke opdateres, når du tilføjer en ny vare. Det ville være forvirrende og uprofessionelt. Løsningen på dette problem findes i et kraftfuldt mønster centreret omkring PropertyChanged-hændelsen. Denne mekanisme er hjørnestenen i databinding og er fundamental for arkitekturmønstre som MVVM (Model-View-ViewModel).

What is propertychanged event in C#?
The PropertyChanged event is a powerful feature in C# that simplifies data binding and enhances the maintainability and efficiency of your code. By notifying other parts of your code about property changes, it enables better interaction between different components.

Denne artikel vil dykke ned i, hvad PropertyChanged-hændelsen er, hvordan den implementeres korrekt gennem INotifyPropertyChanged-interfacet, og hvorfor den er så uundværlig for at bygge dynamiske og vedligeholdelsesvenlige .NET-applikationer.

Indholdsfortegnelse

Hvad er INotifyPropertyChanged?

Kernen i systemet er INotifyPropertyChanged-interfacet. Dette interface, som findes i System.ComponentModel-navneområdet, er utroligt simpelt. Det indeholder kun ét enkelt medlem:

public interface INotifyPropertyChanged { event PropertyChangedEventHandler PropertyChanged; }

Når en klasse implementerer dette interface, signalerer den til omverdenen, at den kan udsende en notifikation, hver gang værdien af en af dens offentlige egenskaber (properties) ændres. Denne notifikation er selve PropertyChanged-hændelsen. Andre dele af programmet, typisk UI-elementer, kan abonnere på denne hændelse. Når hændelsen udløses, ved abonnenten, at den skal opdatere sig selv for at afspejle den nye værdi.

En sikker implementering

At implementere interfacet korrekt er afgørende for at undgå fejl, især i applikationer med flere tråde. En robust og genanvendelig implementering ser ofte således ud:

using System.ComponentModel; using System.Runtime.CompilerServices; public class Person: INotifyPropertyChanged { private string _navn; public string Navn { get { return _navn; } set { if (_navn != value) { _navn = value; OnPropertyChanged(); } } } public event PropertyChangedEventHandler PropertyChanged; protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null) { PropertyChangedEventHandler handler = PropertyChanged; if (handler != null) { handler(this, new PropertyChangedEventArgs(propertyName)); } } }

Lad os bryde koden ned:

  • Privat felt (_navn): Dette felt gemmer den faktiske data for vores Navn-egenskab.
  • Offentlig egenskab (Navn): Dette er den egenskab, som andre dele af koden vil interagere med. I set-blokken er logikken central.
  • Værdi-tjek (if (_navn != value)): Vi udløser kun hændelsen, hvis den nye værdi rent faktisk er forskellig fra den gamle. Dette forhindrer unødvendige opdateringer og potentielle uendelige løkker.
  • OnPropertyChanged-metoden: Dette er en hjælpemetode, der er ansvarlig for at udløse PropertyChanged-hændelsen.
  • [CallerMemberName]-attributten: Dette er en fantastisk funktion introduceret i .NET 4.5. Den fortæller kompilatoren, at den automatisk skal indsætte navnet på den metode eller egenskab, der kalder OnPropertyChanged. I dette tilfælde, når vi kalder OnPropertyChanged() fra Navn-egenskabens setter, vil kompilatoren automatisk levere strengen "Navn". Dette eliminerer "magiske strenge" og gør koden mere robust over for refaktorering.
  • Trådsikkerhed: Linjen PropertyChangedEventHandler handler = PropertyChanged; er vigtig. Den skaber en lokal kopi af hændelseshandleren. Dette forhindrer en race condition, hvor en anden tråd kunne fjerne abonnementet på hændelsen mellem vores null-tjek (if (handler != null)) og selve kaldet, hvilket ellers ville forårsage en NullReferenceException.

Hvorfor er databinding så vigtigt?

Nu hvor vi har en klasse, der kan notificere om ændringer, kan vi udnytte kraften i databinding. Databinding er en mekanisme i UI-frameworks som WPF, UWP, Avalonia og .NET MAUI, der skaber en bro mellem en UI-kontrol (f.eks. en tekstboks) og en dataegenskab (f.eks. vores Navn-egenskab).

Does INotifyPropertyChanged raise an event if a property changes?
Raising an event when a property changes is precisely what INotifyPropertyChanged does. There's one required member to implement INotifyPropertyChanged and that is the PropertyChanged event. Anything you implemented yourself would probably be identical to that implementation, so there's no advantage to not using it.

Når en binding er etableret, lytter UI-frameworket automatisk efter PropertyChanged-hændelsen. Når vores Person-objekt udløser hændelsen for Navn-egenskaben, fanger bindingssystemet den og opdaterer automatisk den tilknyttede UI-kontrol. Dette sker uden, at vi manuelt skal skrive kode for at opdatere UI'et.

Dette princip er fundamentalt i MVVM-mønsteret, hvor ViewModel'en eksponerer data til View'et (UI'et) og bruger INotifyPropertyChanged til at holde de to synkroniserede.

Avanceret emne: Dependency Properties

Mens INotifyPropertyChanged er en generel mekanisme, der kan bruges overalt i .NET, har UI-frameworks som WPF og UWP deres eget, mere avancerede ejendomssystem kaldet Dependency Properties (afhængighedsegenskaber). Disse er ikke almindelige CLR-egenskaber, men specielle egenskaber registreret hos frameworket.

What is propertychanged event in C#?
The PropertyChanged event is a powerful feature in C# that simplifies data binding and enhances the maintainability and efficiency of your code. By notifying other parts of your code about property changes, it enables better interaction between different components.

Når en Dependency Property ændres, udløser den ikke en standard PropertyChanged-hændelse. I stedet bruger den en specifik callback-mekanisme, der leverer mere detaljerede oplysninger gennem DependencyPropertyChangedEventArgs. Disse argumenter indeholder ikke kun ejendommens navn, men også både den gamle og den nye værdi, hvilket giver mulighed for mere kompleks logik.

Sammenligningstabel

Her er en tabel, der sammenligner de to mekanismer:

FunktionINotifyPropertyChangedDependency Property System
AnvendelsesområdeGenerel notifikation i enhver .NET-klasse (ViewModels, Models etc.)Primært i UI-kontroller inden for specifikke frameworks (WPF, UWP).
ImplementeringImplementering af interface i klassen.Statisk registrering af egenskaben hos frameworket.
Information ved ændringNavnet på den ændrede egenskab (PropertyChangedEventArgs).Både gammel og ny værdi, samt selve egenskaben (DependencyPropertyChangedEventArgs).
HukommelsesforbrugVærdier gemmes i private felter for hver instans.Værdier gemmes effektivt af frameworket, hvilket er mere hukommelseseffektivt for tusindvis af UI-elementer.
Indbyggede funktionerKun notifikation.Understøtter databinding, animationer, styling, property-værdi-arv og validering direkte i systemet.

Ofte Stillede Spørgsmål (OSS)

Hvad sker der, hvis jeg glemmer at udløse OnPropertyChanged?

Hvis du ændrer værdien af det private felt (f.eks. _navn) uden at kalde OnPropertyChanged(), vil din data blive opdateret, men ingen notifikation vil blive sendt. Som resultat vil brugergrænsefladen ikke opdatere sig og vil vise forældet information. Dette er en meget almindelig fejl under udvikling.

Er INotifyPropertyChanged kun til UI?

Nej, slet ikke. Selvom det er mest kendt for sin rolle i UI-databinding, er det grundlæggende en implementering af Observer-designmønsteret. Du kan bruge det i enhver situation, hvor en del af dit system har brug for at reagere på ændringer i en anden del. For eksempel kan en logføringstjeneste abonnere på ændringer i et konfigurationsobjekt for at logge, når indstillinger ændres.

How do I handle a state change through a property change?
Some class handling methods that "handle" otherwise unexposed events that report a state change through a property change, such as ButtonBase.OnIsPressedChanged, also use the DependencyPropertyChangedEventArgs class for event data.

Hvorfor ikke bare gøre felterne offentlige?

Ved at bruge egenskaber (properties) med en get og set-blok opnår du kontrol. Det er i set-blokken, du kan indsætte logik, såsom at validere den nye værdi, tjekke om den er forskellig fra den gamle, og vigtigst af alt, udløse PropertyChanged-hændelsen. Offentlige felter giver ingen af disse muligheder.

Findes der biblioteker, der kan simplificere dette?

Ja. Mange MVVM-frameworks som Prism, MvvmCross og Community Toolkit MVVM (en del af .NET Community Toolkit) tilbyder baseklasser (f.eks. ObservableObject), der allerede har en optimeret implementering af INotifyPropertyChanged. Ved at arve fra disse klasser kan du simplificere din kode betydeligt og fokusere på din forretningslogik.

Hvis du vil læse andre artikler, der ligner Forstå PropertyChanged-hændelsen i C#, kan du besøge kategorien Sundhed.

Go up