wpf
Proprietà di dipendenza
Ricerca…
introduzione
Le proprietà di dipendenza sono un tipo di proprietà che estende una proprietà CLR. Mentre una proprietà CLR viene letta direttamente da un membro della classe, una proprietà dipendenze verrà risolta in modo dinamico quando si chiama il metodo GetValue () acquisito dall'oggetto tramite ereditarietà dalla classe DependencyObject di base.
Questa sezione analizza le proprietà di dipendenza e spiega il loro utilizzo sia concettualmente che attraverso esempi di codice.
Sintassi
- DependencyProperty.Register (nome stringa, tipo propertyType, Type ownerType)
- DependencyProperty.Register (nome stringa, tipo propertyType, Type ownerType, PropertyMetadata typeMetadata)
- DependencyProperty.Register (nome stringa, tipo propertyType, Type ownerType, PropertyMetadata typeMetadata, ValidateValueCallback validateValueCallback)
- DependencyProperty.RegisterAttached (nome stringa, Type propertyType, Type ownerType)
- DependencyProperty.RegisterAttached (nome stringa, tipo propertyType, Type ownerType, PropertyMetadata typeMetadata)
- DependencyProperty.RegisterAttached (nome stringa, tipo propertyType, Type ownerType, PropertyMetadata typeMetadata, ValidateValueCallback validateValueCallback)
- DependencyProperty.RegisterReadOnly (nome stringa, tipo propertyType, Type ownerType, PropertyMetadata typeMetadata)
- DependencyProperty.RegisterReadOnly (nome stringa, tipo propertyType, Type ownerType, PropertyMetadata typeMetadata, ValidateValueCallback validateValueCallback)
- DependencyProperty.RegisterAttachedReadOnly (nome stringa, tipo propertyType, Type ownerType, PropertyMetadata typeMetadata)
- DependencyProperty.RegisterAttachedReadOnly (nome stringa, tipo propertyType, Type ownerType, PropertyMetadata typeMetadata, ValidateValueCallback validateValueCallback)
Parametri
Parametro | Dettagli |
---|---|
nome | La rappresentazione in String del nome della proprietà |
Tipo di proprietà | Il Type di proprietà, ad es. typeof(int) |
ownerType | Il Type della classe in cui viene definita la proprietà, ad esempio typeof(MyControl) o typeof(MyAttachedProperties) . |
typeMetadata | Istanza di System.Windows.PropertyMetadata (o una delle sue sottoclassi) che definisce i valori predefiniti, proprietà callback modificate, FrameworkPropertyMetadata consente di definire le opzioni di associazione come System.Windows.Data.BindingMode.TwoWay . |
validateValueCallback | Callback personalizzato che restituisce true se il nuovo valore della proprietà è valido, altrimenti falso. |
Proprietà di dipendenza standard
Quando usare
Praticamente tutti i controlli WPF fanno un uso pesante delle proprietà di dipendenza. Una proprietà di dipendenza consente l'utilizzo di molte funzionalità WPF che non sono possibili con le proprietà CLR standard, incluso ma non limitato al supporto per stili, animazioni, associazione dati, ereditarietà del valore e notifiche di modifiche.
La proprietà TextBox.Text
è un semplice esempio di dove è necessaria una proprietà di dipendenza standard. Qui, l'associazione dei dati non sarebbe possibile se Text
fosse una proprietà CLR standard.
<TextBox Text="{Binding FirstName}" />
Come definire
Le proprietà di dipendenza possono essere definite solo in classi derivate da DependencyObject
, come FrameworkElement
, Control
, ecc.
Uno dei modi più veloci per creare una proprietà di dipendenza standard senza dover ricordare la sintassi è utilizzare lo snippet "propdp" digitando propdp
e quindi premendo Tab . Verrà inserito uno snippet di codice che può essere modificato in base alle tue esigenze:
public class MyControl : Control
{
public int MyProperty
{
get { return (int)GetValue(MyPropertyProperty); }
set { SetValue(MyPropertyProperty, value); }
}
// Using a DependencyProperty as the backing store for MyProperty.
// This enables animation, styling, binding, etc...
public static readonly DependencyProperty MyPropertyProperty =
DependencyProperty.Register("MyProperty", typeof(int), typeof(MyControl),
new PropertyMetadata(0));
}
Si dovrebbe Tab attraverso le diverse parti del frammento di codice per apportare le modifiche necessarie, incluso l'aggiornamento del nome della proprietà, tipo di proprietà, che contiene il tipo di classe, e il valore di default.
Convenzioni importanti
Ci sono alcune importanti convenzioni / regole da seguire qui:
Creare una proprietà CLR per la proprietà di dipendenza. Questa proprietà viene utilizzata nel codice code dell'utente o da altri utenti. Dovrebbe invocare
GetValue
eSetValue
modo che i consumatori non debbano farlo.Assegna un nome alla proprietà di dipendenza correttamente. Il campo
DependencyProperty
dovrebbe esserepublic static readonly
. Dovrebbe avere un nome che corrisponde al nome della proprietà CLR e termina con "Proprietà", ad es.Text
eTextProperty
Text
.Non aggiungere ulteriore logica al setter della proprietà CLR. Il sistema delle proprietà di dipendenza (e specificamente XAML) non utilizza la proprietà CLR. Se si desidera eseguire un'azione quando il valore della proprietà cambia, è necessario fornire una richiamata tramite
PropertyMetadata
:public static readonly DependencyProperty MyPropertyProperty = DependencyProperty.Register("MyProperty", typeof(int), typeof(MyControl), new PropertyMetadata(0, MyPropertyChangedHandler)); private static void MyPropertyChangedHandler(DependencyObject sender, DependencyPropertyChangedEventArgs args) { // Use args.OldValue and args.NewValue here as needed. // sender is the object whose property changed. // Some unboxing required. }
Modalità di rilegatura
Per eliminare la necessità di specificare Mode=TwoWay
in binding (simile al comportamento di TextBox.Text
), aggiornare il codice per utilizzare FrameworkPropertyMetadata
anziché PropertyMetadata
e specificare il flag appropriato:
public static readonly DependencyProperty MyPropertyProperty =
DependencyProperty.Register("MyProperty", typeof(int), typeof(MyControl),
new FrameworkPropertyMetadata(0, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault));
Proprietà di dipendenza allegate
Quando usare
Una proprietà associata è una proprietà di dipendenza che può essere applicata a qualsiasi DependencyObject
per migliorare il comportamento di vari controlli o servizi che sono a conoscenza dell'esistenza della proprietà.
Alcuni casi d'uso per le proprietà allegate includono:
- Avere un elemento genitore itera attraverso i suoi figli e agire sui bambini in un certo modo. Ad esempio, il controllo
Grid
utilizza leGrid.Row
Grid.Column
Grid.Row
,Grid.Column
,Grid.RowSpan
eGrid.ColumnSpan
per disporre gli elementi in righe e colonne. - Aggiunta di elementi visivi ai controlli esistenti con modelli personalizzati, ad esempio aggiungendo filigrane a caselle di testo vuote in tutta l'app senza dover
TextBox
sottoclasse diTextBox
. - Fornire un servizio o una funzionalità generica per alcuni o tutti i controlli esistenti, ad esempio
ToolTipService
oFocusManager
. Questi sono comunemente chiamati comportamenti allegati . - Quando è richiesta l'ereditarietà dell'albero visivo, ad esempio è simile al comportamento di
DataContext
.
Ciò dimostra ulteriormente cosa sta accadendo nel caso d'uso della Grid
:
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<Label Grid.Column="0" Content="Your Name:" />
<TextBox Grid.Column="1" Text="{Binding FirstName}" />
</Grid>
Grid.Column
non è una proprietà esistente su Label
o TextBox
. Piuttosto, il controllo Grid
esamina i suoi elementi figli e li dispone in base ai valori delle proprietà associate.
Come definire
Continueremo a utilizzare Grid
per questo esempio. La definizione di Grid.Column
è mostrata sotto, ma DependencyPropertyChangedEventHandler
è esclusa per brevità.
public static readonly DependencyProperty RowProperty =
DependencyProperty.RegisterAttached("Row", typeof(int), typeof(Grid),
new FrameworkPropertyMetadata(0, ...));
public static void SetRow(UIElement element, int value)
{
if (element == null)
throw new ArgumentNullException("element");
element.SetValue(RowProperty, value);
}
public static int GetRow(UIElement element)
{
if (element == null)
throw new ArgumentNullException("element");
return ((int)element.GetValue(RowProperty));
}
Poiché le proprietà associate possono essere associate a un'ampia varietà di elementi, non possono essere implementate come proprietà CLR. Al suo posto viene introdotta una coppia di metodi statici.
Quindi, a differenza delle proprietà di dipendenza standard, le proprietà associate possono anche essere definite in classi che non sono derivate da DependencyObject
.
Le stesse convenzioni di denominazione applicabili alle proprietà di dipendenza regolari si applicano anche qui: la proprietà di dipendenza RowProperty
ha i metodi corrispondenti GetRow
e SetRow
.
Avvertenze
Come documentato su MSDN :
Sebbene l'ereditarietà del valore della proprietà possa sembrare funzionare per le proprietà di dipendenza non collegate, il comportamento di ereditarietà per una proprietà non collegata tramite determinati limiti di elementi nell'albero di runtime non è definito. Usa sempre RegisterAttached per registrare le proprietà in cui si specifica Eredita nei metadati.
Proprietà di dipendenza di sola lettura
Quando usare
Una proprietà di dipendenza di sola lettura è simile a una normale proprietà di dipendenza, ma è strutturata in modo da non consentire l'impostazione del suo valore dall'esterno del controllo. Funziona bene se hai una proprietà che è puramente informativa per i consumatori, ad es. IsMouseOver
o IsKeyboardFocusWithin
.
Come definire
Proprio come le proprietà di dipendenza standard, una proprietà di dipendenza di sola lettura deve essere definita su una classe derivata da DependencyObject
.
public class MyControl : Control
{
private static readonly DependencyPropertyKey MyPropertyPropertyKey =
DependencyProperty.RegisterReadOnly("MyProperty", typeof(int), typeof(MyControl),
new FrameworkPropertyMetadata(0));
public static readonly DependencyProperty MyPropertyProperty = MyPropertyPropertyKey.DependencyProperty;
public int MyProperty
{
get { return (int)GetValue(MyPropertyProperty); }
private set { SetValue(MyPropertyPropertyKey, value); }
}
}
Le stesse convenzioni valide per le proprietà di dipendenza regolari si applicano anche qui, ma con due differenze chiave:
-
DependencyProperty
proviene daDependencyPropertyKey
private
. - Il setter della proprietà CLR è
protected
oprivate
anzichépublic
.
Notare che il setter passa a MyPropertyPropertyKey
e non a MyPropertyProperty
al metodo SetValue
. Poiché la proprietà è stata definita di sola lettura, qualsiasi tentativo di utilizzare SetValue
sulla proprietà deve essere utilizzato con overload che riceve DependencyPropertyKey
; in caso contrario, verrà generata InvalidOperationException
.