wpf
Właściwości zależności
Szukaj…
Wprowadzenie
Właściwości zależności są rodzajem właściwości, które rozszerzają właściwość CLR. Podczas gdy właściwość CLR jest odczytywana bezpośrednio od członka klasy, właściwość zależności będzie dynamicznie rozstrzygana podczas wywoływania metody GetValue (), którą Twój obiekt uzyskuje dzięki dziedziczeniu z podstawowej klasy DependencyObject.
Ta sekcja podzieli właściwości zależności i wyjaśni ich użycie zarówno koncepcyjnie, jak i na przykładach kodu.
Składnia
- DependencyProperty.Register (nazwa ciągu, TypeTypeType, TypeTypeType)
- DependencyProperty.Register (nazwa ciągu, TypeTypeType, Type ownerType, PropertyMetadata typeMetadata)
- DependencyProperty.Register (nazwa ciągu, typ typeType, typ ownerType, PropertyMetadata typeMetadata, ValidateValueCallback validateValueCallback)
- DependencyProperty.RegisterAttached (nazwa ciągu, TypeTypeType, TypeTypeType)
- DependencyProperty.RegisterAttached (nazwa ciągu, typ propertyType, typ ownerType, PropertyMetadata typeMetadata)
- DependencyProperty.RegisterAttached (nazwa ciągu, typ propertyType, typ ownerType, PropertyMetadata typeMetadata, ValidateValueCallback validateValueCallback)
- DependencyProperty.RegisterReadOnly (nazwa ciągu, typ propertyType, typ ownerType, PropertyMetadata typeMetadata)
- DependencyProperty.RegisterReadOnly (nazwa ciągu, typ propertyType, typ ownerType, PropertyMetadata typeMetadata, ValidateValueCallback validateValueCallback)
- DependencyProperty.RegisterAttachedReadOnly (nazwa ciągu, typ propertyType, typ ownerType, PropertyMetadata typeMetadata)
- DependencyProperty.RegisterAttachedReadOnly (nazwa ciągu, typ propertyType, typ ownerType, PropertyMetadata typeMetadata, ValidateValueCallback validateValueCallback)
Parametry
Parametr | Detale |
---|---|
Nazwa | String reprezentujący nazwę właściwości |
Typ nieruchomości | Type właściwości, np. typeof(int) |
ownerType | Type klasy, w której definiowana jest właściwość, np. typeof(MyControl) lub typeof(MyAttachedProperties) . |
typeMetadata | Wystąpienie System.Windows.PropertyMetadata (lub jednej z jego podklas), które definiuje wartości domyślne, wywołania zwrotne zmienione właściwości, FrameworkPropertyMetadata pozwala zdefiniować opcje wiązania, takie jak System.Windows.Data.BindingMode.TwoWay . |
validateValueCallback | Niestandardowe wywołanie zwrotne, które zwraca true, jeśli nowa wartość właściwości jest poprawna, w przeciwnym razie false. |
Standardowe właściwości zależności
Kiedy użyć
Praktycznie wszystkie kontrolki WPF intensywnie wykorzystują właściwości zależności. Właściwość zależności pozwala na korzystanie z wielu funkcji WPF, które nie są możliwe w przypadku samych standardowych właściwości CLR, w tym między innymi obsługę stylów, animacji, powiązania danych, dziedziczenia wartości i powiadomień o zmianach.
Właściwość TextBox.Text
jest prostym przykładem tego, gdzie potrzebna jest standardowa właściwość zależności. W tym przypadku powiązanie danych nie byłoby możliwe, gdyby Text
był standardową właściwością CLR.
<TextBox Text="{Binding FirstName}" />
Jak zdefiniować
Właściwości zależności można zdefiniować tylko w klasach pochodzących z DependencyObject
, takich jak FrameworkElement
, Control
itp.
Jednym z najszybszych sposobów utworzenia standardowej właściwości zależności bez konieczności pamiętania składni jest użycie fragmentu „propdp”, wpisując propdp
a następnie naciskając klawisz Tab . Zostanie wstawiony fragment kodu, który można następnie zmodyfikować zgodnie z własnymi potrzebami:
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));
}
Powinieneś tabulować różne części fragmentu kodu, aby wprowadzić niezbędne zmiany, w tym zaktualizować nazwę właściwości, typ właściwości, typ klasy i wartość domyślną.
Ważne konwencje
Istnieje kilka ważnych konwencji / zasad, których należy przestrzegać:
Utwórz właściwość CLR dla właściwości zależności. Ta właściwość jest używana w kodzie obiektu lub przez innych konsumentów. Powinien wywoływać
GetValue
iSetValue
aby konsumenci nie musieli.Nazwij właściwość zależności poprawnie. Pole
DependencyProperty
powinno byćpublic static readonly
. Powinien mieć nazwę, która odpowiada nazwie właściwości CLR i kończy się na „Właściwość”, np.Text
iTextProperty
.Nie dodawaj dodatkowej logiki do ustawiacza właściwości CLR. System właściwości zależności (a konkretnie XAML) nie korzysta z właściwości CLR. Jeśli chcesz wykonać akcję, gdy zmieni się wartość właściwości, musisz podać wywołanie zwrotne za pośrednictwem
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. }
Tryb wiązania
Aby wyeliminować potrzebę określania Mode=TwoWay
w powiązaniach (podobnie jak zachowanie TextBox.Text
), zaktualizuj kod, aby używał FrameworkPropertyMetadata
zamiast PropertyMetadata
i określ odpowiednią flagę:
public static readonly DependencyProperty MyPropertyProperty =
DependencyProperty.Register("MyProperty", typeof(int), typeof(MyControl),
new FrameworkPropertyMetadata(0, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault));
Dołączone właściwości zależności
Kiedy użyć
Załączona właściwość jest właściwością zależności, którą można zastosować do dowolnego obiektu DependencyObject
celu poprawy zachowania różnych elementów sterujących lub usług, które są świadome istnienia tej właściwości.
Niektóre przypadki użycia dołączonych właściwości obejmują:
- Posiadanie elementu rodzica iteruje przez swoje dzieci i działa na nie w określony sposób. Na przykład formant
Grid
korzysta zGrid.Row
,Grid.Column
,Grid.RowSpan
iGrid.ColumnSpan
, aby uporządkować elementy w wierszach i kolumnach. - Dodawanie elementów wizualnych do istniejących kontrolek za pomocą niestandardowych szablonów, np. Dodawanie znaków wodnych do pustych pól tekstowych w całej aplikacji bez konieczności podklasy
TextBox
. - Zapewnienie ogólnej usługi lub funkcji dla niektórych lub wszystkich istniejących formantów, np.
ToolTipService
lubFocusManager
. Są to powszechnie określane jako zachowania przywiązane . - Podczas dziedziczenia w dół wymagane jest drzewo wizualne, np. Podobnie jak zachowanie
DataContext
.
To dodatkowo pokazuje, co dzieje się w przypadku użycia 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
nie jest właściwością istniejącą w Label
lub TextBox
. Kontrolka Grid
raczej przegląda elementy potomne i układa je zgodnie z wartościami dołączonych właściwości.
Jak zdefiniować
W tym przykładzie będziemy nadal używać Grid
. Definicja Grid.Column
jest pokazana poniżej, ale DependencyPropertyChangedEventHandler
jest wykluczony ze względu na zwięzłość.
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));
}
Ponieważ dołączone właściwości mogą być dołączone do wielu różnych elementów, nie można ich zaimplementować jako właściwości CLR. Zamiast tego wprowadzono parę metod statycznych.
Dlatego, w przeciwieństwie do standardowych właściwości zależności, właściwości dołączone można również zdefiniować w klasach, które nie pochodzą z DependencyObject
.
Obowiązują tu również te same konwencje nazewnictwa, które mają zastosowanie do zwykłych właściwości zależności: właściwość zależności RowProperty
ma odpowiednie metody GetRow
i SetRow
.
Ostrzeżenia
Jak udokumentowano na MSDN :
Chociaż może wydawać się, że dziedziczenie wartości właściwości działa w przypadku niepowiązanych właściwości zależności, zachowanie dziedziczenia w przypadku nieprzyłączonej właściwości przez pewne granice elementów w drzewie wykonawczym jest niezdefiniowane. Zawsze używaj RegisterAttached do rejestrowania właściwości, w których określasz Dziedziczenia w metadanych.
Właściwości zależności tylko do odczytu
Kiedy użyć
Właściwość zależności tylko do odczytu jest podobna do normalnej właściwości zależności, ale jest tak skonstruowana, aby nie zezwalać na ustawianie jej wartości poza kontrolą. Działa to dobrze, jeśli mają właściwość, która ma charakter wyłącznie informacyjny dla konsumentów, np IsMouseOver
lub IsKeyboardFocusWithin
.
Jak zdefiniować
Podobnie jak standardowe właściwości zależności, właściwość zależności tylko do odczytu musi zostać zdefiniowana w klasie wywodzącej się z 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); }
}
}
Obowiązują tu również te same konwencje, które dotyczą normalnych właściwości zależności, ale z dwiema kluczowymi różnicami:
-
DependencyProperty
pochodzi zprivate
DependencyPropertyKey
. - Narzędzie do ustawiania właściwości CLR jest
protected
lubprivate
zamiastpublic
.
Zauważ, że ustawiający przekazuje MyPropertyPropertyKey
a nie MyPropertyProperty
do metody SetValue
. Ponieważ właściwość została zdefiniowana jako tylko do odczytu, każda próba użycia SetValue
we właściwości musi być używana z przeciążeniem, które otrzymuje DependencyPropertyKey
; w przeciwnym razie zostanie InvalidOperationException
.