Aangepaste afhankelijkheidseigenschappen (WPF .NET)
Ontwikkelaars van WPF-toepassingen (Windows Presentation Foundation) en auteurs van onderdelen kunnen aangepaste afhankelijkheidseigenschappen maken om de functionaliteit van hun eigenschappen uit te breiden. In tegenstelling tot een COMMON Language Runtime (CLR) eigenschap, voegt een afhankelijkheidseigenschap ondersteuning toe voor styling, gegevensbinding, overname, animaties en standaardwaarden. Background, Widthen Text zijn voorbeelden van bestaande afhankelijkheidseigenschappen in WPF-klassen. In dit artikel wordt beschreven hoe u aangepaste afhankelijkheidseigenschappen implementeert en opties biedt voor het verbeteren van de prestaties, bruikbaarheid en veelzijdigheid.
Voorwaarden
In het artikel wordt ervan uitgegaan dat u basiskennis hebt van afhankelijkheidseigenschappen en dat u overzicht van eigenschappen van afhankelijkheden hebt gelezen. Als u de voorbeelden in dit artikel wilt volgen, helpt dit als u bekend bent met Extensible Application Markup Language (XAML) en weet hoe u WPF-toepassingen schrijft.
Identificator van afhankelijkheidseigenschap
Dependency-eigenschappen zijn eigenschappen die zijn geregistreerd in het WPF-eigenschappensysteem via aanroepen zoals Register of RegisterReadOnly. De methode Register
retourneert een DependencyProperty exemplaar met de geregistreerde naam en kenmerken van een afhankelijkheidseigenschap. U wijst het DependencyProperty
exemplaar toe aan een statisch alleen-lezen veld, ook wel een afhankelijkheidseigenschaps-idgenoemd, die volgens conventie de naam <property name>Property
heeft. Het id-veld voor de eigenschap Background is bijvoorbeeld altijd BackgroundProperty.
De afhankelijkheidseigenschap identificatie wordt gebruikt als achtergrondveld voor het ophalen of instellen van eigenschapswaarden, in plaats van het standaardpatroon van het ondersteunen van een eigenschap met een privéveld. Het eigenschappensysteem gebruikt niet alleen de id, XAML-processors kunnen deze gebruiken en uw code (en mogelijk externe code) heeft toegang tot afhankelijkheidseigenschappen via hun id's.
Afhankelijkheidseigenschappen kunnen alleen worden toegepast op klassen die zijn afgeleid van DependencyObject typen. De meeste WPF-klassen ondersteunen afhankelijkheidseigenschappen, omdat DependencyObject
zich dicht bij de hoofdmap van de WPF-klassehiërarchie bevindt. Zie voor meer informatie over eigenschappen van afhankelijkheden en de terminologie en conventies die worden gebruikt om deze te beschrijven overzicht van eigenschappen van afhankelijkheden.
Wrappers voor afhankelijkheidseigenschappen
WPF-afhankelijkheidseigenschappen die geen gekoppelde eigenschappen zijn, worden weergegeven door een CLR-wrapper die get
en set
accessors implementeert. Met behulp van een property wrapper kunnen gebruikers van afhankelijke eigenschappen waarden van afhankelijkheidseigenschappen ophalen of instellen, zoals bij elke andere CLR-eigenschap. De get
en set
accessors communiceren met het onderliggende eigenschapssysteem via DependencyObject.GetValue en DependencyObject.SetValue aanroepen, waarbij de id van de afhankelijkheidseigenschap als parameter wordt doorgegeven. Consumenten van afhankelijkheidseigenschappen roepen doorgaans niet rechtstreeks GetValue
of SetValue
aan, maar als u een aangepaste afhankelijkheidseigenschap implementeert, gebruikt u deze methoden in de wrapper.
Wanneer moet u een afhankelijkheidseigenschap implementeren
Wanneer u een eigenschap implementeert op een klasse die is afgeleid van DependencyObject, maakt u deze een afhankelijkheidseigenschap door een back-up van uw eigenschap te maken met een DependencyProperty-id. Of het nuttig is om een afhankelijkheidseigenschap te maken, is afhankelijk van uw scenario. Hoewel het ondersteunen van uw eigenschap met een privéveld voldoende is voor sommige scenario's, kunt u overwegen om een afhankelijkheidseigenschap te implementeren als u wilt dat uw eigenschap een of meer van de volgende WPF-mogelijkheden ondersteunt:
Eigenschappen die instelbaar zijn binnen een stijl. Zie stijlen en sjablonenvoor meer informatie.
Eigenschappen die ondersteuning bieden voor gegevensbinding. Zie voor meer informatie over gegevensbindingsafhankelijkheidseigenschappen De eigenschappen van twee besturingselementen binden.
Eigenschappen die instelbaar zijn via dynamische resourceverwijzingen. Zie XAML-resourcesvoor meer informatie.
Eigenschappen die automatisch hun waarde overnemen van een ouder element in de elementstructuur. Hiervoor moet u zich registreren met behulp van RegisterAttached, zelfs als u ook een property wrapper voor CLR-toegang maakt. Zie overname van eigenschapswaardenvoor meer informatie.
Eigenschappen die kunnen worden geanimeerd. Zie Animatieoverzichtvoor meer informatie.
Melding door het WPF-eigenschappensysteem wanneer een eigenschapswaarde wordt gewijzigd. Wijzigingen kunnen worden veroorzaakt door acties van het eigenschappensysteem, de omgeving, de gebruiker of de stijlen. Uw eigenschap kan een callback-methode opgeven in metagegevens van eigenschappen die telkens worden aangeroepen wanneer het eigenschapssysteem bepaalt dat de eigenschapswaarde is gewijzigd. Een gerelateerd concept is coercion van eigenschapswaarde. Raadpleeg eigenschap callbacks en validatievoor afhankelijkheden voor meer informatie.
Toegang tot metagegevens van afhankelijkheidseigenschappen, die worden gelezen door WPF-processen. U kunt bijvoorbeeld eigenschappenmetagegevens gebruiken voor het volgende:
Geef op of een gewijzigde waarde van de afhankelijkheidseigenschap de visuals voor een element opnieuw moet compileren in het indelingssysteem.
Stel de standaardwaarde van een afhankelijkheidseigenschap in door metagegevens voor afgeleide klassen te overschrijven.
Visual Studio WPF Designerondersteuning, zoals het bewerken van de eigenschappen van een aangepast besturingselement in het venster Eigenschappen. Zie Overzicht van het ontwerpen van besturingselementenvoor meer informatie.
Voor sommige scenario's is het overschrijven van de metagegevens van een bestaande afhankelijkheidseigenschap een betere optie dan het implementeren van een nieuwe afhankelijkheidseigenschap. Of een onderdrukking van metagegevens praktisch is, is afhankelijk van uw scenario en hoe nauw dat scenario lijkt op de implementatie van bestaande WPF-afhankelijkheidseigenschappen en -klassen. Zie voor meer informatie over het overschrijven van metadata van bestaande afhankelijkheidseigenschappen metagegevens van afhankelijkheidseigenschappen.
Controlelijst voor het maken van een afhankelijkheidseigenschap
Volg deze stappen om een afhankelijkheidseigenschap te maken. Sommige van de stappen kunnen worden gecombineerd en geïmplementeerd in één regel code.
(Optioneel) Metagegevens van afhankelijkheidseigenschappen maken.
Registreer de afhankelijkheidseigenschap bij het eigenschappensysteem, waarbij u een eigenschapsnaam, een eigenaartype, het eigenschapswaardetype en eventueel metagegevens van de eigenschap opgeeft.
Definieer een DependencyProperty-id als een
public static readonly
veld voor het type eigenaar. De id-veldnaam is de naam van de eigenschap met het achtervoegselProperty
toegevoegd.Definieer een CLR-wrapper-eigenschap met dezelfde naam als de naam van de afhankelijkheidseigenschap. Implementeer in de CLR-wrapper de toegangen
get
enset
die verbinding maken met de afhankelijkheidseigenschap die de wrapper ondersteunt.
De eigendom registreren
Als u wilt dat uw eigenschap een afhankelijkheidseigenschap is, moet u deze registreren bij het eigenschappensysteem. Als u uw property wilt registreren, roept u de Register methode aan vanuit de body van uw klasse, maar buiten alle liddefinities. De Register
-methode retourneert een unieke id van de afhankelijkheidseigenschap die u gebruikt bij het aanroepen van de API van het eigenschapssysteem. De reden dat de Register
aanroep buiten liddefinities wordt uitgevoerd, is omdat u de retourwaarde toewijst aan een public static readonly
veld van het type DependencyProperty. Dit veld, dat u in uw klasse maakt, is de id voor uw afhankelijkheidseigenschap. In het volgende voorbeeld wordt het eerste argument van Register
de afhankelijkheidseigenschap AquariumGraphic
genoemd.
// Register a dependency property with the specified property name,
// property type, owner type, and property metadata. Store the dependency
// property identifier as a public static readonly member of the class.
public static readonly DependencyProperty AquariumGraphicProperty =
DependencyProperty.Register(
name: "AquariumGraphic",
propertyType: typeof(Uri),
ownerType: typeof(Aquarium),
typeMetadata: new FrameworkPropertyMetadata(
defaultValue: new Uri("http://www.contoso.com/aquarium-graphic.jpg"),
flags: FrameworkPropertyMetadataOptions.AffectsRender,
propertyChangedCallback: new PropertyChangedCallback(OnUriChanged))
);
' Register a dependency property with the specified property name,
' property type, owner type, and property metadata. Store the dependency
' property identifier as a public static readonly member of the class.
Public Shared ReadOnly AquariumGraphicProperty As DependencyProperty =
DependencyProperty.Register(
name:="AquariumGraphic",
propertyType:=GetType(Uri),
ownerType:=GetType(Aquarium),
typeMetadata:=New FrameworkPropertyMetadata(
defaultValue:=New Uri("http://www.contoso.com/aquarium-graphic.jpg"),
flags:=FrameworkPropertyMetadataOptions.AffectsRender,
propertyChangedCallback:=New PropertyChangedCallback(AddressOf OnUriChanged)))
Notitie
Het definiëren van de afhankelijkheidseigenschap in de hoofdtekst van de klasse is de typische implementatie, maar het is ook mogelijk om een afhankelijkheidseigenschap te definiëren in de klasse statische constructor. Deze benadering kan zinvol zijn als u meer dan één regel code nodig hebt om de afhankelijkheidseigenschap te initialiseren.
Naamgeving van afhankelijkheidseigenschap
De vastgestelde naamconventie voor afhankelijkheidseigenschappen is verplicht voor normaal gedrag van het eigenschappensysteem. De naam van het id-veld dat u maakt, moet de geregistreerde naam van de eigenschap zijn met het achtervoegsel Property
.
De naam van een afhankelijkheidseigenschap moet uniek zijn binnen de registratieklasse. Afhankelijkheidseigenschappen die worden overgenomen via een basistype, zijn al geregistreerd en kunnen niet worden geregistreerd door een afgeleid type. U kunt echter een afhankelijkheidseigenschap gebruiken die is geregistreerd door een ander type, zelfs een type waarvan uw klasse niet wordt overgenomen door uw klasse toe te voegen als eigenaar van de afhankelijkheidseigenschap. Zie Metagegevens van eigenschappen van afhankelijkhedenvoor meer informatie over het toevoegen van een klasse als eigenaar.
Een eigenschapswikkelaar implementeren
Volgens de conventie moet de naam van de wrapper-eigenschap hetzelfde zijn als de eerste parameter van de Register-aanroep, de naam van de afhankelijkheidseigenschap. De wrapper-implementatie roept GetValue aan in de get
accessor en SetValue in de set
-accessor (voor eigenschappen voor lezen/schrijven). In het volgende voorbeeld ziet u een wrapper, na de registratieaanroep en id-velddeclaratie. Alle eigenschappen van openbare afhankelijkheden in WPF-klassen gebruiken een vergelijkbaar wrappermodel.
// Register a dependency property with the specified property name,
// property type, owner type, and property metadata. Store the dependency
// property identifier as a public static readonly member of the class.
public static readonly DependencyProperty AquariumGraphicProperty =
DependencyProperty.Register(
name: "AquariumGraphic",
propertyType: typeof(Uri),
ownerType: typeof(Aquarium),
typeMetadata: new FrameworkPropertyMetadata(
defaultValue: new Uri("http://www.contoso.com/aquarium-graphic.jpg"),
flags: FrameworkPropertyMetadataOptions.AffectsRender,
propertyChangedCallback: new PropertyChangedCallback(OnUriChanged))
);
// Declare a read-write property wrapper.
public Uri AquariumGraphic
{
get => (Uri)GetValue(AquariumGraphicProperty);
set => SetValue(AquariumGraphicProperty, value);
}
' Register a dependency property with the specified property name,
' property type, owner type, and property metadata. Store the dependency
' property identifier as a public static readonly member of the class.
Public Shared ReadOnly AquariumGraphicProperty As DependencyProperty =
DependencyProperty.Register(
name:="AquariumGraphic",
propertyType:=GetType(Uri),
ownerType:=GetType(Aquarium),
typeMetadata:=New FrameworkPropertyMetadata(
defaultValue:=New Uri("http://www.contoso.com/aquarium-graphic.jpg"),
flags:=FrameworkPropertyMetadataOptions.AffectsRender,
propertyChangedCallback:=New PropertyChangedCallback(AddressOf OnUriChanged)))
' Declare a read-write property wrapper.
Public Property AquariumGraphic As Uri
Get
Return CType(GetValue(AquariumGraphicProperty), Uri)
End Get
Set
SetValue(AquariumGraphicProperty, Value)
End Set
End Property
Behalve in zeldzame gevallen mag uw wrapper-implementatie alleen GetValue en SetValue code bevatten. Zie gevolgen voor aangepaste afhankelijkheidseigenschappen.
Als uw object geen vaste naamgevingsconventies volgt, kan het zijn dat u misschien deze problemen ondervindt:
Sommige aspecten van stijlen en sjablonen werken niet.
De meeste hulpprogramma's en ontwerpers zijn afhankelijk van de naamconventies om XAML correct te serialiseren en hulp te bieden bij de ontwerpomgeving op eigenschappenniveau.
De huidige implementatie van het WPF XAML-laadprogramma omzeilt de wrappers volledig en is afhankelijk van de naamconventie voor het verwerken van kenmerkwaarden. Zie XAML-laad- en afhankelijkheidseigenschappenvoor meer informatie.
Metagegevens van afhankelijkheidseigenschappen
Wanneer u een afhankelijkheidseigenschap registreert, maakt het eigenschappensysteem een metagegevensobject om eigenschappen op te slaan. Door overbelasting van de Register methode kunt u tijdens de registratie eigenschappenmetagegevens opgeven, bijvoorbeeld Register(String, Type, Type, PropertyMetadata). Een veelvoorkomend gebruik van eigenschapsmetagegevens is het toepassen van een aangepaste standaardwaarde voor nieuwe exemplaren die gebruikmaken van een afhankelijkheidseigenschap. Als u geen metagegevens van eigenschappen opgeeft, wijst het eigenschappensysteem standaardwaarden toe aan veel van de kenmerken van de afhankelijkheidseigenschap.
Als u een afhankelijkheidseigenschap maakt op een klasse die is afgeleid van FrameworkElement, kunt u de meer gespecialiseerde metagegevensklasse gebruiken FrameworkPropertyMetadata in plaats van de basisklasse PropertyMetadata. Met verschillende FrameworkPropertyMetadata constructorhandtekeningen kunt u verschillende combinaties van metagegevenskenmerken opgeven. Als u alleen een standaardwaarde wilt opgeven, gebruikt u FrameworkPropertyMetadata(Object) en geeft u de standaardwaarde door aan de parameter Object
. Zorg ervoor dat het waardetype overeenkomt met de propertyType
die is opgegeven in de Register
aanroep.
Met sommige FrameworkPropertyMetadata overbelastingen kunt u metagegevensoptievlaggen voor uw eigenschap opgeven. Het eigenschappensysteem converteert deze vlaggen naar discrete eigenschappen en de vlagwaarden worden gebruikt door WPF-processen, zoals de indelingsengine.
Metagegevensvlagmen instellen
Houd rekening met het volgende bij het instellen van metagegevensvlagmen:
Als uw eigenschapswaarde (of wijzigingen in deze waarde) van invloed is op de wijze waarop het indelingssysteem een UI-element weergeeft, stelt u een of meer van de volgende vlaggen in:
AffectsMeasure, wat aangeeft dat voor een wijziging van de eigenschapswaarde een wijziging in de weergave van de gebruikersinterface is vereist, met name de ruimte die wordt bezet door een object binnen het bovenliggende object. Stel bijvoorbeeld deze metagegevensvlag in voor een eigenschap
Width
.AffectsArrange, wat aangeeft dat voor een wijziging in de eigenschapswaarde een wijziging in ui-rendering is vereist, met name de positie van een object binnen het bovenliggende object. Normaal gesproken verandert het object niet ook de grootte. Stel bijvoorbeeld deze metagegevensvlag in voor een eigenschap
Alignment
.AffectsRender, wat aangeeft dat er een wijziging is opgetreden die geen invloed heeft op de indeling en meting, maar nog steeds een andere render vereist. Stel deze vlag bijvoorbeeld in voor een
Background
eigenschap of een andere eigenschap die van invloed is op de kleur van een element.
U kunt deze vlaggen ook gebruiken als invoer voor uw overschrijvingsimplementaties van het eigenschappensysteem (of de indeling) callbacks. U kunt bijvoorbeeld een OnPropertyChanged callback gebruiken om InvalidateArrange aan te roepen wanneer een eigenschap van het exemplaar een waardewijziging rapporteert en AffectsArrange is ingesteld in metagegevens.
Sommige eigenschappen zijn van invloed op de renderingkenmerken van het bovenliggende element op andere manieren. Wijzigingen in de eigenschap MinOrphanLines kunnen bijvoorbeeld de algehele weergave van een stroomdocument wijzigen. Gebruik AffectsParentArrange of AffectsParentMeasure om bovenliggende acties in uw eigen eigenschappen aan te geven.
Afhankelijkheidseigenschappen ondersteunen standaard gegevensbinding. U kunt echter IsDataBindingAllowed gebruiken om gegevensbinding uit te schakelen wanneer er geen realistisch scenario is, of wanneer de prestaties van gegevensbindingen problematisch zijn, zoals bij grote objecten.
Hoewel de standaardmodus voor gegevensbinding voor afhankelijkheidseigenschappen OneWayis, kunt u de bindingsmodus van een specifieke binding wijzigen in TwoWay. Zie Bindingsrichtingvoor meer informatie. Als auteur van een afhankelijkheidseigenschap kunt u er zelfs voor kiezen om tweerichtingsbindingen te maken voor de standaardmodus. Een voorbeeld van een bestaande afhankelijkheidseigenschap die gebruikmaakt van gegevensbinding in twee richtingen, is MenuItem.IsSubmenuOpen, die een status heeft die is gebaseerd op andere eigenschappen en methodeaanroepen. Het scenario voor
IsSubmenuOpen
is dat de instellingslogica en het composieren van MenuIteminteractie hebben met de standaardthemastijl. TextBox.Text is een andere WPF-afhankelijkheidseigenschap die standaard gebruikmaakt van binding in twee richtingen.U kunt de overerving van eigenschappen voor uw dependency property inschakelen door de Inherits-vlag in te stellen. Eigenschapsovername is handig voor scenario's waarin bovenliggende en onderliggende elementen een eigenschap delen en het logisch is dat het onderliggende element de waarde van het bovenliggende element voor deze gemeenschappelijke eigenschap overneemt. Een voorbeeld van een overgenomen eigenschap is DataContext, die bindingsbewerkingen ondersteunt die gebruikmaken van het hoofddetailscenario voor gegevenspresentatie. Met het erven van eigenschapswaarden kunt u een gegevenscontext opgeven bij de pagina of de toepassingsroot, waardoor het niet nodig is deze op te geven voor bindings van onderliggende elementen. Hoewel een overgenomen eigenschapswaarde de standaardwaarde overschrijft, kunnen eigenschapswaarden lokaal worden ingesteld op elk onderliggend element. Gebruik overname van eigenschapswaarden spaarzaam omdat deze prestatiekosten heeft. Zie overname van eigenschapswaardenvoor meer informatie.
Stel de vlag Journal in om aan te geven dat uw afhankelijkheidseigenschap moet worden gedetecteerd of gebruikt door navigatielogboekservices. Met de eigenschap SelectedIndex wordt bijvoorbeeld de vlag
Journal
ingesteld om aan te bevelen dat toepassingen een logboekgeschiedenis van geselecteerde items behouden.
Alleen-lezen afhankelijke eigenschappen
U kunt een afhankelijkheidseigenschap definiëren die alleen-lezen is. Een typisch scenario is een afhankelijkheidseigenschap waarin de interne status wordt opgeslagen. IsMouseOver is bijvoorbeeld alleen-lezen omdat de status alleen moet worden bepaald door de muisinvoer. Zie eigenschappen van alleen-lezenafhankelijkheidvoor meer informatie.
Eigenschappen van afhankelijkheid van verzamelingstype
Afhankelijkheidseigenschappen van het verzamelingstype hebben extra implementatieproblemen, zoals het instellen van een standaardwaarde voor referentietypen en ondersteuning voor gegevensbindingen voor verzamelingselementen. Zie Verzamelingstype-afhankelijkheidseigenschappenvoor meer informatie.
Beveiliging van afhankelijkheidseigenschappen
Normaal gesproken declareert u afhankelijkheidseigenschappen als openbare eigenschappen en DependencyProperty id-velden als public static readonly
velden. Als u een meer beperkend toegangsniveau opgeeft, zoals protected
, kan een afhankelijkheidseigenschap nog steeds worden geopend via de id in combinatie met api's van het eigenschappensysteem. Zelfs een beveiligd id-veld is mogelijk toegankelijk via WPF-metagegevensrapportage of waardebepalings-API's, zoals LocalValueEnumerator. Zie Beveiliging van afhankelijkheidseigenschappenvoor meer informatie.
Voor alleen-lezen afhankelijkheidseigenschappen is de waarde die uit RegisterReadOnly wordt geretourneerd, DependencyPropertyKey, en maakt u meestal geen lid van uw klasse van DependencyPropertyKey
een public
. Omdat het WPF-eigenschappensysteem de DependencyPropertyKey
buiten uw code niet doorgeeft, heeft een alleen-lezen afhankelijkheidseigenschap een betere set
beveiliging dan een eigenschap voor lezen/schrijven.
Afhankelijkheidseigenschappen en klassenconstructors
Er is een algemeen principe in het programmeren van beheerde code, vaak afgedwongen door hulpprogramma's voor codeanalyse, die klasseconstructors geen virtuele methoden mogen aanroepen. Dit komt doordat basisconstructors kunnen worden aangeroepen tijdens de initialisatie van een afgeleide klasseconstructor en een virtuele methode die door een basisconstructor wordt aangeroepen, kan worden uitgevoerd voordat de afgeleide klasse is geïnitialiseerd. Wanneer u afgeleid bent van een klasse die al is afgeleid van DependencyObject, roept het eigenschappensysteem zelf aan en maakt het virtuele methoden intern beschikbaar. Deze virtuele methoden maken onderdeel uit van de services van het WPF-eigenschappensysteem. Door de methoden te overschrijven, kunnen afgeleide klassen deelnemen aan waardebepaling. Als u potentiële problemen met runtime-initialisatie wilt voorkomen, moet u geen afhankelijkheidseigenschapswaarden instellen binnen constructors van klassen, tenzij u een specifiek constructorpatroon volgt. Zie Veilige constructorpatronen voor DependencyObjectsvoor meer informatie.
Zie ook
- Afhankelijke eigenschappen overzicht
- Metadata van eigenschap van afhankelijkheid
- Overzicht van het ontwerpen van besturingselementen
- Verzameltypische afhankelijkheidseigenschappen
- Beveiliging van afhankelijkheidseigenschappen
- XAML-eigenschappen voor laden en afhankelijkheid
- Veilige Constructorpatronen voor DependencyObjects
.NET Desktop feedback