Notatka
Dostęp do tej strony wymaga autoryzacji. Może spróbować zalogować się lub zmienić katalogi.
Dostęp do tej strony wymaga autoryzacji. Możesz spróbować zmienić katalogi.
Za pomocą programu Windows Presentation Foundation (WPF) można dostosować strukturę 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. W większości scenariuszy, które wymagają utworzenia nowej kontrolki, można zamiast tego utworzyć nowy szablon dla istniejącej kontrolki.
W tym artykule przedstawiono tworzenie nowej ControlTemplate kontrolki Button .
Kiedy utworzyć szablon kontrolki
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ć właściwość Foreground 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ć 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ącą po przycisku lub odtworzyć funkcjonalność przycisku. Ponadto nowa kontrolka użytkownika udostępnia wizualizację cykliczną.
Możesz uniknąć tworzenia nowych kontrolek, dostosowując układ wizualny istniejącej kontrolki. W przypadku przycisku zaokrąglonego należy utworzyć obiekt ControlTemplate z żądanym układem wizualnym.
Z drugiej strony, jeśli potrzebujesz kontrolki z nową funkcjonalnością, różnymi właściwościami i nowymi ustawieniami, utworzysz nowy UserControlelement .
Wymagania wstępne
Utwórz nową aplikację WPF. W pliku MainWindow.xaml (lub innym wybranym oknie) ustaw następujące właściwości w elemecie <Window> :
| Majątek | Wartość |
|---|---|
| Title | Template Intro Sample |
| SizeToContent | WidthAndHeight |
| MinWidth | 250 |
Ustaw zawartość elementu okna <> 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>
Na końcu plik MainWindow.xaml powinien wyglądać podobnie do następującego kodu XAML:
<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 to jak na poniższej ilustracji:
Utwórz ControlTemplate
Najczęstszym sposobem deklarowania ControlTemplate jest jako zasób w sekcji Resources w pliku XAML. Ponieważ szablony są zasobami, są zgodne z tymi samymi regułami określania zakresu co wszystkie zasoby. Miejsce, w którym deklarujesz szablon, wpływa na to, gdzie możesz go zastosować. Jeśli na przykład zadeklarujesz szablon w elemecie głównym pliku XAML definicji aplikacji, możesz użyć szablonu w dowolnym miejscu w aplikacji. Jeśli zdefiniujesz szablon w oknie, tylko kontrolki w tym oknie mogą używać szablonu.
Aby rozpocząć, 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 nową <kontrolkę ControlTemplate> i ustaw następujące właściwości:
| Majątek | Wartość |
|---|---|
| x:Key | roundbutton |
| TargetType | Button |
Ten szablon kontrolki jest prosty:
- element główny dla kontrolki, Grid
- Ellipse do rysowania zaokrąglonego wyglądu przycisku
- ContentPresenter do wyświetlania zawartości przycisku wskazanego przez użytkownika
<ControlTemplate x:Key="roundbutton" TargetType="Button">
<Grid>
<Ellipse Fill="{TemplateBinding Background}" Stroke="{TemplateBinding Foreground}" />
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center" />
</Grid>
</ControlTemplate>
Powiązanie szablonu
Podczas tworzenia nowego ControlTemplateelementu możesz nadal 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 z publiczną właściwością definiowaną przez kontrolkę. W przypadku używania TemplateBindingmożna włączyć właściwości kontrolki tak, aby działały jako parametry szablonu. Po ustawieniu właściwości kontrolki wartość jest przekazywana do elementu, który ma właściwość TemplateBinding.
Elipsa
Prezenter treści
Szablon zawiera <również element ContentPresenter> . Ponieważ ten szablon jest przeznaczony dla przycisku, należy pamiętać, że przycisk dziedziczy z ContentControl. Przycisk wyświetla zawartość elementu. Możesz ustawić dowolne elementy wewnątrz przycisku, takie jak zwykły tekst, a nawet inna kontrolka. Oba poniższe przykłady są prawidłowymi przyciskami:
<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że być ona prezentowana za pomocą <ContentPresenter>, co robi właśnie szablon.
Jeśli zastosujesz ControlTemplate na typ ContentControl, taki jak Button, szablon szuka ContentPresenter w drzewie elementów. Jeśli znajdzie ContentPresenterelement , szablon automatycznie powiąże właściwość kontrolki Content z elementem 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ść Template drugiego przycisku na zasób roundbutton:
<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.
Możesz zauważyć, że przycisk nie jest okręgiem, ale jest niesymetryczny. Ze względu na sposób działania elementu <wielokropka> zawsze rozszerza się, aby wypełnić dostępne miejsce. Ustaw okrąg jako jednolity, zmieniając width i height właściwości przycisku 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 zostanie wywołane zdarzenie Click. Można jednak zauważyć, że po przeniesieniu myszy nad przyciskiem wizualizacje przycisku nie ulegają zmianie. Szablon definiuje te interakcje wizualne.
Korzystając z dynamicznych systemów zdarzeń i właściwości zapewnianych przez 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 obserwujesz właściwość przycisku IsMouseOver . Gdy mysz znajduje się nad kontrolką, zmień styl <elipsy> na nowy kolor. Ten typ wyzwalacza jest znany jako PropertyTrigger.
Aby ta funkcja działała, należy dodać nazwę do <elipsy>, do której można się odwołać. Nadaj mu nazwę backgroundElement.
<Ellipse x:Name="backgroundElement" Fill="{TemplateBinding Background}" Stroke="{TemplateBinding Foreground}" />
Następnie dodaj nową Trigger do kolekcji ControlTemplate.Triggers. Wyzwalacz obserwuje zdarzenie IsMouseOver pod kątem 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 <Setter> do <wyzwalacza>, który zmienia właściwość Fill obiektu <elipsa> na nowy kolor.
<Trigger Property="IsMouseOver" Value="true">
<Setter Property="Fill" TargetName="backgroundElement" Value="AliceBlue"/>
</Trigger>
Uruchamianie projektu. Po przeniesieniu myszy na przycisk zmienia się kolor <elipsy>.
Korzystanie z elementu VisualState
Stany wizualne są definiowane i wyzwalane przez kontrolkę. Na przykład, po przeniesieniu myszy nad elementem sterującym, element sterujący wyzwala CommonStates.MouseOver stan. Możesz animować zmiany właściwości na podstawie bieżącego stanu kontrolki. W poprzedniej sekcji użyto <PropertyTrigger>, aby zmienić tło przycisku na AliceBlue, gdy właściwość IsMouseOver była ustawiona na 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 WPF Style i szablony.
Aby przekonwertować element <PropertyTrigger> na animowany stan wizualizacji, 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 <Grid> głównej części szablonu kontrolki dodaj element <VisualStateManager.VisualStateGroups> z <VisualStateGroup> dla 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>
Zastosuj wszelkie animacje zdefiniowane w <VisualState>, gdy ten stan zostanie wyzwolony. Tworzenie animacji dla każdego stanu. Umieść animacje wewnątrz elementu scenorysu<>. Aby uzyskać więcej informacji na temat scenorysów, zobacz Storyboards Overview.
Standardowy
Ten stan animuje wypełnienie elipsy, przywracając kolor
Backgrounddo kontrolki.<Storyboard> <ColorAnimation Storyboard.TargetName="backgroundElement" Storyboard.TargetProperty="(Shape.Fill).(SolidColorBrush.Color)" To="{TemplateBinding Background}" Duration="0:0:0.3"/> </Storyboard>Najechanie kursorem
Ten stan animuje elipsę
Background, zmieniając jej kolor na:Yellow.<Storyboard> <ColorAnimation Storyboard.TargetName="backgroundElement" Storyboard.TargetProperty="(Shape.Fill).(SolidColorBrush.Color)" To="Yellow" Duration="0:0:0.3"/> </Storyboard>
Element <ControlTemplate> powinien teraz wyglądać podobnie do poniższego kodu.
<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>
Uruchamianie projektu. Po przeniesieniu myszy na przycisku kolor <Elipsy> animuje.
Dalsze kroki
.NET Desktop feedback