Część 3. Rozszerzenia struktury znaczników XAML
Rozszerzenia znaczników XAML stanowią ważną funkcję w języku XAML, która umożliwia ustawianie właściwości na obiekty lub wartości, do których odwołuje się pośrednio z innych źródeł. Rozszerzenia znaczników XAML są szczególnie ważne w przypadku udostępniania obiektów i odwoływania się do stałych używanych w całej aplikacji, ale znajdują swoje największe narzędzie w powiązaniach danych.
Rozszerzenia struktury znaczników XAML
Ogólnie rzecz biorąc, język XAML służy do ustawiania właściwości obiektu na jawne wartości, takie jak ciąg, liczba, składowa wyliczenia lub ciąg, który jest konwertowany na wartość w tle.
Czasami jednak właściwości muszą odwoływać się do wartości zdefiniowanych w innym miejscu lub które mogą wymagać nieco przetwarzania przez kod w czasie wykonywania. W tych celach dostępne są rozszerzenia znaczników XAML.
Te rozszerzenia znaczników XAML nie są rozszerzeniami xml. XAML jest całkowicie legalny kod XML. Są one nazywane "rozszerzeniami", ponieważ są one wspierane przez kod w klasach, które implementują IMarkupExtension
. Możesz napisać własne niestandardowe rozszerzenia znaczników.
W wielu przypadkach rozszerzenia znaczników XAML są natychmiast rozpoznawalne w plikach XAML, ponieważ są one wyświetlane jako ustawienia atrybutów rozdzielane nawiasami klamrowymi: { i }, ale czasami rozszerzenia znaczników pojawiają się w znacznikach jako konwencjonalne elementy.
Współdzielone zasoby
Niektóre strony XAML zawierają kilka widoków z właściwościami ustawionymi na te same wartości. Na przykład wiele ustawień właściwości dla tych Button
obiektów jest takich samych:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="XamlSamples.SharedResourcesPage"
Title="Shared Resources Page">
<StackLayout>
<Button Text="Do this!"
HorizontalOptions="Center"
VerticalOptions="CenterAndExpand"
BorderWidth="3"
Rotation="-15"
TextColor="Red"
FontSize="24" />
<Button Text="Do that!"
HorizontalOptions="Center"
VerticalOptions="CenterAndExpand"
BorderWidth="3"
Rotation="-15"
TextColor="Red"
FontSize="24" />
<Button Text="Do the other thing!"
HorizontalOptions="Center"
VerticalOptions="CenterAndExpand"
BorderWidth="3"
Rotation="-15"
TextColor="Red"
FontSize="24" />
</StackLayout>
</ContentPage>
Jeśli należy zmienić jedną z tych właściwości, możesz wolisz wprowadzić zmianę tylko raz, a nie trzy razy. Gdyby był to kod, prawdopodobnie będziesz używać stałych i statycznych obiektów tylko do odczytu, aby zachować takie wartości spójne i łatwe do zmodyfikowania.
W języku XAML jednym z popularnych rozwiązań jest przechowywanie takich wartości lub obiektów w słowniku zasobów. Klasa VisualElement
definiuje właściwość o nazwie Resources
typu ResourceDictionary
, która jest słownikiem z kluczami typu string
i wartości typu object
. Można umieścić obiekty w tym słowniku, a następnie odwołać się do nich z znaczników, wszystkie w języku XAML.
Aby użyć słownika zasobów na stronie, dołącz parę tagów Resources
property-element. Najwygodniejsze jest umieszczenie ich w górnej części strony:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="XamlSamples.SharedResourcesPage"
Title="Shared Resources Page">
<ContentPage.Resources>
</ContentPage.Resources>
...
</ContentPage>
Należy również jawnie uwzględnić ResourceDictionary
tagi:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="XamlSamples.SharedResourcesPage"
Title="Shared Resources Page">
<ContentPage.Resources>
<ResourceDictionary>
</ResourceDictionary>
</ContentPage.Resources>
...
</ContentPage>
Teraz do słownika zasobów można dodawać obiekty i wartości różnych typów. Te typy muszą być tworzone wystąpienia. Nie mogą być na przykład klas abstrakcyjnych. Te typy muszą również mieć publiczny konstruktor bez parametrów. Każdy element wymaga klucza słownika określonego za pomocą atrybutu x:Key
. Na przykład:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="XamlSamples.SharedResourcesPage"
Title="Shared Resources Page">
<ContentPage.Resources>
<ResourceDictionary>
<LayoutOptions x:Key="horzOptions"
Alignment="Center" />
<LayoutOptions x:Key="vertOptions"
Alignment="Center"
Expands="True" />
</ResourceDictionary>
</ContentPage.Resources>
...
</ContentPage>
Te dwa elementy są wartościami typu LayoutOptions
struktury , a każdy z nich ma unikatowy klucz i jeden lub dwa zestaw właściwości. W kodzie i narzucie jest znacznie częściej używane statyczne pola LayoutOptions
, ale w tym miejscu bardziej wygodne jest ustawienie właściwości.
Teraz należy ustawić HorizontalOptions
właściwości i VerticalOptions
tych przycisków na te zasoby, a to zrobić za pomocą StaticResource
rozszerzenia znaczników XAML:
<Button Text="Do this!"
HorizontalOptions="{StaticResource horzOptions}"
VerticalOptions="{StaticResource vertOptions}"
BorderWidth="3"
Rotation="-15"
TextColor="Red"
FontSize="24" />
StaticResource
Rozszerzenie znaczników jest zawsze rozdzielane nawiasami klamrowymi i zawiera klucz słownika.
Nazwa StaticResource
odróżnia ją od DynamicResource
elementu , który Xamarin.Forms również obsługuje. DynamicResource
jest przeznaczony dla kluczy słownika skojarzonych z wartościami, które mogą ulec zmianie podczas wykonywania, podczas gdy StaticResource
są tworzone elementy ze słownika tylko raz.
BorderWidth
Dla właściwości należy przechowywać dwukrotnie w słowniku. Język XAML wygodnie definiuje tagi dla typowych typów danych, takich jak x:Double
i x:Int32
:
<ContentPage.Resources>
<ResourceDictionary>
<LayoutOptions x:Key="horzOptions"
Alignment="Center" />
<LayoutOptions x:Key="vertOptions"
Alignment="Center"
Expands="True" />
<x:Double x:Key="borderWidth">
3
</x:Double>
</ResourceDictionary>
</ContentPage.Resources>
Nie musisz umieszczać go w trzech wierszach. Ten wpis słownika dla tego kąta obrotu zajmuje tylko jeden wiersz:
<ContentPage.Resources>
<ResourceDictionary>
<LayoutOptions x:Key="horzOptions"
Alignment="Center" />
<LayoutOptions x:Key="vertOptions"
Alignment="Center"
Expands="True" />
<x:Double x:Key="borderWidth">
3
</x:Double>
<x:Double x:Key="rotationAngle">-15</x:Double>
</ResourceDictionary>
</ContentPage.Resources>
Te dwa zasoby można odwoływać się w taki sam sposób jak wartości LayoutOptions
:
<Button Text="Do this!"
HorizontalOptions="{StaticResource horzOptions}"
VerticalOptions="{StaticResource vertOptions}"
BorderWidth="{StaticResource borderWidth}"
Rotation="{StaticResource rotationAngle}"
TextColor="Red"
FontSize="24" />
W przypadku zasobów typu Color
można użyć tych samych reprezentacji ciągów, które są używane podczas bezpośredniego przypisywania atrybutów tych typów. Konwertery typów są wywoływane podczas tworzenia zasobu. Oto zasób typu Color
:
<Color x:Key="textColor">Red</Color>
Często programy ustawiają FontSize
właściwość na element członkowski NamedSize
wyliczenia, na przykład Large
. Klasa FontSizeConverter
działa za kulisami, aby przekonwertować ją na wartość zależną od platformy przy użyciu Device.GetNamedSized
metody . Jednak podczas definiowania zasobu rozmiaru czcionki warto użyć wartości liczbowej, jak pokazano tutaj jako x:Double
typ:
<x:Double x:Key="fontSize">24</x:Double>
Teraz wszystkie właściwości z wyjątkiem Text
są definiowane przez ustawienia zasobów:
<Button Text="Do this!"
HorizontalOptions="{StaticResource horzOptions}"
VerticalOptions="{StaticResource vertOptions}"
BorderWidth="{StaticResource borderWidth}"
Rotation="{StaticResource rotationAngle}"
TextColor="{StaticResource textColor}"
FontSize="{StaticResource fontSize}" />
Istnieje również możliwość użycia OnPlatform
w słowniku zasobów w celu zdefiniowania różnych wartości dla platform. Oto jak OnPlatform
obiekt może być częścią słownika zasobów dla różnych kolorów tekstu:
<OnPlatform x:Key="textColor"
x:TypeArguments="Color">
<On Platform="iOS" Value="Red" />
<On Platform="Android" Value="Aqua" />
<On Platform="UWP" Value="#80FF80" />
</OnPlatform>
Zwróć uwagę, że OnPlatform
zarówno atrybut, x:Key
ponieważ jest to obiekt w słowniku, jak i x:TypeArguments
atrybut, ponieważ jest to klasa ogólna. Atrybuty iOS
, Android
i UWP
są konwertowane na Color
wartości podczas inicjowania obiektu.
Oto końcowy kompletny plik XAML z trzema przyciskami, które uzyskują dostęp do sześciu wartości udostępnionych:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="XamlSamples.SharedResourcesPage"
Title="Shared Resources Page">
<ContentPage.Resources>
<ResourceDictionary>
<LayoutOptions x:Key="horzOptions"
Alignment="Center" />
<LayoutOptions x:Key="vertOptions"
Alignment="Center"
Expands="True" />
<x:Double x:Key="borderWidth">3</x:Double>
<x:Double x:Key="rotationAngle">-15</x:Double>
<OnPlatform x:Key="textColor"
x:TypeArguments="Color">
<On Platform="iOS" Value="Red" />
<On Platform="Android" Value="Aqua" />
<On Platform="UWP" Value="#80FF80" />
</OnPlatform>
<x:Double x:Key="fontSize">24</x:Double>
</ResourceDictionary>
</ContentPage.Resources>
<StackLayout>
<Button Text="Do this!"
HorizontalOptions="{StaticResource horzOptions}"
VerticalOptions="{StaticResource vertOptions}"
BorderWidth="{StaticResource borderWidth}"
Rotation="{StaticResource rotationAngle}"
TextColor="{StaticResource textColor}"
FontSize="{StaticResource fontSize}" />
<Button Text="Do that!"
HorizontalOptions="{StaticResource horzOptions}"
VerticalOptions="{StaticResource vertOptions}"
BorderWidth="{StaticResource borderWidth}"
Rotation="{StaticResource rotationAngle}"
TextColor="{StaticResource textColor}"
FontSize="{StaticResource fontSize}" />
<Button Text="Do the other thing!"
HorizontalOptions="{StaticResource horzOptions}"
VerticalOptions="{StaticResource vertOptions}"
BorderWidth="{StaticResource borderWidth}"
Rotation="{StaticResource rotationAngle}"
TextColor="{StaticResource textColor}"
FontSize="{StaticResource fontSize}" />
</StackLayout>
</ContentPage>
Zrzuty ekranu weryfikują spójny styl i styl zależny od platformy:
Chociaż najbardziej typowe jest zdefiniowanie Resources
kolekcji w górnej części strony, należy pamiętać, że Resources
właściwość jest definiowana przez VisualElement
element , a kolekcje można mieć Resources
na innych elementach na stronie. Na przykład spróbuj dodać jeden do elementu w tym przykładzie StackLayout
:
<StackLayout>
<StackLayout.Resources>
<ResourceDictionary>
<Color x:Key="textColor">Blue</Color>
</ResourceDictionary>
</StackLayout.Resources>
...
</StackLayout>
Dowiesz się, że kolor tekstu przycisków jest teraz niebieski. Zasadniczo za każdym razem, gdy analizator XAML napotka rozszerzenie znaczników, wyszukuje StaticResource
drzewo wizualne i używa pierwszego ResourceDictionary
napotkanego klucza.
Jednym z najpopularniejszych typów obiektów przechowywanych w słownikach zasobów jest Xamarin.FormsStyle
element , który definiuje kolekcję ustawień właściwości. Style zostały omówione w artykule Style.
Czasami deweloperzy nowi w języku XAML zastanawiają się, czy mogą umieścić element wizualny, taki jak Label
lub Button
w obiekcie ResourceDictionary
. Chociaż z pewnością jest to możliwe, nie ma sensu. Celem obiektu ResourceDictionary
jest udostępnianie obiektów. Nie można udostępnić elementu wizualizacji. To samo wystąpienie nie może być wyświetlane dwa razy na jednej stronie.
Rozszerzenie x:Static Markup
Pomimo podobieństw ich nazw x:Static
i StaticResource
są bardzo różne. StaticResource
Zwraca obiekt ze słownika zasobów, gdy x:Static
uzyskuje dostęp do jednego z następujących elementów:
- publiczne pole statyczne
- publiczna właściwość statyczna
- pole stałej publicznej
- element członkowski wyliczenia.
StaticResource
Rozszerzenie znaczników jest obsługiwane przez implementacje XAML, które definiują słownik zasobów, podczas gdy x:Static
jest wewnętrzną częścią XAML, jak x
ujawnia prefiks.
Oto kilka przykładów, które pokazują, jak x:Static
jawnie odwoływać się do pól statycznych i elementów członkowskich wyliczenia:
<Label Text="Hello, XAML!"
VerticalOptions="{x:Static LayoutOptions.Start}"
HorizontalTextAlignment="{x:Static TextAlignment.Center}"
TextColor="{x:Static Color.Aqua}" />
Do tej pory nie jest to bardzo imponujące. x:Static
Jednak rozszerzenie znaczników może również odwoływać się do pól statycznych lub właściwości z własnego kodu. Na przykład oto AppConstants
klasa zawierająca niektóre pola statyczne, których można użyć na wielu stronach w całej aplikacji:
using System;
using Xamarin.Forms;
namespace XamlSamples
{
static class AppConstants
{
public static readonly Thickness PagePadding;
public static readonly Font TitleFont;
public static readonly Color BackgroundColor = Color.Aqua;
public static readonly Color ForegroundColor = Color.Brown;
static AppConstants()
{
switch (Device.RuntimePlatform)
{
case Device.iOS:
PagePadding = new Thickness(5, 20, 5, 0);
TitleFont = Font.SystemFontOfSize(35, FontAttributes.Bold);
break;
case Device.Android:
PagePadding = new Thickness(5, 0, 5, 0);
TitleFont = Font.SystemFontOfSize(40, FontAttributes.Bold);
break;
case Device.UWP:
PagePadding = new Thickness(5, 0, 5, 0);
TitleFont = Font.SystemFontOfSize(50, FontAttributes.Bold);
break;
}
}
}
}
Aby odwołać się do pól statycznych tej klasy w pliku XAML, musisz w jakiś sposób wskazać w pliku XAML, w którym znajduje się ten plik. Należy to zrobić za pomocą deklaracji przestrzeni nazw XML.
Pamiętaj, że pliki XAML utworzone w ramach standardowego Xamarin.Forms szablonu XAML zawierają dwie deklaracje przestrzeni nazw XML: jedną do uzyskiwania Xamarin.Forms dostępu do klas, a drugą do odwoływania się do tagów i atrybutów wewnętrznych języka XAML:
xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
Aby uzyskać dostęp do innych klas, potrzebne będą dodatkowe deklaracje przestrzeni nazw XML. Każda dodatkowa deklaracja przestrzeni nazw XML definiuje nowy prefiks. Aby uzyskać dostęp do klas lokalnych w bibliotece .NET Standard aplikacji udostępnionej, takiej jak AppConstants
, programiści XAML często używają prefiksu local
. Deklaracja przestrzeni nazw musi wskazywać nazwę przestrzeni nazw CLR (środowisko uruchomieniowe języka wspólnego), znaną również jako nazwa przestrzeni nazw platformy .NET, która jest nazwą wyświetlaną w definicji języka C# namespace
lub w using
dyrektywie:
xmlns:local="clr-namespace:XamlSamples"
Można również zdefiniować deklaracje przestrzeni nazw XML dla przestrzeni nazw platformy .NET w dowolnym zestawie, do którego odwołuje się biblioteka .NET Standard. Na przykład poniżej sys
przedstawiono prefiks dla standardowej przestrzeni nazw platformy .NET System
, która znajduje się w zestawie netstandard . Ponieważ jest to inny zestaw, należy również określić nazwę zestawu, w tym przypadku netstandard:
xmlns:sys="clr-namespace:System;assembly=netstandard"
Zwróć uwagę, że słowo kluczowe clr-namespace
następuje dwukropkiem, a następnie nazwa przestrzeni nazw platformy .NET, po którym następuje średnik, słowo kluczowe assembly
, znak równości i nazwa zestawu.
Tak, dwukropek następuje clr-namespace
, ale znak równości jest zgodny z assembly
. Składnia została zdefiniowana w ten sposób celowo: większość deklaracji przestrzeni nazw XML odwołuje się do identyfikatora URI, który rozpoczyna nazwę schematu identyfikatora URI, na przykład http
, po którym zawsze następuje dwukropek. Część clr-namespace
tego ciągu ma naśladować tę konwencję.
Oba te deklaracje przestrzeni nazw są uwzględnione w przykładzie StaticConstantsPage . Zwróć uwagę, że BoxView
wymiary są ustawione na Math.PI
i Math.E
, ale skalowane według współczynnika 100:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:XamlSamples"
xmlns:sys="clr-namespace:System;assembly=netstandard"
x:Class="XamlSamples.StaticConstantsPage"
Title="Static Constants Page"
Padding="{x:Static local:AppConstants.PagePadding}">
<StackLayout>
<Label Text="Hello, XAML!"
TextColor="{x:Static local:AppConstants.BackgroundColor}"
BackgroundColor="{x:Static local:AppConstants.ForegroundColor}"
Font="{x:Static local:AppConstants.TitleFont}"
HorizontalOptions="Center" />
<BoxView WidthRequest="{x:Static sys:Math.PI}"
HeightRequest="{x:Static sys:Math.E}"
Color="{x:Static local:AppConstants.ForegroundColor}"
HorizontalOptions="Center"
VerticalOptions="CenterAndExpand"
Scale="100" />
</StackLayout>
</ContentPage>
Rozmiar wynikowego BoxView
względem ekranu jest zależny od platformy:
Inne standardowe rozszerzenia znaczników
Kilka rozszerzeń znaczników jest wewnętrznych dla języka XAML i obsługiwanych w Xamarin.Forms plikach XAML. Niektóre z nich nie są używane bardzo często, ale są niezbędne, gdy ich potrzebujesz:
- Jeśli właściwość ma wartość inną niż
null
domyślna, ale chcesz ją ustawić nanull
, ustaw ją na{x:Null}
rozszerzenie znaczników. - Jeśli właściwość jest typu
Type
, można przypisać ją doType
obiektu przy użyciu rozszerzenia{x:Type someClass}
znaczników . - Tablice w języku XAML można definiować przy użyciu
x:Array
rozszerzenia znaczników. To rozszerzenie znaczników ma wymagany atrybut o nazwieType
, który wskazuje typ elementów w tablicy. - Rozszerzenie
Binding
znaczników zostało omówione w części 4. Podstawy powiązań danych. - Rozszerzenie
RelativeSource
znaczników jest omawiane w powiązaniach względnych.
Rozszerzenie znaczników ConstraintExpression
Rozszerzenia znaczników mogą mieć właściwości, ale nie są ustawione tak jak atrybuty XML. W rozszerzeniu znaczników ustawienia właściwości są oddzielone przecinkami, a żadne znaki cudzysłowu nie są wyświetlane w nawiasach klamrowych.
Można to zilustrować Xamarin.Forms za pomocą rozszerzenia znaczników o nazwie ConstraintExpression
, który jest używany z klasą RelativeLayout
. Możesz określić lokalizację lub rozmiar widoku podrzędnego jako stałą lub względem nadrzędnego lub innego nazwanego widoku. Składnia obiektu ConstraintExpression
umożliwia ustawienie położenia lub rozmiaru widoku przy użyciu właściwości times innego Factor
widoku oraz Constant
. Cokolwiek bardziej złożonego niż wymaga to kodu.
Oto przykład:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="XamlSamples.RelativeLayoutPage"
Title="RelativeLayout Page">
<RelativeLayout>
<!-- Upper left -->
<BoxView Color="Red"
RelativeLayout.XConstraint=
"{ConstraintExpression Type=Constant,
Constant=0}"
RelativeLayout.YConstraint=
"{ConstraintExpression Type=Constant,
Constant=0}" />
<!-- Upper right -->
<BoxView Color="Green"
RelativeLayout.XConstraint=
"{ConstraintExpression Type=RelativeToParent,
Property=Width,
Factor=1,
Constant=-40}"
RelativeLayout.YConstraint=
"{ConstraintExpression Type=Constant,
Constant=0}" />
<!-- Lower left -->
<BoxView Color="Blue"
RelativeLayout.XConstraint=
"{ConstraintExpression Type=Constant,
Constant=0}"
RelativeLayout.YConstraint=
"{ConstraintExpression Type=RelativeToParent,
Property=Height,
Factor=1,
Constant=-40}" />
<!-- Lower right -->
<BoxView Color="Yellow"
RelativeLayout.XConstraint=
"{ConstraintExpression Type=RelativeToParent,
Property=Width,
Factor=1,
Constant=-40}"
RelativeLayout.YConstraint=
"{ConstraintExpression Type=RelativeToParent,
Property=Height,
Factor=1,
Constant=-40}" />
<!-- Centered and 1/3 width and height of parent -->
<BoxView x:Name="oneThird"
Color="Red"
RelativeLayout.XConstraint=
"{ConstraintExpression Type=RelativeToParent,
Property=Width,
Factor=0.33}"
RelativeLayout.YConstraint=
"{ConstraintExpression Type=RelativeToParent,
Property=Height,
Factor=0.33}"
RelativeLayout.WidthConstraint=
"{ConstraintExpression Type=RelativeToParent,
Property=Width,
Factor=0.33}"
RelativeLayout.HeightConstraint=
"{ConstraintExpression Type=RelativeToParent,
Property=Height,
Factor=0.33}" />
<!-- 1/3 width and height of previous -->
<BoxView Color="Blue"
RelativeLayout.XConstraint=
"{ConstraintExpression Type=RelativeToView,
ElementName=oneThird,
Property=X}"
RelativeLayout.YConstraint=
"{ConstraintExpression Type=RelativeToView,
ElementName=oneThird,
Property=Y}"
RelativeLayout.WidthConstraint=
"{ConstraintExpression Type=RelativeToView,
ElementName=oneThird,
Property=Width,
Factor=0.33}"
RelativeLayout.HeightConstraint=
"{ConstraintExpression Type=RelativeToView,
ElementName=oneThird,
Property=Height,
Factor=0.33}" />
</RelativeLayout>
</ContentPage>
Być może najważniejszą lekcją, którą należy wziąć z tego przykładu, jest składnia rozszerzenia znaczników znaczników: w nawiasach klamrowych rozszerzenia znaczników nie muszą być wyświetlane znaki cudzysłowu. Podczas wpisywania rozszerzenia znaczników w pliku XAML naturalne jest ujęcie wartości właściwości w cudzysłów. Oprzeć się pokusie!
Oto uruchomiony program:
Podsumowanie
Rozszerzenia znaczników XAML pokazane tutaj zapewniają ważną obsługę plików XAML. Ale być może najcenniejsze rozszerzenie znaczników XAML to Binding
, które zostało omówione w następnej części tej serii, część 4. Podstawy powiązań danych.