Jak utworzyć szablon dla kontrolki (WPF.NET)
Za pomocą Windows Presentation Foundation (WPF) można dostosować strukturę wizualizacji i zachowanie istniejącej kontrolki przy użyciu własnego szablonu wielokrotnego użytku. Szablony można stosować globalnie do aplikacji, okien i stron lub bezpośrednio do kontrolek. Większość scenariuszy, które wymagają utworzenia nowej kontrolki, może być objęta zamiast tego tworzenie nowego szablonu dla istniejącej kontrolki.
Ważne
Dokumentacja przewodnika po pulpicie dla platform .NET 6 i .NET 5 (w tym .NET Core 3.1) jest w trakcie budowy.
W tym artykule zapoznasz się z tworzeniem nowej ControlTemplate kontrolki Button .
Kiedy utworzyć kontrolkęTemplate
Kontrolki mają wiele właściwości, takich jak Background, Foregroundi FontFamily. Te właściwości kontrolują różne aspekty wyglądu kontrolki, ale zmiany, które można wprowadzić, ustawiając te właściwości, są ograniczone. Można na przykład ustawić Foreground właściwość na niebieską i FontStyle kursywę na .CheckBox Jeśli chcesz dostosować wygląd kontrolki poza ustawieniem innych właściwości kontrolki, możesz utworzyć element ControlTemplate.
W większości interfejsów użytkownika przycisk ma ten sam ogólny wygląd: prostokąt z tekstem. Jeśli chcesz utworzyć przycisk zaokrąglony, możesz utworzyć nową kontrolkę dziedziczą po przycisku lub odtworzyć funkcjonalność przycisku. Ponadto nowa kontrolka użytkownika zapewni wizualizację cykliczną.
Możesz uniknąć tworzenia nowych kontrolek, dostosowując układ wizualny istniejącej kontrolki. Za pomocą zaokrąglonego przycisku utworzysz ControlTemplate obiekt z żądanym układem wizualnym.
Z drugiej strony, jeśli potrzebujesz kontrolki z nowymi funkcjami, różnymi właściwościami i nowymi ustawieniami, utwórz nowy UserControlelement .
Wymagania wstępne
Utwórz nową aplikację WPF i w pliku MainWindow.xaml (lub innym wybranym oknie) ustaw następujące właściwości w <elemecie Window> :
| Właściwość | Wartość |
|---|---|
| Title | Template Intro Sample |
| SizeToContent | WidthAndHeight |
| MinWidth | 250 |
Ustaw zawartość <elementu Window> na następujący kod XAML:
<StackPanel Margin="10">
<Label>Unstyled Button</Label>
<Button>Button 1</Button>
<Label>Rounded Button</Label>
<Button>Button 2</Button>
</StackPanel>
W końcu plik MainWindow.xaml powinien wyglądać podobnie do następującego:
<Window x:Class="IntroToStylingAndTemplating.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:IntroToStylingAndTemplating"
mc:Ignorable="d"
Title="Template Intro Sample" SizeToContent="WidthAndHeight" MinWidth="250">
<StackPanel Margin="10">
<Label>Unstyled Button</Label>
<Button>Button 1</Button>
<Label>Rounded Button</Label>
<Button>Button 2</Button>
</StackPanel>
</Window>
Jeśli uruchomisz aplikację, wygląda następująco:
Tworzenie kontrolkiTemplate
Najczęstszym sposobem deklarowania elementu ControlTemplate jest zasób w sekcji w Resources pliku XAML. Ponieważ szablony są zasobami, są zgodne z tymi samymi regułami określania zakresu, które mają zastosowanie do wszystkich zasobów. Po prostu deklarowanie szablonu ma wpływ na miejsce zastosowania szablonu. Jeśli na przykład zadeklarujesz szablon w elemecie głównym pliku XAML definicji aplikacji, szablon może być używany w dowolnym miejscu w aplikacji. Jeśli zdefiniujesz szablon w oknie, tylko kontrolki w tym oknie mogą używać szablonu.
Aby rozpocząć od, dodaj Window.Resources element do pliku MainWindow.xaml :
<Window x:Class="IntroToStylingAndTemplating.Window2"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:IntroToStylingAndTemplating"
mc:Ignorable="d"
Title="Template Intro Sample" SizeToContent="WidthAndHeight" MinWidth="250">
<Window.Resources>
</Window.Resources>
<StackPanel Margin="10">
<Label>Unstyled Button</Label>
<Button>Button 1</Button>
<Label>Rounded Button</Label>
<Button>Button 2</Button>
</StackPanel>
</Window>
Utwórz nowy <element ControlTemplate> z następującymi właściwościami:
| Właściwość | Wartość |
|---|---|
| x:Key | roundbutton |
| TargetType | Button |
Ten szablon kontrolki będzie prosty:
- element główny kontrolki, a Grid
- , Ellipse aby narysować zaokrąglony wygląd przycisku
- a ContentPresenter , aby wyświetlić zawartość przycisku określonego przez użytkownika
<ControlTemplate x:Key="roundbutton" TargetType="Button">
<Grid>
<Ellipse Fill="{TemplateBinding Background}" Stroke="{TemplateBinding Foreground}" />
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center" />
</Grid>
</ControlTemplate>
SzablonBinding
Podczas tworzenia nowego ControlTemplateelementu nadal możesz chcieć użyć właściwości publicznych, aby zmienić wygląd kontrolki. Rozszerzenie znaczników TemplateBinding wiąże właściwość elementu, który znajduje się w ControlTemplate właściwości publicznej zdefiniowanej przez kontrolkę. W przypadku korzystania z szablonu TemplateBinding można włączyć właściwości kontrolki, aby działały jako parametry szablonu. Oznacza to, że gdy właściwość kontrolki jest ustawiona, ta wartość jest przekazywana do elementu, który ma na nim właściwość TemplateBinding .
Elipsa
Zwróć uwagę, że Fill właściwości <i elementu elipsy> są powiązane z właściwościami i Background kontrolkiForeground.Stroke
Contentpresenter
Element <ContentPresenter> jest również dodawany do szablonu. Ponieważ ten szablon jest przeznaczony dla przycisku, należy wziąć pod uwagę, że przycisk dziedziczy z ContentControlelementu . Przycisk przedstawia zawartość elementu. Możesz ustawić dowolny element wewnątrz przycisku, na przykład zwykły tekst, a nawet inną kontrolkę. Oba poniższe przyciski są prawidłowe:
<Button>My Text</Button>
<!-- and -->
<Button>
<CheckBox>Checkbox in a button</CheckBox>
</Button>
W obu poprzednich przykładach tekst i pole wyboru są ustawione jako właściwość Button.Content . Niezależnie od tego, co jest ustawione jako zawartość, można przedstawić za pomocą <elementu ContentPresenter>, co robi szablon.
Jeśli element ControlTemplate jest stosowany do ContentControl typu, takiego jak Button, ContentPresenter element jest wyszukiwany w drzewie elementów. Jeśli element ContentPresenter zostanie znaleziony, szablon automatycznie powiąże właściwość kontrolki Content z właściwością ContentPresenter.
Korzystanie z szablonu
Znajdź przyciski zadeklarowane na początku tego artykułu.
<StackPanel Margin="10">
<Label>Unstyled Button</Label>
<Button>Button 1</Button>
<Label>Rounded Button</Label>
<Button>Button 2</Button>
</StackPanel>
Ustaw właściwość drugiego roundbutton przycisku Template na zasób:
<StackPanel Margin="10">
<Label>Unstyled Button</Label>
<Button>Button 1</Button>
<Label>Rounded Button</Label>
<Button Template="{StaticResource roundbutton}">Button 2</Button>
</StackPanel>
Jeśli uruchomisz projekt i przyjrzysz się wynikowi, zobaczysz, że przycisk ma zaokrąglone tło.
Być może zauważyłeś, że przycisk nie jest okręgiem, ale jest niesymetryczny. Ze względu na sposób <działania elementu elipsy> zawsze rozszerza się, aby wypełnić dostępne miejsce. Ustaw okrąg jako jednolity, zmieniając width właściwości przycisku i height na tę samą wartość:
<StackPanel Margin="10">
<Label>Unstyled Button</Label>
<Button>Button 1</Button>
<Label>Rounded Button</Label>
<Button Template="{StaticResource roundbutton}" Width="65" Height="65">Button 2</Button>
</StackPanel>
Dodawanie wyzwalacza
Mimo że przycisk z zastosowanym szablonem wygląda inaczej, zachowuje się tak samo jak każdy inny przycisk. Po naciśnięciu przycisku Click zdarzenie zostanie wyzwolony. Jednak być może zauważysz, że po przeniesieniu myszy nad przyciskiem wizualizacje przycisku nie zmieniają się. Te interakcje wizualne są definiowane przez szablon.
Dzięki dynamicznym systemom zdarzeń i właściwości, które zapewnia WPF, można obserwować określoną właściwość dla wartości, a następnie w razie potrzeby ponownie stylować szablon. W tym przykładzie zobaczysz właściwość przycisku IsMouseOver . Gdy mysz jest nad kontrolką, styl <Ellipse> z nowym kolorem. Ten typ wyzwalacza jest znany jako WłaściwośćTrigger.
Aby można było to zrobić, musisz dodać nazwę do wielokropka>, do< którego możesz się odwoływać. Nadaj mu nazwę backgroundElement.
<Ellipse x:Name="backgroundElement" Fill="{TemplateBinding Background}" Stroke="{TemplateBinding Foreground}" />
Następnie dodaj nowy Trigger element do kolekcji ControlTemplate.Triggers . Wyzwalacz będzie obserwować IsMouseOver zdarzenie dla wartości true.
<ControlTemplate x:Key="roundbutton" TargetType="Button">
<Grid>
<Ellipse x:Name="backgroundElement" Fill="{TemplateBinding Background}" Stroke="{TemplateBinding Foreground}" />
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center" />
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="true">
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
Następnie dodaj <element Setter> do <wyzwalacza>, który zmienia właściwość <Fill wielokropka> na nowy kolor.
<Trigger Property="IsMouseOver" Value="true">
<Setter Property="Fill" TargetName="backgroundElement" Value="AliceBlue"/>
</Trigger>
Uruchom projekt. Zwróć uwagę, że po przeniesieniu myszy nad przyciskiem kolor <wielokropka> zmienia się.
Korzystanie z elementu VisualState
Stany wizualne są definiowane i wyzwalane przez kontrolkę. Na przykład po przeniesieniu myszy na wierzchu kontrolki CommonStates.MouseOver stan jest wyzwalany. Zmiany właściwości można animować na podstawie bieżącego stanu kontrolki. W poprzedniej sekcji <właściwośćTrigger> została użyta do zmiany pierwszego planu przycisku na AliceBlue wartość , gdy IsMouseOver właściwość miała wartość true. Zamiast tego utwórz stan wizualny, który animuje zmianę tego koloru, zapewniając płynne przejście. Aby uzyskać więcej informacji na temat visualStates, zobacz Style i szablony w WPF.
Aby przekonwertować element< PropertyTrigger> na animowany stan wizualizacji, najpierw usuń <element ControlTemplate.Triggers> z szablonu.
<ControlTemplate x:Key="roundbutton" TargetType="Button">
<Grid>
<Ellipse x:Name="backgroundElement" Fill="{TemplateBinding Background}" Stroke="{TemplateBinding Foreground}" />
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center" />
</Grid>
</ControlTemplate>
Następnie w <katalogu głównym siatki> szablonu kontrolki dodaj <element VisualStateManager.VisualStateGroups> z elementem< VisualStateGroup> for CommonStates. Zdefiniuj dwa stany Normal i MouseOver.
<ControlTemplate x:Key="roundbutton" TargetType="Button">
<Grid>
<VisualStateManager.VisualStateGroups>
<VisualStateGroup Name="CommonStates">
<VisualState Name="Normal">
</VisualState>
<VisualState Name="MouseOver">
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<Ellipse x:Name="backgroundElement" Fill="{TemplateBinding Background}" Stroke="{TemplateBinding Foreground}" />
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center" />
</Grid>
</ControlTemplate>
Wszystkie animacje zdefiniowane w elemecie VisualState> są stosowane po wyzwoleniu< tego stanu. Utwórz animacje dla każdego stanu. Animacje są umieszczane wewnątrz elementu scenorysu<>. Aby uzyskać więcej informacji na temat scenorysów, zobacz Storyboards Overview (Omówienie scenorysów).
Normalne
Ten stan animuje wypełnienie wielokropka, przywracając go do koloru kontrolki
Background.<Storyboard> <ColorAnimation Storyboard.TargetName="backgroundElement" Storyboard.TargetProperty="(Shape.Fill).(SolidColorBrush.Color)" To="{TemplateBinding Background}" Duration="0:0:0.3"/> </Storyboard>Mouseover
Ten stan animuje kolor wielokropka
Backgroundna nowy kolor:Yellow.<Storyboard> <ColorAnimation Storyboard.TargetName="backgroundElement" Storyboard.TargetProperty="(Shape.Fill).(SolidColorBrush.Color)" To="Yellow" Duration="0:0:0.3"/> </Storyboard>
KontrolkaTemplate<> powinna teraz wyglądać następująco.
<ControlTemplate x:Key="roundbutton" TargetType="Button">
<Grid>
<VisualStateManager.VisualStateGroups>
<VisualStateGroup Name="CommonStates">
<VisualState Name="Normal">
<Storyboard>
<ColorAnimation Storyboard.TargetName="backgroundElement"
Storyboard.TargetProperty="(Shape.Fill).(SolidColorBrush.Color)"
To="{TemplateBinding Background}"
Duration="0:0:0.3"/>
</Storyboard>
</VisualState>
<VisualState Name="MouseOver">
<Storyboard>
<ColorAnimation Storyboard.TargetName="backgroundElement"
Storyboard.TargetProperty="(Shape.Fill).(SolidColorBrush.Color)"
To="Yellow"
Duration="0:0:0.3"/>
</Storyboard>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<Ellipse Name="backgroundElement" Fill="{TemplateBinding Background}" Stroke="{TemplateBinding Foreground}" />
<ContentPresenter x:Name="contentPresenter" HorizontalAlignment="Center" VerticalAlignment="Center" />
</Grid>
</ControlTemplate>
Uruchom projekt. Zwróć uwagę, że po przeniesieniu myszy nad przyciskiem kolor <wielokropka> animuje.