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:

  1. 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 e SetValue modo che i consumatori non debbano farlo.

  2. Assegna un nome alla proprietà di dipendenza correttamente. Il campo DependencyProperty dovrebbe essere public static readonly . Dovrebbe avere un nome che corrisponde al nome della proprietà CLR e termina con "Proprietà", ad es. Text e TextProperty Text .

  3. 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:

  1. Avere un elemento genitore itera attraverso i suoi figli e agire sui bambini in un certo modo. Ad esempio, il controllo Grid utilizza le Grid.Row Grid.Column Grid.Row , Grid.Column , Grid.RowSpan e Grid.ColumnSpan per disporre gli elementi in righe e colonne.
  2. 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 di TextBox .
  3. Fornire un servizio o una funzionalità generica per alcuni o tutti i controlli esistenti, ad esempio ToolTipService o FocusManager . Questi sono comunemente chiamati comportamenti allegati .
  4. 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:

  1. DependencyProperty proviene da DependencyPropertyKey private .
  2. Il setter della proprietà CLR è protected o private 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 .



Modified text is an extract of the original Stack Overflow Documentation
Autorizzato sotto CC BY-SA 3.0
Non affiliato con Stack Overflow