WPF - Szybki przewodnik
WPF oznacza Windows Presentation Foundation. Jest to potężny framework do tworzenia aplikacji Windows. W tym samouczku wyjaśniono funkcje, które należy zrozumieć, aby tworzyć aplikacje WPF, oraz sposób, w jaki wprowadza to fundamentalną zmianę w aplikacjach systemu Windows.
WPF został najpierw wprowadzony w wersji .NET Framework 3.0, a następnie wiele innych funkcji zostało dodanych w kolejnych wersjach .NET Framework.
Architektura WPF
Przed WPF inne struktury interfejsu użytkownika oferowane przez firmę Microsoft, takie jak formularze MFC i Windows, były tylko otokami wokół bibliotek DLL User32 i GDI32, ale WPF tylko w minimalnym stopniu wykorzystuje User32. Więc,
- WPF to coś więcej niż tylko opakowanie.
- Jest częścią platformy .NET.
- Zawiera mieszankę kodu zarządzanego i niezarządzanego.
Główne składniki architektury WPF są pokazane na poniższym rysunku. Najważniejszą częścią kodu WPF są -
- Struktura prezentacji
- Rdzeń prezentacji
- Milcore
Plik presentation framework i presentation core zostały napisane w kodzie zarządzanym. Milcore jest częścią niezarządzanego kodu, która umożliwia ścisłą integrację z DirectX (odpowiedzialnym za wyświetlanie i renderowanie). CLR sprawia, że proces rozwoju jest bardziej produktywny, oferując wiele funkcji, takich jak zarządzanie pamięcią, obsługa błędów itp.
WPF - Zalety
We wcześniejszych strukturach GUI nie było rzeczywistego oddzielenia między wyglądem aplikacji a jej zachowaniem. Zarówno GUI, jak i zachowanie zostały stworzone w tym samym języku, np. C # lub VB.Net, co wymagałoby od programisty więcej wysiłku, aby zaimplementować zarówno interfejs użytkownika, jak i związane z nim zachowanie.
W WPF elementy interfejsu użytkownika są projektowane w języku XAML, podczas gdy zachowania można implementować w językach proceduralnych, takich jak C # i VB.Net. Dlatego bardzo łatwo jest oddzielić zachowanie od kodu projektanta.
Dzięki XAML programiści mogą pracować równolegle z projektantami. Rozdzielenie GUI i jego zachowania może pozwolić nam łatwo zmienić wygląd kontrolki przy użyciu stylów i szablonów.
WPF - funkcje
WPF to potężna platforma do tworzenia aplikacji systemu Windows. Obsługuje wiele wspaniałych funkcji, z których niektóre zostały wymienione poniżej -
Funkcja | Opis |
---|---|
Kontrola wewnątrz Kontroli | Umożliwia zdefiniowanie kontrolki wewnątrz innej kontrolki jako zawartości. |
Wiązanie danych | Mechanizm wyświetlania i interakcji z danymi między elementami interfejsu użytkownika a obiektem danych w interfejsie użytkownika. |
Usługi medialne | Zapewnia zintegrowany system do tworzenia interfejsów użytkownika z typowymi elementami multimedialnymi, takimi jak obrazy, audio i wideo. |
Szablony | W WPF można zdefiniować wygląd elementu bezpośrednio za pomocą szablonu |
Animacje | Budowanie interaktywności i ruchu w interfejsie użytkownika |
Alternatywne wejście | Obsługuje wprowadzanie wielodotykowe w systemie Windows 7 i nowszych. |
Direct3D | Umożliwia wyświetlanie bardziej złożonej grafiki i niestandardowych motywów |
Firma Microsoft udostępnia dwa ważne narzędzia do tworzenia aplikacji WPF.
- Visual Studio
- Expression Blend
Oba narzędzia mogą tworzyć projekty WPF, ale faktem jest, że Visual Studio jest częściej używane przez programistów, podczas gdy Blend jest częściej używany przez projektantów. W tym samouczku będziemy głównie używać programu Visual Studio.
Instalacja
Firma Microsoft udostępnia bezpłatną wersję programu Visual Studio, którą można pobrać z programu VisualStudio .
Pobierz pliki i wykonaj kroki podane poniżej, aby skonfigurować środowisko programistyczne aplikacji WPF w systemie.
Po zakończeniu pobierania uruchom plik installer. Zostanie wyświetlone następujące okno dialogowe.
Kliknij Install i rozpocznie proces instalacji.
Po pomyślnym zakończeniu procesu instalacji pojawi się następujące okno dialogowe.
Zamknij to okno dialogowe i w razie potrzeby uruchom ponownie komputer.
Teraz otwórz program Visual Studio z menu Start, które otworzy następujące okno dialogowe.
- Po zakończeniu zobaczysz główne okno programu Visual Studio.
Teraz możesz zbudować swoją pierwszą aplikację WPF.
W tym rozdziale opracujemy prostą aplikację Hello World WPF. Zacznijmy więc od prostej implementacji, wykonując kroki podane poniżej.
- Kliknij opcję menu Plik> Nowy> Projekt.
- Zostanie wyświetlone następujące okno dialogowe.
W obszarze Szablony wybierz opcję Visual C #, a na środkowym panelu wybierz opcję Aplikacja WPF.
Nadaj projektowi nazwę. RodzajHelloWorld w polu nazwy i kliknij przycisk OK.
Domyślnie tworzone są dwa pliki, jeden to XAML plik (mainwindow.xaml), a drugi to plik CS plik (mainwindow.cs)
W pliku mainwindow.xaml zobaczysz dwa podokna, z których jedno to design window a drugi to source (XAML) window.
W aplikacji WPF istnieją dwa sposoby projektowania interfejsu użytkownika dla aplikacji. Jednym z nich jest po prostu przeciągnięcie i upuszczenie elementów interfejsu użytkownika z przybornika do okna projektu. Drugim sposobem jest zaprojektowanie interfejsu użytkownika przez napisanie tagów XAML dla elementów interfejsu użytkownika. Program Visual Studio obsługuje tagi XAML, gdy funkcja przeciągania i upuszczania jest używana do projektowania interfejsu użytkownika.
W pliku mainwindow.xaml następujące tagi XAML są zapisywane domyślnie.
<Window x:Class = "HelloWorld.MainWindow"
xmlns = "http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x = "http://schemas.microsoft.com/winfx/2006/xaml"
Title = "MainWindow" Height = "350" Width = "604">
<Grid>
</Grid>
</Window>
- Domyślnie Siatka jest ustawiana jako pierwszy element po stronie.
- Przejdźmy do przybornika i przeciągnijmy TextBlock do okna projektu.
- W oknie projektu zobaczysz TextBlock.
Gdy spojrzysz na okno źródłowe, zobaczysz, że program Visual Studio wygenerował dla Ciebie kod XAML TextBlock.
Zmieńmy właściwość Text TextBlock w kodzie XAML z TextBlock na Hello World.
<Window x:Class = "HelloWorld.MainWindow"
xmlns = "http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x = "http://schemas.microsoft.com/winfx/2006/xaml"
Title = "MainWindow" Height = "350" Width = "604">
<Grid>
<TextBlock x:Name = "textBlock" HorizontalAlignment = "Left"
Margin = "235,143,0,0" TextWrapping = "Wrap" Text = "Hello World!"
VerticalAlignment = "Top" Height = "44" Width = "102" />
</Grid>
</Window>
- Teraz zobaczysz zmianę również w oknie projektu.
Kiedy powyższy kod zostanie skompilowany i wykonany, zobaczysz następujące okno.
Gratulacje! Zaprojektowałeś i utworzyłeś swoją pierwszą aplikację WPF.
Jedną z pierwszych rzeczy, które napotkasz podczas pracy z WPF, jest XAML. XAML oznacza Extensible Application Markup Language. To prosty i deklaratywny język oparty na XML.
W języku XAML bardzo łatwo jest tworzyć, inicjować i ustawiać właściwości obiektów z relacjami hierarchicznymi.
Służy głównie do projektowania GUI, ale może być również używany do innych celów, np. Do deklarowania przepływu pracy w Workflow Foundation.
Podstawowa składnia
Podczas tworzenia nowego projektu WPF domyślnie napotkasz część kodu XAML w pliku MainWindow.xaml, jak pokazano poniżej.
<Window x:Class = "Resources.MainWindow"
xmlns = "http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x = "http://schemas.microsoft.com/winfx/2006/xaml"
Title = "MainWindow" Height = "350" Width = "525">
<Grid>
</Grid>
</Window>
Powyższy plik XAML zawiera różne rodzaje informacji. Poniższa tabela pokrótce wyjaśnia rolę każdej informacji.
Informacja | Opis |
---|---|
<Okno | Jest to otwierający element obiektu lub kontener katalogu głównego. |
x: Class = "Resources.MainWindow" | Jest to deklaracja klasy częściowej, która łączy znacznik z częściowym kodem klasy zdefiniowanym za nią. |
xmlns = "http://schemas.microsoft.com/win fx / 2006 / xaml / prezentacja" | Mapuje domyślną przestrzeń nazw XAML dla klienta / struktury WPF |
xmlns: x = "http://schemas.microsoft.com/w infx / 2006 / xaml" | Przestrzeń nazw XAML dla języka XAML, który mapuje go na prefiks x: |
> | Koniec elementu obiektu głównego |
<Grid> </Grid> |
Jest to uruchamianie i zamykanie znaczników pustego obiektu siatki. |
</Window> | Zamknięcie elementu obiektu |
Reguły składni dla XAML są prawie podobne do XML. Jeśli spojrzysz na dokument XAML, zauważysz, że jest to w rzeczywistości prawidłowy plik XML, ale plik XML niekoniecznie jest plikiem XAML. Dzieje się tak, ponieważ w języku XML wartość atrybutów musi być ciągiem, podczas gdy w języku XAML może to być inny obiekt, który jest znany jako składnia elementu właściwości.
Składnia elementu Object rozpoczyna się od lewego nawiasu trójkątnego (<), po którym następuje nazwa obiektu, np. Przycisk.
Zdefiniuj niektóre właściwości i atrybuty tego elementu obiektu.
Element Object musi być zamknięty ukośnikiem (/), po którym bezpośrednio następuje prawy nawias ostry (>).
Przykład prostego obiektu bez elementu potomnego
<Button/>
Przykład elementu obiektu z pewnymi atrybutami
<Button Content = "Click Me" Height = "30" Width = "60" />
Przykład alternatywnej składni do definiowania właściwości (składnia elementu właściwości)
<Button>
<Button.Content>Click Me</Button.Content>
<Button.Height>30</Button.Height>
<Button.Width>60</Button.Width>
</Button>
Przykład obiektu z elementem podrzędnym: StackPanel zawiera Textblock jako element podrzędny
<StackPanel Orientation = "Horizontal">
<TextBlock Text = "Hello"/>
</StackPanel>
Dlaczego XAML w WPF
XAML to nie tylko najbardziej znana funkcja WPF, ale także jedna z najczęściej niezrozumianych funkcji. Jeśli masz kontakt z WPF, to na pewno słyszałeś o XAML; ale zwróć uwagę na dwa mniej znane fakty dotyczące języka XAML -
- WPF nie potrzebuje XAML
- XAML nie potrzebuje WPF
W rzeczywistości są to oddzielne elementy technologii. Aby zrozumieć, jak to może być, spójrzmy na prosty przykład, w którym jest tworzony przycisk z niektórymi właściwościami w języku XAML.
<Window x:Class = "WPFXAMLOverview.MainWindow"
xmlns = "http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x = "http://schemas.microsoft.com/winfx/2006/xaml"
Title = "MainWindow" Height = "350" Width = "604">
<StackPanel>
<Button x:Name = "button" Content = "Click Me" HorizontalAlignment = "Left"
Margin = "150" VerticalAlignment = "Top" Width = "75" />
</StackPanel>
</Window>
Jeśli zdecydujesz się nie używać XAML w WPF, możesz osiągnąć ten sam wynik GUI również z językiem proceduralnym. Spójrzmy na ten sam przykład, ale tym razem utworzymy przycisk w C #.
using System.Windows;
using System.Windows.Controls;
namespace WPFXAMLOverview {
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window {
public MainWindow() {
InitializeComponent();
// Create the StackPanel
StackPanel stackPanel = new StackPanel();
this.Content = stackPanel;
// Create the Button
Button button = new Button();
button.Content = "Click Me";
button.HorizontalAlignment = HorizontalAlignment.Left;
button.Margin = new Thickness(150);
button.VerticalAlignment = VerticalAlignment.Top;
button.Width = 75;
stackPanel.Children.Add(button);
}
}
}
Podczas kompilowania i wykonywania kodu XAML lub kodu C # zobaczysz te same dane wyjściowe, jak pokazano poniżej.
Z powyższego przykładu jasno wynika, że to, co możesz zrobić w języku XAML, aby utworzyć, zainicjować i ustawić właściwości obiektów, te same zadania można również wykonać za pomocą kodu.
XAML to kolejny prosty i łatwy sposób projektowania elementów interfejsu użytkownika.
W przypadku języka XAML nie oznacza to, że jedyną możliwością jest zaprojektowanie elementów interfejsu użytkownika. Możesz zadeklarować obiekty w XAML lub zdefiniować je przy użyciu kodu.
XAML jest opcjonalny, ale mimo to stanowi podstawę projektowania WPF.
Celem języka XAML jest umożliwienie projektantom wizualnym bezpośredniego tworzenia elementów interfejsu użytkownika.
WPF ma na celu umożliwienie kontrolowania wszystkich wizualnych aspektów interfejsu użytkownika z poziomu znacznika.
Istnieje wiele technologii, w których elementy i komponenty są uporządkowane w strukturze drzewa, dzięki czemu programiści mogą łatwo obsługiwać obiekt i zmieniać zachowanie aplikacji. Windows Presentation Foundation (WPF) ma kompleksową strukturę drzewa w postaci obiektów. W WPF istnieją dwa sposoby konceptualizacji pełnego drzewa obiektów -
- Struktura drzewa logicznego
- Struktura drzewa wizualnego
Za pomocą tych struktur drzewiastych można łatwo tworzyć i identyfikować relacje między elementami interfejsu użytkownika. Przeważnie programiści i projektanci WPF używają języka proceduralnego do tworzenia aplikacji lub projektują część interfejsu użytkownika aplikacji w języku XAML, pamiętając o strukturze drzewa obiektów.
Struktura drzewa logicznego
W aplikacjach WPF struktura elementów interfejsu użytkownika w XAML reprezentuje logiczną strukturę drzewa. W języku XAML podstawowe elementy interfejsu użytkownika są deklarowane przez dewelopera. Drzewo logiczne w WPF definiuje następujące -
- Właściwości zależności
- Zasoby statyczne i dynamiczne
- Wiązanie elementów w nazwie itp.
Spójrzmy na poniższy przykład, w którym tworzony jest przycisk i pole listy.
<Window x:Class = "WPFElementsTree.MainWindow"
xmlns = "http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x = "http://schemas.microsoft.com/winfx/2006/xaml"
Title = "MainWindow" Height = "350" Width = "604">
<StackPanel>
<Button x:Name = "button" Height = "30" Width = "70" Content = "OK" Margin = "20" />
<ListBox x:Name = "listBox" Height = "100" Width = "100" Margin = "20">
<ListBoxItem Content = "Item 1" />
<ListBoxItem Content = "Item 2" />
<ListBoxItem Content = "Item 3" />
</ListBox>
</StackPanel>
</Window>
Jeśli spojrzysz na kod XAML, zobaczysz strukturę drzewa, tj. Węzeł główny to okno, a wewnątrz węzła głównego jest tylko jedno dziecko, czyli StackPanel. Ale StackPanel zawiera dwa elementy podrzędne, przycisk i pole listy. Pole listy ma jeszcze trzy podrzędne elementy listy.
Struktura drzewa wizualnego
W WPF koncepcja drzewa wizualnego opisuje strukturę obiektów wizualnych reprezentowaną przez klasę Visual Base. Oznacza wszystkie elementy interfejsu użytkownika, które są renderowane na ekranie wyjściowym.
Gdy programista chce utworzyć szablon dla określonej kontrolki, w rzeczywistości renderuje wizualne drzewo tej kontrolki. Drzewo wizualne jest również bardzo przydatne dla tych, którzy chcą rysować kontrolki niższego poziomu ze względu na wydajność i optymalizację.
W aplikacjach WPF drzewo wizualne jest używane dla -
- Renderowanie obiektów wizualnych.
- Renderowanie układów.
- Zdarzenia kierowane przeważnie wędrują wzdłuż drzewa wizualnego, a nie drzewa logicznego.
Aby zobaczyć drzewo wizualne powyższej prostej aplikacji, która zawiera przycisk i pole listy, skompilujmy i uruchom kod XAML, a zobaczysz następujące okno.
Gdy aplikacja jest uruchomiona, możesz zobaczyć wizualne drzewo uruchomionej aplikacji w oknie Live Visual Tree, które pokazuje pełną hierarchię tej aplikacji, jak pokazano poniżej.
Drzewo wizualne jest zwykle nadzbiorem drzewa logicznego. Widać tutaj, że wszystkie elementy logiczne są również obecne w drzewie wizualnym. Tak więc te dwa drzewa to tak naprawdę tylko dwa różne widoki tego samego zestawu obiektów, które tworzą interfejs użytkownika.
Drzewo logiczne pomija wiele szczegółów, umożliwiając skupienie się na podstawowej strukturze interfejsu użytkownika i zignorowanie szczegółów dotyczących tego, jak został on przedstawiony.
Drzewo logiczne służy do tworzenia podstawowej struktury interfejsu użytkownika.
Drzewo wizualne będzie interesujące, jeśli koncentrujesz się na prezentacji. Na przykład, jeśli chcesz dostosować wygląd dowolnego elementu interfejsu użytkownika, będziesz musiał użyć drzewa wizualnego.
W aplikacjach WPF właściwość zależności jest określonym typem właściwości, który rozszerza właściwość CLR. Wykorzystuje określone funkcje dostępne w systemie właściwości WPF.
Klasa, która definiuje właściwość zależności, musi być dziedziczona z klasy DependencyObjectklasa. Wiele klas kontrolek interfejsu użytkownika, które są używane w języku XAML, pochodzi zDependencyObject i obsługują właściwości zależności, np. klasa Button obsługuje IsMouseOver właściwość zależności.
Poniższy kod XAML tworzy przycisk z niektórymi właściwościami.
<Window x:Class = "WPFDependencyProperty.MainWindow"
xmlns = "http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x = "http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local = "clr-namespace:WPFDependencyProperty"
Title = "MainWindow" Height = "350" Width = "604">
<Grid>
<Button Height = "40" Width = "175" Margin = "10" Content = "Dependency Property">
<Button.Style>
<Style TargetType = "{x:Type Button}">
<Style.Triggers>
<Trigger Property = "IsMouseOver" Value = "True">
<Setter Property = "Foreground" Value = "Red" />
</Trigger>
</Style.Triggers>
</Style>
</Button.Style>
</Button>
</Grid>
</Window>
Rozszerzenie znacznika x: Type w XAML ma podobną funkcjonalność, jak typeof () w C #. Jest używany, gdy określono atrybuty przyjmujące typ obiektu, na przykład <Style TargetType = "{x: Type Button}">
Gdy powyższy kod zostanie skompilowany i wykonany, otrzymasz następujący kod MainWindow. Gdy mysz znajduje się nad przyciskiem, zmienia kolor pierwszego planu przycisku. Kiedy mysz opuszcza przycisk, przywraca on swój pierwotny kolor.
Dlaczego potrzebujemy właściwości zależności
Właściwość zależności daje wszelkiego rodzaju korzyści, gdy używasz jej w swojej aplikacji. Właściwość zależności może być używana przez właściwość CLR w następujących scenariuszach -
- Jeśli chcesz ustawić styl
- Jeśli chcesz powiązać dane
- Jeśli chcesz ustawić za pomocą zasobu (statycznego lub dynamicznego)
- Jeśli chcesz wspierać animację
Zasadniczo właściwości zależności oferują wiele funkcji, których nie uzyskasz przy użyciu właściwości CLR.
Główna różnica między dependency properties i inne CLR properties są wymienione poniżej -
Właściwości CLR mogą bezpośrednio odczytywać / zapisywać z prywatnego elementu członkowskiego klasy przy użyciu getter i setter. Natomiast właściwości zależności nie są przechowywane w obiekcie lokalnym.
Właściwości zależności są przechowywane w słowniku par klucz / wartość, który jest udostępniany przez klasę DependencyObject. Oszczędza również dużo pamięci, ponieważ przechowuje właściwość po zmianie. Może być również powiązany w języku XAML.
Niestandardowe właściwości zależności
W środowisku .NET można również zdefiniować niestandardowe właściwości zależności. Wykonaj kroki podane poniżej, aby zdefiniować niestandardową właściwość zależności w języku C #.
Zadeklaruj i zarejestruj swój dependency property z rejestrem wywołań systemowych.
Zapewnić setter i getter dla nieruchomości.
Zdefiniuj static handler który obsłuży wszelkie zmiany zachodzące na całym świecie
Zdefiniuj plik instance handler który obsłuży wszelkie zmiany, które nastąpią w tej konkretnej instancji.
Poniższy kod C # definiuje właściwość zależności, aby ustawić SetText właściwość kontrolki użytkownika.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace WpfApplication3 {
/// <summary>
/// Interaction logic for UserControl1.xaml
/// </summary>
public partial class UserControl1 : UserControl {
public UserControl1() {
InitializeComponent();
}
public static readonly DependencyProperty SetTextProperty =
DependencyProperty.Register("SetText", typeof(string), typeof(UserControl1), new
PropertyMetadata("", new PropertyChangedCallback(OnSetTextChanged)));
public string SetText {
get { return (string)GetValue(SetTextProperty); }
set { SetValue(SetTextProperty, value); }
}
private static void OnSetTextChanged(DependencyObject d,
DependencyPropertyChangedEventArgs e) {
UserControl1 UserControl1Control = d as UserControl1;
UserControl1Control.OnSetTextChanged(e);
}
private void OnSetTextChanged(DependencyPropertyChangedEventArgs e) {
tbTest.Text = e.NewValue.ToString();
}
}
}
Oto plik XAML, w którym TextBlock jest zdefiniowany jako kontrolka użytkownika, a właściwość Text zostanie do niego przypisana przez właściwość zależności SetText.
Poniższy kod XAML tworzy kontrolkę użytkownika i inicjuje jej SetText właściwość zależności.
<Window x:Class = "WpfApplication3.MainWindow"
xmlns = "http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x = "http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:views = "clr-namespace:WpfApplication3"
Title = "MainWindow" Height = "350" Width = "604">
<Grid>
<views:UserControl1 SetText = "Hellow World"/>
</Grid>
</Window>
Uruchommy tę aplikację. Możesz od razu zauważyć, że w naszym MainWindow właściwość zależności dla kontrolki użytkownika została pomyślnie użyta jako Text.
ZA routed eventjest typem zdarzenia, które może wywołać procedury obsługi wielu detektorów w drzewie elementów, a nie tylko obiekt, który wywołał zdarzenie. Zasadniczo jest to zdarzenie CLR obsługiwane przez instancję klasy Routed Event. Jest zarejestrowany w systemie zdarzeń WPF. RoutedEvents mają trzy główne strategie routingu, które są następujące:
- Wydarzenie bezpośrednie
- Wydarzenie propagujące
- Wydarzenie w tunelu
Wydarzenie bezpośrednie
Zdarzenie bezpośrednie jest podobne do zdarzeń w formularzach systemu Windows, które są wywoływane przez element, z którego pochodzi zdarzenie.
W przeciwieństwie do standardowego zdarzenia CLR, zdarzenia kierowane bezpośrednio obsługują obsługę klas i mogą być używane w ustawieniach zdarzeń i wyzwalaczach zdarzeń w ramach Twojego stylu kontroli niestandardowej.
Dobrym przykładem bezpośredniego zdarzenia byłoby zdarzenie MouseEnter.
Wydarzenie propagujące
Zdarzenie propagacji zaczyna się od elementu, z którego pochodzi zdarzenie. Następnie podróżuje w górę drzewa wizualnego do najwyższego elementu w drzewie wizualnym. Tak więc w WPF najwyższym elementem jest najprawdopodobniej okno.
Wydarzenie w tunelu
Programy obsługi zdarzeń w katalogu głównym drzewa elementów są wywoływane, a następnie zdarzenie przemieszcza się w dół drzewa wizualnego do wszystkich węzłów podrzędnych, aż osiągnie element, z którego pochodzi zdarzenie.
Różnica między zdarzeniem propagacji a zdarzeniem tunelowania polega na tym, że zdarzenie tunelowania zawsze zaczyna się od podglądu.
W aplikacji WPF zdarzenia są często implementowane jako para tunelowania / propagacji. Będziesz więc mieć podgląd MouseDown, a następnie zdarzenie MouseDown.
Poniżej podano prosty przykład zdarzenia Routed, w którym przycisk i trzy bloki tekstu są tworzone z pewnymi właściwościami i zdarzeniami.
<Window x:Class = "WPFRoutedEvents.MainWindow"
xmlns = "http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x = "http://schemas.microsoft.com/winfx/2006/xaml"
Title = "MainWindow" Height = "450" Width = "604" ButtonBase.Click = "Window_Click" >
<Grid>
<StackPanel Margin = "20" ButtonBase.Click = "StackPanel_Click">
<StackPanel Margin = "10">
<TextBlock Name = "txt1" FontSize = "18" Margin = "5" Text = "This is a TextBlock 1" />
<TextBlock Name = "txt2" FontSize = "18" Margin = "5" Text = "This is a TextBlock 2" />
<TextBlock Name = "txt3" FontSize = "18" Margin = "5" Text = "This is a TextBlock 3" />
</StackPanel>
<Button Margin = "10" Content = "Click me" Click = "Button_Click" Width = "80"/>
</StackPanel>
</Grid>
</Window>
Oto kod C # dla implementacji zdarzeń Click dla Button, StackPanel i Window.
using System.Windows;
namespace WPFRoutedEvents {
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window {
public MainWindow() {
InitializeComponent();
}
private void Button_Click(object sender, RoutedEventArgs e) {
txt1.Text = "Button is Clicked";
}
private void StackPanel_Click(object sender, RoutedEventArgs e) {
txt2.Text = "Click event is bubbled to Stack Panel";
}
private void Window_Click(object sender, RoutedEventArgs e) {
txt3.Text = "Click event is bubbled to Window";
}
}
}
Kiedy kompilujesz i wykonujesz powyższy kod, wygeneruje on następujące okno -
Po kliknięciu przycisku bloki tekstu zostaną zaktualizowane, jak pokazano poniżej.
Jeśli chcesz zatrzymać kierowane zdarzenie na jakimkolwiek określonym poziomie, musisz ustawić e.Handled = true;
Zmieńmy StackPanel_Click zdarzenie, jak pokazano poniżej -
private void StackPanel_Click(object sender, RoutedEventArgs e) {
txt2.Text = "Click event is bubbled to Stack Panel";
e.Handled = true;
}
Po kliknięciu na przycisk, można zaobserwować, że zdarzenie click nie będą kierowane do okna i zatrzyma się na StackPanel i 3 rd blok tekstu nie zostaną zaktualizowane.
Niestandardowe zdarzenia kierowane
W .NET Framework można również zdefiniować niestandardowe zdarzenia kierowane. Aby zdefiniować niestandardowe zdarzenie kierowane w języku C #, należy wykonać kroki podane poniżej.
Zadeklaruj i zarejestruj swoje zdarzenie kierowane za pomocą wywołania systemowego RegisterRoutedEvent.
Określ strategię routingu, np. Bubble, Tunnel lub Direct.
Podaj procedurę obsługi zdarzeń.
Weźmy przykład, aby dowiedzieć się więcej o niestandardowych zdarzeniach kierowanych. Wykonaj czynności podane poniżej -
Utwórz nowy projekt WPF za pomocą WPFCustomRoutedEvent
Kliknij prawym przyciskiem myszy rozwiązanie i wybierz Dodaj> Nowy element ...
Otworzy się następujące okno dialogowe, teraz wybierz Custom Control (WPF) i nazwij to MyCustomControl.
Kliknij Add i zobaczysz, że dwa nowe pliki (Themes / Generic.xaml i MyCustomControl.cs) zostaną dodane do twojego rozwiązania.
Poniższy kod XAML ustawia styl kontrolki niestandardowej w pliku Generic.xaml.
<ResourceDictionary
xmlns = "http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x = "http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local = "clr-namespace:WPFCustomRoutedEvent">
<Style TargetType = "{x:Type local:MyCustomControl}">
<Setter Property = "Margin" Value = "50"/>
<Setter Property = "Template">
<Setter.Value>
<ControlTemplate TargetType = "{x:Type local:MyCustomControl}">
<Border Background = "{TemplateBinding Background}"
BorderBrush = "{TemplateBinding BorderBrush}"
BorderThickness = "{TemplateBinding BorderThickness}">
<Button x:Name = "PART_Button" Content = "Click Me" />
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>
Poniżej podano kod C # dla MyCustomControl class który dziedziczy z Control class w którym niestandardowe kierowane zdarzenie Click jest tworzone dla kontrolki niestandardowej.
using System.Windows;
using System.Windows.Controls;
namespace WPFCustomRoutedEvent {
public class MyCustomControl : Control {
static MyCustomControl() {
DefaultStyleKeyProperty.OverrideMetadata(typeof(MyCustomControl),
new FrameworkPropertyMetadata(typeof(MyCustomControl)));
}
public override void OnApplyTemplate() {
base.OnApplyTemplate();
//demo purpose only, check for previous instances and remove the handler first
var button = GetTemplateChild("PART_Button") as Button;
if (button ! = null)
button.Click + = Button_Click;
}
void Button_Click(object sender, RoutedEventArgs e) {
RaiseClickEvent();
}
public static readonly RoutedEvent ClickEvent =
EventManager.RegisterRoutedEvent("Click", RoutingStrategy.Bubble,
typeof(RoutedEventHandler), typeof(MyCustomControl));
public event RoutedEventHandler Click {
add { AddHandler(ClickEvent, value); }
remove { RemoveHandler(ClickEvent, value); }
}
protected virtual void RaiseClickEvent() {
RoutedEventArgs args = new RoutedEventArgs(MyCustomControl.ClickEvent);
RaiseEvent(args);
}
}
}
Oto implementacja zdarzenia kierowanego niestandardowo w C #, która wyświetli okno komunikatu, gdy użytkownik je kliknie.
using System.Windows;
namespace WPFCustomRoutedEvent {
// <summary>
// Interaction logic for MainWindow.xaml
// </summary>
public partial class MainWindow : Window {
public MainWindow() {
InitializeComponent();
}
private void MyCustomControl_Click(object sender, RoutedEventArgs e) {
MessageBox.Show("It is the custom routed event of your custom control");
}
}
}
Oto implementacja w pliku MainWindow.xaml w celu dodania kontrolki niestandardowej ze zdarzeniem kierowanym Click.
<Window x:Class = "WPFCustomRoutedEvent.MainWindow"
xmlns = "http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x = "http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local = "clr-namespace:WPFCustomRoutedEvent"
Title = "MainWindow" Height = "350" Width = "604">
<Grid>
<local:MyCustomControl Click = "MyCustomControl_Click" />
</Grid>
</Window>
Gdy powyższy kod zostanie skompilowany i wykonany, utworzy następujące okno zawierające niestandardową kontrolkę.
Po kliknięciu kontrolki niestandardowej zostanie wyświetlony następujący komunikat.
Windows Presentation Foundation (WPF) umożliwia programistom łatwe tworzenie i tworzenie wizualnie wzbogaconych aplikacji opartych na interfejsie użytkownika.
Klasyczne elementy interfejsu użytkownika lub kontrolki w innych strukturach interfejsu użytkownika są również ulepszone w aplikacjach WPF.
Wszystkie standardowe kontrolki WPF można znaleźć w przyborniku, który jest częścią System.Windows.Controls.
Te kontrolki można również tworzyć w języku znaczników XAML.
Pełna hierarchia dziedziczenia formantów WPF jest następująca -
Poniższa tabela zawiera listę kontrolek, które omówimy w kolejnych rozdziałach.
Sr. No. | Sterowanie i opis |
---|---|
1 | Przycisk Kontrolka, która reaguje na dane wejściowe użytkownika |
2 | Kalendarz Reprezentuje kontrolkę, która umożliwia użytkownikowi wybranie daty przy użyciu wyświetlania kalendarza wizualnego. |
3 | CheckBox Kontrolka, którą użytkownik może wybrać lub wyczyścić. |
4 | ComboBox Rozwijana lista elementów, z których użytkownik może wybierać. |
5 | Menu kontekstowe Pobiera lub ustawia element menu kontekstowego, który powinien być wyświetlany za każdym razem, gdy menu kontekstowe jest żądane za pośrednictwem interfejsu użytkownika (UI) z poziomu tego elementu. |
6 | Siatka danych Reprezentuje kontrolkę wyświetlającą dane w dostosowywalnej siatce. |
7 | DatePicker Kontrolka, która pozwala użytkownikowi wybrać datę. |
8 | Dialogi Aplikacja może również wyświetlać dodatkowe okna, aby pomóc użytkownikowi zebrać lub wyświetlić ważne informacje. |
9 | GridView Kontrolka przedstawiająca kolekcję elementów w wierszach i kolumnach, które można przewijać w poziomie. |
10 | Wizerunek Kontrolka przedstawiająca obraz. |
11 | Etykieta Wyświetla tekst w formularzu. Zapewnia obsługę kluczy dostępu. |
12 | Skrzynka na listy Kontrolka przedstawiająca wbudowaną listę elementów, z których użytkownik może wybierać. |
13 | Menu Reprezentuje kontrolkę menu systemu Windows, która umożliwia hierarchiczne organizowanie elementów skojarzonych z poleceniami i programami obsługi zdarzeń. |
14 | PasswordBox Formant do wprowadzania haseł. |
15 | Popup Wyświetla zawartość nad istniejącą zawartością, w granicach okna aplikacji. |
16 | Pasek postępu Kontrolka wskazująca postęp poprzez wyświetlenie paska. |
17 | Przycisk radiowy Kontrolka, która umożliwia użytkownikowi wybranie pojedynczej opcji z grupy opcji. |
18 | ScrollViewer Formant kontenera, który umożliwia użytkownikowi przesuwanie i powiększanie jego zawartości. |
19 | Suwak Kontrolka, która umożliwia użytkownikowi wybieranie z zakresu wartości przez przesuwanie kontrolki Thumb wzdłuż ścieżki. |
20 | TextBlock Kontrolka wyświetlająca tekst. |
21 | ToggleButton Przycisk, który można przełączać między 2 stanami. |
22 | ToolTip Wyskakujące okienko, które wyświetla informacje o elemencie. |
23 | Okno Okno główne, które zapewnia opcję minimalizacji / maksymalizacji, pasek tytułu, ramkę i przycisk zamykania |
24 | Elementy sterujące innych firm Użyj formantów innych firm w aplikacjach WPF. |
Omówimy wszystkie te kontrole po kolei wraz z ich wdrożeniem.
Układ elementów sterujących jest bardzo ważny i krytyczny dla użyteczności aplikacji. Służy do uporządkowania grupy elementów GUI w Twojej aplikacji. Podczas wybierania paneli układu należy wziąć pod uwagę kilka ważnych kwestii -
- Pozycje elementów potomnych
- Rozmiary elementów podrzędnych
- Nakładanie nakładających się elementów potomnych jeden na drugi
Stały układ pikseli elementów sterujących nie działa, gdy aplikacja ma być wyświetlana na różnych rozdzielczościach ekranu. XAML zapewnia bogaty zestaw wbudowanych paneli układu do odpowiedniego rozmieszczania elementów GUI. Oto niektóre z najczęściej używanych i popularnych paneli układu -
Sr. No. | Panele i opis |
---|---|
1 | Panel stosu Panel stosu to prosty i przydatny panel układu w języku XAML. W panelu stosu elementy podrzędne można układać w jednej linii, poziomo lub pionowo, w oparciu o właściwość orientacji. |
2 | Panel Wrap W WrapPanel elementy podrzędne są umieszczane w kolejności sekwencyjnej, od lewej do prawej lub od góry do dołu na podstawie właściwości orientacji. |
3 | Panel dokowania DockPanel definiuje obszar do rozmieszczenia elementów podrzędnych względem siebie w poziomie lub w pionie. Za pomocą DockPanel można łatwo zadokować elementy podrzędne na górze, na dole, w prawo, w lewo i na środku za pomocąDock własność. |
4 | Panel płótna Panel Canvas to podstawowy panel układu, w którym elementy podrzędne mogą być jawnie pozycjonowane za pomocą współrzędnych względem elementu Canvas dowolna strona, taka jak lewa, prawa, góra i dół. |
5 | Panel siatki Panel siatki zapewnia elastyczny obszar, który składa się z wierszy i kolumn. W siatce elementy podrzędne można układać w formie tabelarycznej. |
Zagnieżdżanie układu oznacza użycie panelu układu wewnątrz innego układu, np. Zdefiniowanie paneli stosu wewnątrz siatki. Ta koncepcja jest szeroko stosowana w celu wykorzystania zalet wielu układów w aplikacji. W poniższym przykładzie będziemy używać paneli stosu wewnątrz siatki.
Przyjrzyjmy się poniższemu kodowi XAML.
<Window x:Class = "WPFNestingLayouts.MainWindow"
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:WPFNestingLayouts"
mc:Ignorable = "d" Title = "MainWindow" Height = "350" Width = "604">
<Grid Background = "AntiqueWhite">
<Grid.RowDefinitions>
<RowDefinition Height = "*" />
<RowDefinition Height = "*" />
<RowDefinition Height = "*" />
<RowDefinition Height = "*" />
<RowDefinition Height = "*" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width = "*" />
</Grid.ColumnDefinitions>
<Label Content = "Employee Info" FontSize = "15"
FontWeight = "Bold" Grid.Column = "0" Grid.Row = "0"/>
<StackPanel Grid.Column = "0" Grid.Row = "1" Orientation = "Horizontal">
<Label Content = "Name" VerticalAlignment = "Center" Width = "70"/>
<TextBox Name = "txtName" Text = "Muhammad Ali" VerticalAlignment = "Center"
Width = "200">
</TextBox>
</StackPanel>
<StackPanel Grid.Column = "0" Grid.Row = "2" Orientation = "Horizontal">
<Label Content = "ID" VerticalAlignment = "Center" Width = "70"/>
<TextBox Name = "txtCity" Text = "421" VerticalAlignment = "Center"
Width = "50">
</TextBox>
</StackPanel>
<StackPanel Grid.Column = "0" Grid.Row = "3" Orientation = "Horizontal">
<Label Content = "Age" VerticalAlignment = "Center" Width = "70"/>
<TextBox Name = "txtState" Text = "32" VerticalAlignment = "Center"
Width = "50"></TextBox>
</StackPanel>
<StackPanel Grid.Column = "0" Grid.Row = "4" Orientation = "Horizontal">
<Label Content = "Title" VerticalAlignment = "Center" Width = "70"/>
<TextBox Name = "txtCountry" Text = "Programmer" VerticalAlignment = "Center"
Width = "200"></TextBox>
</StackPanel>
</Grid>
</Window>
Kiedy kompilujesz i wykonujesz powyższy kod, wyświetli się następujące okno.
Zalecamy wykonanie powyższego przykładowego kodu i wypróbowanie innych układów zagnieżdżania.
Windows Presentation Foundation (WPF) zapewnia zaawansowany interfejs API, za pomocą którego aplikacje mogą pobierać dane wejściowe z różnych urządzeń, takich jak mysz, klawiatura i panele dotykowe. W tym rozdziale omówimy następujące typy danych wejściowych, które mogą być obsługiwane w aplikacjach WPF -
Sr. No. | Dane wejściowe i opis |
---|---|
1 | Mysz Istnieją różne typy wejść myszy, takie jak MouseDown, MouseEnter, MouseLeave itp. |
2 | Klawiatura Istnieje wiele typów wejść z klawiatury, takich jak KeyDown, KeyUp, TextInput itp. |
3 | ContextMenu lub RoutedCommands RoutedCommands umożliwiają obsługę danych wejściowych na bardziej semantycznym poziomie. W rzeczywistości są to proste instrukcje, takie jak Nowy, Otwórz, Kopiuj, Wytnij i Zapisz. |
4 | Wielodotykowy Windows 7 i jego nowsze wersje mają możliwość odbierania danych wejściowych z wielu urządzeń wrażliwych na dotyk. Aplikacje WPF mogą również obsługiwać wprowadzanie dotykowe jako inne dane wejściowe, takie jak mysz lub klawiatura, przez podnoszenie zdarzeń, gdy wystąpi dotknięcie. |
Argument wiersza polecenia to mechanizm, w którym użytkownik może przekazać zestaw parametrów lub wartości do aplikacji WPF, gdy jest ona wykonywana. Te argumenty są bardzo ważne, aby kontrolować aplikację z zewnątrz, na przykład, jeśli chcesz otworzyć dokument programu Word z wiersza poleceń, możesz użyć tego polecenia „C:\> start winword word1.docx”I się otworzy word1.docx dokument.
Argumenty wiersza poleceń są obsługiwane w funkcji Startup. Poniżej znajduje się prosty przykład, który pokazuje, jak przekazać argumenty wiersza polecenia do aplikacji WPF. Utwórzmy nową aplikację WPF o nazwieWPFCommandLine.
Przeciągnij jedno pole tekstowe z przybornika do okna projektu.
W tym przykładzie przekażemy ścieżkę do pliku txt do naszej aplikacji jako parametr wiersza poleceń.
Program odczyta plik txt, a następnie zapisze cały tekst w polu tekstowym.
Poniższy kod XAML tworzy pole tekstowe i inicjuje je z niektórymi właściwościami.
<Window x:Class = "WPFCommandLine.MainWindow"
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:WPFCommandLine"
mc:Ignorable = "d" Title = "MainWindow" Height = "350" Width = "525">
<Grid>
<TextBox x:Name = "textBox" HorizontalAlignment = "Left"
Height = "180" Margin = "100" TextWrapping = "Wrap"
VerticalAlignment = "Top" Width = "300"/>
</Grid>
</Window>
- Teraz zasubskrybuj zdarzenie startowe w pliku App.xaml, jak pokazano poniżej.
<Application x:Class = "WPFCommandLine.App"
xmlns = "http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x = "http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local = "clr-namespace:WPFCommandLine"
StartupUri = "MainWindow.xaml" Startup = "app_Startup">
<Application.Resources>
</Application.Resources>
</Application>
Poniżej podano implementację zdarzenia app_Startup w App.xaml.cs, które otrzyma argumenty wiersza poleceń.
using System.Windows;
namespace WPFCommandLine {
/// <summary>
/// Interaction logic for App.xaml
/// </summary>
public partial class App : Application {
public static string[] Args;
void app_Startup(object sender, StartupEventArgs e) {
// If no command line arguments were provided, don't process them
if (e.Args.Length == 0) return;
if (e.Args.Length > 0) {
Args = e.Args;
}
}
}
}
Teraz w klasie MainWindow program otworzy plik txt i zapisze cały tekst w polu tekstowym.
Jeśli zostanie znaleziony jakiś błąd, program wyświetli komunikat o błędzie w polu tekstowym.
using System;
using System.IO;
using System.Windows;
namespace WPFCommandLine {
public partial class MainWindow : Window {
public MainWindow() {
InitializeComponent();
String[] args = App.Args;
try {
// Open the text file using a stream reader.
using (StreamReader sr = new StreamReader(args[0])) {
// Read the stream to a string, and write
// the string to the text box
String line = sr.ReadToEnd();
textBox.AppendText(line.ToString());
textBox.AppendText("\n");
}
}
catch (Exception e) {
textBox.AppendText("The file could not be read:");
textBox.AppendText("\n");
textBox.AppendText(e.Message);
}
}
}
}
Kiedy powyższy kod zostanie skompilowany i wykonany, utworzy puste okno z polem tekstowym, ponieważ ten program potrzebuje argumentu wiersza poleceń. Dlatego program Visual Studio zapewnia łatwy sposób uruchamiania aplikacji z parametrami wiersza polecenia.
Kliknij prawym przyciskiem myszy projekt WPF w eksploratorze rozwiązań i wybierz właściwości, wyświetli się następujące okno.
Wybierz opcję Debuguj i wpisz ścieżkę do pliku w argumencie wiersza polecenia.
Utwórz plik txt za pomocą Test.txt i napisz tekst w tym pliku i zapisz go w dowolnej lokalizacji. W tym przypadku plik txt jest zapisywany na „D:\" twardy dysk.
Zapisz zmiany w projekcie, a następnie skompiluj i uruchom aplikację. Zobaczysz tekst w TextBox, który program czyta z pliku Text.txt.
Teraz spróbujmy zmienić nazwę pliku na twoim komputerze z Test.txt do Test1.txt i ponownie uruchom program, zobaczysz ten komunikat o błędzie w polu tekstowym.
Zalecamy wykonanie powyższego kodu i wykonanie wszystkich kroków w celu pomyślnego wykonania aplikacji.
Powiązanie danych to mechanizm w aplikacjach WPF, który zapewnia prosty i łatwy sposób wyświetlania danych i interakcji z aplikacjami środowiska wykonawczego systemu Windows. W tym mechanizmie zarządzanie danymi jest całkowicie oddzielone od sposobu, w jaki dane.
Powiązanie danych umożliwia przepływ danych między elementami interfejsu użytkownika a obiektem danych w interfejsie użytkownika. Po ustanowieniu powiązania i zmianie danych lub modelu biznesowego aktualizacje automatycznie odzwierciedlają elementy interfejsu użytkownika i odwrotnie. Możliwe jest również powiązanie nie ze standardowym źródłem danych, ale z innym elementem na stronie.
Powiązanie danych jest dwojakiego rodzaju - one-way data binding i two-way data binding.
Jednokierunkowe wiązanie danych
W powiązaniu jednokierunkowym dane są wiązane ze źródła (czyli obiektu przechowującego dane) do celu (czyli obiektu wyświetlającego dane)
Weźmy prosty przykład, aby szczegółowo zrozumieć jednokierunkowe powiązanie danych. Przede wszystkim utwórz nowy projekt WPF o nazwieWPFDataBinding.
Poniższy kod XAML tworzy dwie etykiety, dwa pola tekstowe i jeden przycisk i inicjuje je z niektórymi właściwościami.
<Window x:Class = "WPFDataBinding.MainWindow"
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:WPFDataBinding"
mc:Ignorable = "d" Title = "MainWindow" Height = "350" Width = "604">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height = "Auto" />
<RowDefinition Height = "Auto" />
<RowDefinition Height = "*" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width = "Auto" />
<ColumnDefinition Width = "200" />
</Grid.ColumnDefinitions>
<Label Name = "nameLabel" Margin = "2">_Name:</Label>
<TextBox Name = "nameText" Grid.Column = "1" Margin = "2"
Text = "{Binding Name, Mode = OneWay}"/>
<Label Name = "ageLabel" Margin = "2" Grid.Row = "1">_Age:</Label>
<TextBox Name = "ageText" Grid.Column = "1" Grid.Row = "1" Margin = "2"
Text = "{Binding Age, Mode = OneWay}"/>
<StackPanel Grid.Row = "2" Grid.ColumnSpan = "2">
<Button Content = "_Show..." Click="Button_Click" />
</StackPanel>
</Grid>
</Window>
Właściwości tekstowe obu pól tekstowych są powiązane z „Imię” i „Wiek”, które są zmiennymi klasowymi klasy Person, która jest pokazana poniżej.
W klasie Person mamy tylko dwie zmienne Name i Age, a jego obiekt jest zainicjowany w MainWindow klasa.
W kodzie XAML jesteśmy powiązani z nazwą właściwości i wiekiem, ale nie wybraliśmy obiektu, do którego należy ta właściwość.
Najłatwiejszym sposobem jest przypisanie obiektu do DataContext których właściwości są wiązane w następującym C # kodzie w MainWindowconstructor.
using System.Windows;
namespace WPFDataBinding {
public partial class MainWindow : Window {
Person person = new Person { Name = "Salman", Age = 26 };
public MainWindow() {
InitializeComponent();
this.DataContext = person;
}
private void Button_Click(object sender, RoutedEventArgs e) {
string message = person.Name + " is " + person.Age;
MessageBox.Show(message);
}
}
public class Person {
private string nameValue;
public string Name {
get { return nameValue; }
set { nameValue = value; }
}
private double ageValue;
public double Age {
get { return ageValue; }
set {
if (value != ageValue) {
ageValue = value;
}
}
}
}
}
Uruchommy tę aplikację i od razu zobaczysz w naszym MainWindow, że pomyślnie powiązaliśmy z obiektem Name i Age tej osoby.
Po naciśnięciu Show przycisk, wyświetli imię i wiek w oknie komunikatu.
Zmieńmy nazwę i wiek w oknie dialogowym.
Jeśli teraz klikniesz przycisk Pokaż, ponownie wyświetli się ten sam komunikat.
Dzieje się tak, ponieważ tryb powiązania danych jest ustawiony na jednokierunkowy w kodzie XAML. Aby wyświetlić zaktualizowane dane, musisz zrozumieć dwukierunkowe powiązanie danych.
Dwukierunkowe wiązanie danych
W przypadku powiązania dwukierunkowego użytkownik może modyfikować dane za pośrednictwem interfejsu użytkownika i aktualizować te dane w źródle. Jeśli źródło zmienia się, gdy użytkownik patrzy na widok, chcesz, aby widok został zaktualizowany.
Weźmy ten sam przykład, ale tutaj zmienimy tryb wiązania z jednokierunkowego na dwukierunkowy w kodzie XAML.
<Window x:Class = "WPFDataBinding.MainWindow"
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:WPFDataBinding"
mc:Ignorable = "d" Title = "MainWindow" Height = "350" Width = "604">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height = "Auto" />
<RowDefinition Height = "Auto" />
<RowDefinition Height = "*" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width = "Auto" />
<ColumnDefinition Width = "200" />
</Grid.ColumnDefinitions>
<Label Name = "nameLabel" Margin = "2">_Name:</Label>
<TextBox Name = "nameText" Grid.Column = "1" Margin = "2"
Text = "{Binding Name, Mode = TwoWay}"/>
<Label Name = "ageLabel" Margin = "2" Grid.Row = "1">_Age:</Label>
<TextBox Name = "ageText" Grid.Column = "1" Grid.Row = "1" Margin = "2"
Text = "{Binding Age, Mode = TwoWay}"/>
<StackPanel Grid.Row = "2" Grid.ColumnSpan = "2">
<Button Content = "_Show..." Click = "Button_Click" />
</StackPanel>
</Grid>
</Window>
Uruchommy ponownie tę aplikację.
Wytworzy ten sam wynik -
Zmieńmy teraz wartości Name i Age -
Jeśli klikniesz teraz przycisk Pokaż, wyświetli zaktualizowany komunikat.
Zalecamy wykonanie powyższego kodu w obu przypadkach, aby lepiej zrozumieć koncepcję.
Zasoby są zwykle definicjami związanymi z jakimś przedmiotem, którego po prostu spodziewasz się używać częściej niż raz. Jest to możliwość lokalnego przechowywania danych dla kontrolek lub dla bieżącego okna lub globalnie dla całych aplikacji.
Zdefiniowanie obiektu jako zasobu umożliwia nam dostęp do niego z innego miejsca. Oznacza to, że przedmiot można ponownie wykorzystać. Zasoby są definiowane w słownikach zasobów, a każdy obiekt można zdefiniować jako zasób, dzięki czemu jest on zasobem, który można udostępniać. Unikatowy klucz jest określony dla zasobu XAML i za pomocą tego klucza można odwoływać się do niego przy użyciu rozszerzenia znaczników StaticResource.
Zasoby mogą być dwojakiego rodzaju -
- StaticResource
- DynamicResource
StaticResource to jednorazowe wyszukiwanie, podczas gdy DynamicResource działa bardziej jak powiązanie danych. Pamięta, że właściwość jest powiązana z określonym kluczem zasobu. Jeśli obiekt skojarzony z tym kluczem ulegnie zmianie, zasób dynamiczny zaktualizuje właściwość docelową.
Przykład
Oto prosta aplikacja dla zasobu SolidColorBrush.
Utwórzmy nowy projekt WPF o nazwie WPFResouces.
Przeciągnij dwa prostokąty i ustaw ich właściwości, jak pokazano w poniższym kodzie XAML.
<Window x:Class = "WPFResources.MainWindow"
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:WPFResources"
mc:Ignorable = "d" Title = "MainWindow" Height = "350" Width = "525">
<Window.Resources>
<SolidColorBrush x:Key = "brushResource" Color = "Blue" />
</Window.Resources>
<StackPanel>
<Rectangle Height = "50" Margin = "20" Fill = "{StaticResource brushResource}" />
<Rectangle Height = "50" Margin = "20" Fill = "{DynamicResource brushResource}" />
<Button x:Name = "changeResourceButton"
Content = "_Change Resource" Click = "changeResourceButton_Click" />
</StackPanel>
</Window>
W powyższym kodzie XAML widać, że jeden prostokąt ma StaticResource, a drugi ma DynamicResource, a kolor brushResource to Bisque.
Kiedy kompilujesz i wykonujesz kod, wygeneruje on następujący plik MainWindow.
Kiedy klikniesz przycisk „Zmień zasób”, zobaczysz, że prostokąt z DynamicResource zmieni kolor na czerwony.
Zakres zasobów
Zasoby są zdefiniowane w resource dictionaries, ale istnieje wiele miejsc, w których można zdefiniować słownik zasobów. W powyższym przykładzie słownik zasobów jest zdefiniowany na poziomie okna / strony. W jakim słowniku zasób jest zdefiniowany, natychmiast ogranicza zakres tego zasobu. Zatem zakres, tj. Gdzie możesz użyć zasobu, zależy od tego, gdzie go zdefiniowałeś.
Zdefiniuj zasób w słowniku zasobów siatki i jest dostępny tylko dla tej siatki i jej elementów podrzędnych.
Zdefiniuj go w oknie / na stronie i jest dostępny dla wszystkich elementów tego okna / strony.
Katalog główny aplikacji można znaleźć w słowniku zasobów App.xaml. Jest to katalog główny naszej aplikacji, więc zdefiniowane tutaj zasoby obejmują całą aplikację.
Jeśli chodzi o zakres zasobu, najczęściej są to poziom aplikacji, poziom strony i określony poziom elementu, taki jak Grid, StackPanel itp.
Powyższa aplikacja ma zasoby na poziomie okna / strony.
Słowniki zasobów
Słowniki zasobów w aplikacjach XAML sugerują, że słowniki zasobów są przechowywane w osobnych plikach. Jest śledzony w prawie wszystkich aplikacjach XAML. Definiowanie zasobów w oddzielnych plikach może mieć następujące zalety -
Separacja między definiowaniem zasobów w słowniku zasobów a kodem związanym z interfejsem użytkownika.
Zdefiniowanie wszystkich zasobów w oddzielnym pliku, takim jak App.xaml, spowodowałoby udostępnienie ich w całej aplikacji.
Jak więc definiujemy nasze zasoby w słowniku zasobów w oddzielnym pliku? Cóż, jest to bardzo łatwe, wystarczy dodać nowy słownik zasobów za pośrednictwem programu Visual Studio, wykonując czynności podane poniżej -
W swoim rozwiązaniu dodaj nowy folder i nadaj mu nazwę ResourceDictionaries.
Kliknij prawym przyciskiem myszy ten folder i wybierz opcję Słownik zasobów z pozycji Dodaj podmenu i nadaj mu nazwę DictionaryWithBrush.xaml
Przykład
Weźmy teraz ten sam przykład, ale tutaj zdefiniujemy słownik zasobów na poziomie aplikacji. Kod XAML dla MainWindow.xaml jest następujący -
<Window x:Class = "WPFResources.MainWindow"
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:WPFResources"
mc:Ignorable = "d" Title = "MainWindow" Height = "350" Width = "525">
<StackPanel>
<Rectangle Height = "50" Margin = "20" Fill = "{StaticResource brushResource}" />
<Rectangle Height = "50" Margin = "20" Fill = "{DynamicResource brushResource}" />
<Button x:Name = "changeResourceButton"
Content = "_Change Resource" Click = "changeResourceButton_Click" />
</StackPanel>
</Window>
Oto implementacja w DictionaryWithBrush.xaml -
<ResourceDictionary xmlns = "http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x = "http://schemas.microsoft.com/winfx/2006/xaml">
<SolidColorBrush x:Key = "brushResource" Color = "Blue" />
</ResourceDictionary>
Oto implementacja w app.xaml -
<Application x:Class="WPFResources.App"
xmlns = "http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x = "http://schemas.microsoft.com/winfx/2006/xaml"
StartupUri = "MainWindow.xaml">
<Application.Resources>
<ResourceDictionary Source = " XAMLResources\ResourceDictionaries\DictionaryWithBrush.xaml"/>
</Application.Resources>
</Application>
Gdy powyższy kod zostanie skompilowany i wykonany, wygeneruje następujący wynik -
Po kliknięciu przycisku Zmień zasób prostokąt zmieni kolor na czerwony.
Zalecamy wykonanie powyższego kodu i wypróbowanie dodatkowych zasobów (na przykład koloru tła).
Szablon opisuje ogólny wygląd i wygląd kontrolki. Z każdą kontrolką skojarzony jest domyślny szablon, który nadaje formantowi jej wygląd. W aplikacjach WPF można łatwo tworzyć własne szablony, gdy chcesz dostosować zachowanie wizualne i wygląd kontrolki.
Łączność między logiką a szablonem można osiągnąć za pomocą powiązania danych. Główna różnica międzystyles i templates są wymienione poniżej -
Style mogą zmieniać wygląd kontrolki tylko przy użyciu domyślnych właściwości tej kontrolki.
Dzięki szablonom możesz uzyskać dostęp do większej liczby części kontrolki niż w stylach. Możesz również określić istniejące i nowe zachowanie formantu.
Istnieją dwa typy najczęściej używanych szablonów -
- Szablon kontroli
- Szablon danych
Szablon kontroli
Szablon kontrolny definiuje wizualny wygląd kontrolki. Wszystkie elementy interfejsu użytkownika mają pewien rodzaj wyglądu i zachowania, np. Button ma wygląd i zachowanie. Zdarzenie kliknięcia lub najechania myszą to zachowania wywoływane w odpowiedzi na kliknięcie i najechanie myszą, a także domyślny wygląd przycisku, który można zmienić za pomocą szablonu sterowania.
Przykład
Weźmy prosty przykład. Stworzymy dwa przyciski (jeden jest z szablonem, a drugi jest przyciskiem domyślnym) i zainicjujemy je niektórymi właściwościami.
<Window x:Class = "TemplateDemo.MainWindow"
xmlns = "http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x = "http://schemas.microsoft.com/winfx/2006/xaml"
Title = "MainWindow" Height = "350" Width = "604">
<Window.Resources>
<ControlTemplate x:Key = "ButtonTemplate" TargetType = "Button">
<Grid>
<Ellipse x:Name = "ButtonEllipse" Height = "100" Width = "150" >
<Ellipse.Fill>
<LinearGradientBrush StartPoint = "0,0.2" EndPoint = "0.2,1.4">
<GradientStop Offset = "0" Color = "Red" />
<GradientStop Offset = "1" Color = "Orange" />
</LinearGradientBrush>
</Ellipse.Fill>
</Ellipse>
<ContentPresenter Content = "{TemplateBinding Content}"
HorizontalAlignment = "Center" VerticalAlignment = "Center" />
</Grid>
<ControlTemplate.Triggers>
<Trigger Property = "IsMouseOver" Value = "True">
<Setter TargetName = "ButtonEllipse" Property = "Fill" >
<Setter.Value>
<LinearGradientBrush StartPoint = "0,0.2" EndPoint = "0.2,1.4">
<GradientStop Offset = "0" Color = "YellowGreen" />
<GradientStop Offset = "1" Color = "Gold" />
</LinearGradientBrush>
</Setter.Value>
</Setter>
</Trigger>
<Trigger Property = "IsPressed" Value = "True">
<Setter Property = "RenderTransform">
<Setter.Value>
<ScaleTransform ScaleX = "0.8" ScaleY = "0.8"
CenterX = "0" CenterY = "0" />
</Setter.Value>
</Setter>
<Setter Property = "RenderTransformOrigin" Value = "0.5,0.5" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Window.Resources>
<StackPanel>
<Button Content = "Round Button!"
Template = "{StaticResource ButtonTemplate}"
Width = "150" Margin = "50" />
<Button Content = "Default Button!" Height = "40"
Width = "150" Margin = "5" />
</StackPanel>
</Window>
Kiedy kompilujesz i wykonujesz powyższy kod, wyświetli się następujący plik MainWindow.
Po najechaniu myszą na przycisk z niestandardowym szablonem zmieni on swój kolor, jak pokazano poniżej.
Szablon danych
Szablon danych definiuje i określa wygląd i strukturę zbioru danych. Zapewnia elastyczność formatowania i definiowania prezentacji danych w dowolnym elemencie interfejsu użytkownika. Jest głównie używany w kontrolkach elementów związanych z danymi, takich jak ComboBox, ListBox itp.
Przykład
Weźmy prosty przykład, aby zrozumieć pojęcie szablonu danych. Utwórz nowy projekt WPF o nazwieWPFDataTemplates.
W poniższym kodzie XAML utworzymy szablon danych jako zasób do przechowywania etykiet i pól tekstowych. Dostępny jest również przycisk i pole listy, na których można wyświetlić dane.
<Window x:Class = "WPFDataTemplates.MainWindow"
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:WPFDataTemplates"
xmlns:loc = "clr-namespace:WPFDataTemplates"
mc:Ignorable = "d" Title = "MainWindow" Height = "350" Width = "525">
<Window.Resources>
<DataTemplate DataType = "{x:Type loc:Person}">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height = "Auto" />
<RowDefinition Height = "Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width = "Auto" />
<ColumnDefinition Width = "200" />
</Grid.ColumnDefinitions>
<Label Name = "nameLabel" Margin = "10"/>
<TextBox Name = "nameText" Grid.Column = "1" Margin = "10"
Text = "{Binding Name}"/>
<Label Name = "ageLabel" Margin = "10" Grid.Row = "1"/>
<TextBox Name = "ageText" Grid.Column = "1" Grid.Row = "1" Margin = "10"
Text = "{Binding Age}"/>
</Grid>
</DataTemplate>
</Window.Resources>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height = "Auto" />
<RowDefinition Height = "*" />
</Grid.RowDefinitions>
<ListBox ItemsSource = "{Binding}" />
<StackPanel Grid.Row = "1" >
<Button Content = "_Show..." Click = "Button_Click" Width = "80" HorizontalAlignment = "Left" Margin = "10"/>
</StackPanel>
</Grid>
</Window>
Tutaj jest implementation in C# w którym lista obiektów Person jest przypisana do DataContext, implementacja klasy Person i zdarzenie kliknięcia przycisku.
using System.Collections.Generic;
using System.Windows;
namespace WPFDataTemplates {
public partial class MainWindow : Window {
Person src = new Person { Name = "Ali", Age = 27 };
List<Person> people = new List<Person>();
public MainWindow() {
InitializeComponent();
people.Add(src);
people.Add(new Person { Name = "Mike", Age = 62 });
people.Add(new Person { Name = "Brian", Age = 12 });
this.DataContext = people;
}
private void Button_Click(object sender, RoutedEventArgs e) {
string message = src.Name + " is " + src.Age;
MessageBox.Show(message);
}
}
public class Person {
private string nameValue;
public string Name {
get { return nameValue; }
set { nameValue = value; }
}
private double ageValue;
public double Age {
get { return ageValue; }
set {
if (value != ageValue) {
ageValue = value;
}
}
}
}
}
Kiedy kompilujesz i wykonujesz powyższy kod, wyświetli się następujące okno. Zawiera jedną listę, a wewnątrz pola listy, każdy element listy zawiera dane obiektu klasy Person, które są wyświetlane w etykietach i polach tekstowych.
Platforma .NET udostępnia kilka strategii personalizacji i dostosowywania wyglądu aplikacji. Style zapewniają nam elastyczność w ustawianiu niektórych właściwości obiektu i ponownym użyciu tych konkretnych ustawień w wielu obiektach w celu uzyskania spójnego wyglądu.
W stylach możesz ustawić tylko istniejące właściwości obiektu, takie jak wysokość, szerokość, rozmiar czcionki itp.
Można określić tylko domyślne zachowanie formantu.
Do jednego stylu można dodać wiele właściwości.
Style służą do nadania jednolitego wyglądu lub zestawu kontrolek. Niejawne style służą do zastosowania wyglądu do wszystkich kontrolek danego typu i uproszczenia aplikacji. Wyobraź sobie trzy przyciski, wszystkie muszą wyglądać tak samo, mieć taką samą szerokość i wysokość, ten sam rozmiar czcionki, ten sam kolor pierwszego planu itp. Możemy ustawić wszystkie te właściwości na samych elementach przycisków i nadal jest to całkiem w porządku dla wszystkich przycisków. Spójrz na poniższy diagram.
Jednak w rzeczywistych aplikacjach zazwyczaj będzie ich znacznie więcej, które muszą wyglądać dokładnie tak samo. Oczywiście nie tylko przyciski, ale zazwyczaj chcesz, aby bloki tekstowe, pola tekstowe i pola kombi itp. Wyglądały tak samo w całej aplikacji. Z pewnością musi istnieć lepszy sposób na osiągnięcie tego i jest on znany jakostyling. Możesz myśleć o stylu jako o wygodnym sposobie zastosowania zestawu wartości właściwości do więcej niż jednego elementu. Spójrz na poniższy diagram.
Przykład
Weźmy prosty przykład, aby zrozumieć tę koncepcję. Zacznij od utworzenia nowego projektu WPF.
Przeciągnij trzy przyciski z przybornika do okna projektu.
Poniższy kod XAML tworzy trzy przyciski i inicjuje je z niektórymi właściwościami.
<Window x:Class = "WPFStyle.MainWindow"
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: WPFStyle"
mc:Ignorable = "d" Title = "MainWindow" Height = "350" Width = "604">
<StackPanel>
<Button Content = "Button1" Height = "30" Width = "80"
Foreground = "Blue" FontSize = "12" Margin = "10"/>
<Button Content = "Button2" Height = "30" Width = "80"
Foreground = "Blue" FontSize = "12" Margin = "10"/>
<Button Content = "Button3" Height = "30" Width = "80"
Foreground = "Blue" FontSize = "12" Margin = "10"/>
</StackPanel>
</Window>
Kiedy spojrzysz na powyższy kod, zobaczysz, że dla wszystkich przycisków wysokość, szerokość, kolor pierwszego planu, rozmiar czcionki i właściwości marginesów są takie same. Teraz, gdy powyższy kod zostanie skompilowany i wykonany, zostanie wyświetlone następujące okno.
Spójrzmy teraz na ten sam przykład, ale tym razem będziemy używać style.
<Window x:Class = "XAMLStyle.MainWindow"
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:XAMLStyle"
mc:Ignorable = "d" Title = "MainWindow" Height = "350" Width = "604">
<Window.Resources>
<Style x:Key = "myButtonStyle" TargetType = "Button">
<Setter Property = "Height" Value = "30" />
<Setter Property = "Width" Value = "80" />
<Setter Property = "Foreground" Value = "Blue" />
<Setter Property = "FontSize" Value = "12" />
<Setter Property = "Margin" Value = "10" />
</Style>
</Window.Resources>
<StackPanel>
<Button Content = "Button1" Style = "{StaticResource myButtonStyle}" />
<Button Content = "Button2" Style = "{StaticResource myButtonStyle}" />
<Button Content = "Button3" Style="{StaticResource myButtonStyle}" />
</StackPanel>
</Window>
Style są zdefiniowane w słowniku zasobów, a każdy styl ma unikalny identyfikator klucza i typ docelowy. Wewnątrz elementu <style> widać, że dla każdej właściwości, która zostanie uwzględniona w stylu, zdefiniowano wiele tagów ustawiających.
W powyższym przykładzie wszystkie wspólne właściwości każdego przycisku są teraz zdefiniowane w stylu, a następnie styl jest przypisywany do każdego przycisku z unikalnym kluczem przez ustawienie właściwości stylu za pomocą rozszerzenia znaczników StaticResource.
Kiedy kompilujesz i wykonujesz powyższy kod, wyświetli się następujące okno (to samo wyjście).
Zaleta zrobienia tego w ten sposób jest od razu oczywista, możemy ponownie użyć tego stylu w dowolnym miejscu jego zakresu; a jeśli musimy to zmienić, po prostu zmieniamy to raz w definicji stylu zamiast w każdym elemencie.
Na jakim poziomie styl jest definiowany natychmiastowo ogranicza zakres tego stylu. Zatem zakres, tj. Gdzie możesz użyć stylu, zależy od tego, gdzie go zdefiniowałeś. Style można definiować na następujących poziomach -
Sr.No | Poziomy i opis |
---|---|
1 | Poziom kontroli Zdefiniowanie stylu na poziomie kontroli można zastosować tylko do tej konkretnej kontrolki. Poniżej podano przykład poziomu sterowania, na którym przycisk i TextBlock mają swój własny styl. |
2 | Poziom układu Zdefiniowanie stylu na dowolnym poziomie układu spowoduje, że będzie on dostępny tylko dla tego układu i jego elementów podrzędnych. |
3 | Poziom okna Zdefiniowanie stylu na poziomie okna może sprawić, że będzie on dostępny dla wszystkich elementów w tym oknie. |
4 | Poziom aplikacji Zdefiniowanie stylu na poziomie aplikacji może sprawić, że będzie on dostępny w całej aplikacji. Weźmy ten sam przykład, ale tutaj umieścimy style w pliku app.xaml, aby był dostępny w całej aplikacji. |
Wyzwalacz zasadniczo umożliwia zmianę wartości właściwości lub podejmowanie działań na podstawie wartości właściwości. Dzięki temu możesz dynamicznie zmieniać wygląd i / lub zachowanie twojego elementu sterującego bez konieczności tworzenia nowego.
Wyzwalacze służą do zmiany wartości dowolnej właściwości, gdy spełnione są określone warunki. Wyzwalacze są zwykle definiowane w stylu lub w katalogu głównym dokumentu, które są stosowane do tej konkretnej kontrolki. Istnieją trzy rodzaje wyzwalaczy -
- Wyzwalacze właściwości
- Wyzwalacze danych
- Wyzwalacze zdarzeń
Wyzwalacze właściwości
W wyzwalaczach właściwości, gdy zmiana nastąpi w jednej właściwości, przyniesie natychmiastową lub animowaną zmianę w innej właściwości. Można na przykład użyć wyzwalacza właściwości, aby zmienić wygląd przycisku, gdy wskaźnik myszy znajduje się nad przyciskiem.
Poniższy przykładowy kod pokazuje, jak zmienić kolor pierwszego planu przycisku, gdy wskaźnik myszy znajduje się nad przyciskiem.
<Window x:Class = "WPFPropertyTriggers.MainWindow"
xmlns = "http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x = "http://schemas.microsoft.com/winfx/2006/xaml"
Title = "MainWindow" Height = "350" Width = "604">
<Window.Resources>
<Style x:Key = "TriggerStyle" TargetType = "Button">
<Setter Property = "Foreground" Value = "Blue" />
<Style.Triggers>
<Trigger Property = "IsMouseOver" Value = "True">
<Setter Property = "Foreground" Value = "Green" />
</Trigger>
</Style.Triggers>
</Style>
</Window.Resources>
<Grid>
<Button Width = "100" Height = "70"
Style = "{StaticResource TriggerStyle}" Content = "Trigger"/>
</Grid>
</Window>
Kiedy kompilujesz i wykonujesz powyższy kod, wygeneruje on następujące okno -
Gdy mysz znajdzie się nad przyciskiem, jego kolor pierwszego planu zmieni się na zielony.
Wyzwalacze danych
Wyzwalacz danych wykonuje pewne akcje, gdy powiązane dane spełniają pewne warunki. Przyjrzyjmy się poniższemu kodowi XAML, w którym pole wyboru i blok tekstu są tworzone z niektórymi właściwościami. Zaznaczenie tego pola wyboru spowoduje zmianę koloru pierwszego planu na czerwony.
<Window x:Class = "WPFDataTrigger.MainWindow"
xmlns = "http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x = "http://schemas.microsoft.com/winfx/2006/xaml"
Title = "Data Trigger" Height = "350" Width = "604">
<StackPanel HorizontalAlignment = "Center">
<CheckBox x:Name = "redColorCheckBox"
Content = "Set red as foreground color" Margin = "20"/>
<TextBlock Name = "txtblock" VerticalAlignment = "Center"
Text = "Event Trigger" FontSize = "24" Margin = "20">
<TextBlock.Style>
<Style>
<Style.Triggers>
<DataTrigger Binding = "{Binding ElementName = redColorCheckBox, Path = IsChecked}"
Value = "true">
<Setter Property = "TextBlock.Foreground" Value = "Red"/>
<Setter Property = "TextBlock.Cursor" Value = "Hand" />
</DataTrigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
</TextBlock>
</StackPanel>
</Window>
Gdy powyższy kod zostanie skompilowany i wykonany, wygeneruje następujący wynik -
Po zaznaczeniu tego pola wyboru blok tekstu zmieni kolor pierwszego planu na czerwony.
Wyzwalacze zdarzeń
Wyzwalacz zdarzenia wykonuje pewne akcje, gdy zostanie wyzwolone określone zdarzenie. Zwykle jest używany do tworzenia animacji na sterowaniu, takich jak DoubleAnumatio, ColorAnimation itp. W poniższym przykładzie utworzymy prosty przycisk. Uruchomione zdarzenie kliknięcia spowoduje zwiększenie szerokości i wysokości przycisku.
<Window x:Class = "WPFEventTrigger.MainWindow"
xmlns = "http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x = "http://schemas.microsoft.com/winfx/2006/xaml"
Title = "MainWindow" Height = "350" Width = "604">
<Grid>
<Button Content = "Click Me" Width = "60" Height = "30">
<Button.Triggers>
<EventTrigger RoutedEvent = "Button.Click">
<EventTrigger.Actions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty =
"Width" Duration = "0:0:4">
<LinearDoubleKeyFrame Value = "60" KeyTime = "0:0:0"/>
<LinearDoubleKeyFrame Value = "120" KeyTime = "0:0:1"/>
<LinearDoubleKeyFrame Value = "200" KeyTime = "0:0:2"/>
<LinearDoubleKeyFrame Value = "300" KeyTime = "0:0:3"/>
</DoubleAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty = "Height"
Duration = "0:0:4">
<LinearDoubleKeyFrame Value = "30" KeyTime = "0:0:0"/>
<LinearDoubleKeyFrame Value = "40" KeyTime = "0:0:1"/>
<LinearDoubleKeyFrame Value = "80" KeyTime = "0:0:2"/>
<LinearDoubleKeyFrame Value = "150" KeyTime = "0:0:3"/>
</DoubleAnimationUsingKeyFrames>
</Storyboard>
</BeginStoryboard>
</EventTrigger.Actions>
</EventTrigger>
</Button.Triggers>
</Button>
</Grid>
</Window>
Kiedy kompilujesz i wykonujesz powyższy kod, wygeneruje on następujące okno -
Po kliknięciu przycisku zauważysz, że zacznie się on rozszerzać w obu wymiarach.
Zalecamy skompilowanie i wykonanie powyższych przykładów oraz zastosowanie wyzwalaczy również do innych właściwości.
Jest to systematyczny mechanizm identyfikowania i naprawiania błędów lub usterek w fragmencie kodu, który nie zachowuje się tak, jak się spodziewasz. Debugowanie złożonej aplikacji, w której podsystemy są ściśle powiązane, nie jest takie łatwe, ponieważ naprawianie błędów w jednym podsystemie może powodować błędy w innym podsystemie.
Debugowanie w C #
W aplikacjach WPF programiści mają do czynienia z dwoma językami, takimi jak C # i XAML. Jeśli znasz debugowanie w jakimkolwiek języku proceduralnym, takim jak C # lub C / C ++, i znasz również użycie punktów przerwania, możesz łatwo debugować część C # aplikacji.
Weźmy prosty przykład, aby zademonstrować, jak debugować kod C #. Utwórz nowy projekt WPF o nazwieWPFDebuggingDemo. Przeciągnij cztery etykiety, trzy pola tekstowe i jeden przycisk z przybornika. Spójrz na następujący kod XAML.
<Window x:Class = "WPFDebuggingDemo.Window1"
xmlns = "http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x = "http://schemas.microsoft.com/winfx/2006/xaml"
Title = "Window1" Height = "400" Width = "604">
<Grid>
<TextBox Height = "23" Margin = "0,44,169,0" Name = "textBox1"
VerticalAlignment = "Top" HorizontalAlignment = "Right" Width = "120" />
<TextBox Height = "23" Margin = "0,99,169,0" Name = "textBox2"
VerticalAlignment = "Top" HorizontalAlignment = "Right" Width = "120" />
<TextBox HorizontalAlignment = "Right" Margin = "0,153,169,0"
Name = "textBox3" Width = "120" Height = "23" VerticalAlignment = "Top" />
<Label Height = "28" Margin = "117,42,0,0" Name = "label1"
VerticalAlignment = "Top" HorizontalAlignment = "Left" Width = "120">
Item 1</Label>
<Label Height = "28" HorizontalAlignment = "Left"
Margin = "117,99,0,0" Name = "label2" VerticalAlignment = "Top" Width = "120">
Item 2</Label>
<Label HorizontalAlignment = "Left" Margin = "117,153,0,181"
Name = "label3" Width = "120">Item 3</Label>
<Button Height = "23" HorizontalAlignment = "Right" Margin = "0,0,214,127"
Name = "button1" VerticalAlignment = "Bottom" Width = "75"
Click = "button1_Click">Total</Button>
<Label Height = "28" HorizontalAlignment = "Right"
Margin = "0,0,169,66" Name = "label4" VerticalAlignment = "Bottom" Width = "120"/>
</Grid>
</Window>
Poniżej podano kod C #, w którym zaimplementowano zdarzenie kliknięcia przycisku.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace WPFDebuggingDemo {
/// <summary>
/// Interaction logic for Window1.xaml
/// </summary>
public partial class Window1 : Window {
public Window1() {
InitializeComponent();
}
private void button1_Click(object sender, RoutedEventArgs e) {
if (textBox1.Text.Length > 0 && textBox2.Text.Length > 0 && textBox2.Text.Length > 0) {
double total = Convert.ToDouble(textBox1.Text) +
Convert.ToDouble(textBox2.Text) + Convert.ToDouble(textBox3.Text);
label4.Content = total.ToString();
}
else {
MessageBox.Show("Enter the value in all field.");
}
}
}
}
Kiedy kompilujesz i wykonujesz powyższy kod, wyświetli się następujące okno. Teraz wprowadź wartości w pola tekstowe i naciśnij przycisk Suma. Łączną wartość uzyskasz po zsumowaniu wszystkich wartości wprowadzonych w pola tekstowe.
Jeśli spróbujesz wprowadzić wartości inne niż wartości rzeczywiste, powyższa aplikacja ulegnie awarii. Aby znaleźć i rozwiązać problem (dlaczego się zawiesza), możesz wstawić punkty przerwania w zdarzeniu kliknięcia przycisku.
Napiszmy „abc” w punkcie 1, jak pokazano poniżej.
Po kliknięciu przycisku Suma, zobaczysz, że program zatrzymuje się w punkcie przerwania
Teraz przesuń kursor w kierunku pola textbox1.Text, a zobaczysz, że program próbuje dodać abc wartość z innymi wartościami, co jest przyczyną awarii programu.
Debugowanie w XAML
Jeśli spodziewasz się tego samego rodzaju debugowania w XAML, będziesz zaskoczony, wiedząc, że nie można jeszcze debugować kodu XAML, takiego jak debugowanie dowolnego innego kodu języka proceduralnego. Gdy usłyszysz termin debugowanie w kodzie XAML, oznacza to, że spróbuj znaleźć błąd.
W powiązaniu danych Twoje dane nie pojawiają się na ekranie i nie wiesz dlaczego
Lub problem jest związany ze złożonymi układami.
Lub problem z wyrównaniem lub problemy z kolorem marginesów, nakładkami itp. W przypadku niektórych rozbudowanych szablonów, takich jak ListBox i pole kombi.
Debugowanie programu XAML jest zwykle wykonywane w celu sprawdzenia, czy powiązania działają; a jeśli nie działa, to sprawdź, co jest nie tak. Niestety ustawienie punktów przerwania w powiązaniach XAML nie jest możliwe, z wyjątkiem Silverlight, ale możemy użyć okna danych wyjściowych, aby sprawdzić błędy powiązań danych. Przyjrzyjmy się poniższemu kodowi XAML, aby znaleźć błąd w powiązaniu danych.
<Window x:Class = "DataBindingOneWay.MainWindow"
xmlns = "http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x = "http://schemas.microsoft.com/winfx/2006/xaml"
Title = "MainWindow" Height = "350" Width = "604">
<Grid>
<StackPanel Name = "Display">
<StackPanel Orientation = "Horizontal" Margin = "50, 50, 0, 0">
<TextBlock Text = "Name: " Margin = "10" Width = "100"/>
<TextBlock Margin = "10" Width = "100" Text = "{Binding FirstName}"/>
</StackPanel>
<StackPanel Orientation = "Horizontal" Margin = "50,0,50,0">
<TextBlock Text = "Title: " Margin = "10" Width = "100"/>
<TextBlock Margin = "10" Width = "100" Text = "{Binding Title}" />
</StackPanel>
</StackPanel>
</Grid>
</Window>
Właściwości tekstu dwóch bloków tekstowych są ustawione statycznie na „Nazwisko” i „Tytuł”, podczas gdy pozostałe dwa bloki tekstowe Właściwości tekstu są powiązane z „Imię” i „Tytuł”, ale zmiennymi klasowymi są Nazwisko i Tytuł w klasie pracownika, co pokazano poniżej.
Celowo napisaliśmy niepoprawną nazwę zmiennej, aby zrozumieć, gdzie możemy znaleźć tego typu błąd, gdy pożądane wyjście nie jest wyświetlane.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace DataBindingOneWay {
public class Employee {
public string Name { get; set; }
public string Title { get; set; }
public static Employee GetEmployee() {
var emp = new Employee() {
Name = "Ali Ahmed", Title = "Developer"
};
return emp;
}
}
}
Oto implementacja klasy MainWindow w kodzie C #.
using System;
using System.Windows;
using System.Windows.Controls;
namespace DataBindingOneWay {
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window {
public MainWindow() {
InitializeComponent();
DataContext = Employee.GetEmployee();
}
}
}
Uruchommy tę aplikację i od razu zobaczysz w naszym MainWindow, że pomyślnie powiązaliśmy z tytułem tego obiektu pracownika, ale nazwa nie jest powiązana.
Aby sprawdzić, co się stało z nazwą, spójrzmy do okna wyjściowego, w którym generowanych jest dużo dzienników.
Łatwo znaleźć błąd, po prostu wyszukując błąd, a znajdziesz następujący komunikat o błędzie „Błąd ścieżki BindingExpression: Nie znaleziono właściwości„ FirstName ”w„ obiekcie ”„ Pracownik ”
System.Windows.Data Error: 40 : BindingExpression path error: 'FirstName'
property not found on 'object' ''Employee' (HashCode=11611730)'.
BindingExpression:Path = FirstName; DataItem = 'Employee' (HashCode = 11611730);
target element is 'TextBlock' (Name=''); target property is 'Text' (type 'String')
Co wyraźnie wskazuje, że FirstName nie jest członkiem klasy Employee, więc pomaga rozwiązać tego typu problemy w aplikacji.
Po ponownej zmianie FirstName na Name, zobaczysz żądane dane wyjściowe.
Narzędzia do debugowania interfejsu użytkownika dla języka XAML
Narzędzia do debugowania interfejsu użytkownika zostały wprowadzone dla języka XAML w programie Visual Studio 2015 w celu sprawdzenia kodu XAML w czasie wykonywania. Za pomocą tych narzędzi kod XAML jest przedstawiany w postaci wizualnego drzewa uruchomionej aplikacji WPF, a także różnych właściwości elementu interfejsu użytkownika w drzewie. Aby włączyć te narzędzia, wykonaj czynności podane poniżej.
- Przejdź do menu Narzędzia i wybierz Opcje z menu Narzędzia.
- Otworzy się następujące okno dialogowe.
- Przejdź do opcji ogólnych w pozycji Debugowanie po lewej stronie.
- Zaznacz podświetloną opcję, tj. „Włącz narzędzia debugowania interfejsu użytkownika dla języka XAML” i kliknij przycisk OK.
Teraz uruchom dowolną aplikację XAML lub użyj następującego kodu XAML.
<Window x:Class = "XAMLTestBinding.MainWindow"
xmlns = "http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x = "http://schemas.microsoft.com/winfx/2006/xaml"
Title = "MainWindow" Height = "350" Width = "604">
<StackPanel>
<ComboBox Name = "comboBox" Margin = "50" Width = "100">
<ComboBoxItem Content = "Green" />
<ComboBoxItem Content = "Yellow" IsSelected = "True" />
<ComboBoxItem Content = "Orange" />
</ComboBox>
<TextBox Name = "textBox" Margin = "50" Width = "100" Height = "23"
VerticalAlignment = "Top" Text =
"{Binding ElementName = comboBox, Path = SelectedItem.Content, Mode = TwoWay, UpdateSourceTrigger = PropertyChanged}"
Background = "{Binding ElementName = comboBox, Path = SelectedItem.Content}">
</TextBox>
</StackPanel>
</Window>
Po uruchomieniu aplikacji wyświetli się aktywne drzewo wizualne, w którym wszystkie elementy są pokazane w drzewie.
To drzewo wizualne na żywo przedstawia pełną strukturę układu, aby zrozumieć, gdzie znajdują się elementy interfejsu użytkownika. Ale ta opcja jest dostępna tylko w programie Visual Studio 2015. Jeśli używasz starszej opcji programu Visual Studio, nie możesz użyć tego narzędzia, jednak istnieje inne narzędzie, które można zintegrować z programem Visual Studio, takie jak XAML Spy for Visual Studio . Możesz go pobrać z xamlspy
Aplikacje WPF umożliwiają tworzenie niestandardowych formantów, co bardzo ułatwia tworzenie bogatych w funkcje i dostosowywalnych formantów. Kontrolki niestandardowe są używane, gdy wszystkie wbudowane kontrolki dostarczone przez firmę Microsoft nie spełniają Twoich kryteriów lub nie chcesz płacić za kontrolki innych firm.
W tym rozdziale dowiesz się, jak tworzyć niestandardowe kontrolki. Zanim zaczniemy przyglądać się kontrolkom niestandardowym, przyjrzyjmy się najpierw kontroli użytkownika.
Kontrola użytkownika
Kontrolki użytkownika umożliwiają zbieranie i łączenie różnych wbudowanych kontrolek razem i pakowanie ich w kod XAML wielokrotnego użytku. Kontrolki użytkownika są używane w następujących scenariuszach -
Jeśli formant składa się z istniejących formantów, tj. Można utworzyć pojedynczą kontrolkę z wielu już istniejących formantów.
Jeśli formant nie potrzebuje obsługi motywów. Formanty użytkownika nie obsługują skomplikowanych dostosowań, szablonów formantów i trudnych do stylizacji.
Jeśli programista woli pisać kontrolki przy użyciu modelu związanego z kodem, w którym widok, a następnie bezpośredni kod dla programów obsługi zdarzeń.
Nie będziesz dzielić kontroli nad aplikacjami.
Przykład
Przejdźmy do przykładu kontroli użytkownika i wykonaj kroki podane poniżej.
Utwórz nowy projekt WPF, a następnie kliknij prawym przyciskiem myszy rozwiązanie i wybierz Dodaj> Nowy element ...
Otworzy się następujące okno. Teraz wybierzUser Control (WPF) i nazwij go MyUserControl.
Kliknij przycisk Dodaj, a zobaczysz, że dwa nowe pliki (MyUserControl.xaml i MyUserControl.cs) zostaną dodane do Twojego rozwiązania.
Oto kod XAML, w którym jest tworzony przycisk i pole tekstowe z niektórymi właściwościami w pliku MyUserControl.xaml.
<UserControl x:Class = "WPFUserControl.MyUserControl"
xmlns = "http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x = "http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc = "http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d = "http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable = "d" d:DesignHeight = "300" d:DesignWidth = "300">
<Grid>
<TextBox Height = "23"
HorizontalAlignment = "Left"
Margin = "80,49,0,0" Name = "txtBox"
VerticalAlignment = "Top" Width = "200" />
<Button Content = "Click Me"
Height = "23" HorizontalAlignment = "Left"
Margin = "96,88,0,0" Name = "button"
VerticalAlignment = "Top" Click = "button_Click" />
</Grid>
</UserControl>
Poniżej podano kod C # zdarzenia kliknięcia przycisku w pliku MyUserControl.cs, który aktualizuje pole tekstowe.
using System;
using System.Windows;
using System.Windows.Controls;
namespace WPFUserControl {
/// <summary>
/// Interaction logic for MyUserControl.xaml
/// </summary>
public partial class MyUserControl : UserControl {
public MyUserControl() {
InitializeComponent();
}
private void button_Click(object sender, RoutedEventArgs e) {
txtBox.Text = "You have just clicked the button";
}
}
}
Oto implementacja w MainWindow.xaml, aby dodać kontrolkę użytkownika.
<Window x:Class = "XAMLUserControl.MainWindow"
xmlns = "http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x = "http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:control = "clr-namespace:WPFUserControl"
Title = "MainWindow" Height = "350" Width = "525">
<Grid>
<control:MyUserControl/>
</Grid>
</Window>
Kiedy kompilujesz i wykonujesz powyższy kod, wyświetli się następujące okno.
Po kliknięciu przycisku „Kliknij mnie” zauważysz, że tekst w polu tekstowym został zaktualizowany.
Kontrole niestandardowe
Kontrolka niestandardowa to klasa oferująca własny styl i szablon, które są zwykle zdefiniowane w pliku generic.xaml. Kontrolki niestandardowe są używane w następujących scenariuszach -
Jeśli kontrolka nie istnieje i musisz ją utworzyć od podstaw.
Jeśli chcesz rozszerzyć lub dodać funkcjonalność do istniejącej kontrolki, dodając dodatkową właściwość lub dodatkową funkcjonalność w celu dopasowania do konkretnego scenariusza.
Jeśli Twoje elementy sterujące wymagają obsługi motywów i stylizacji.
Jeśli chcesz dzielić kontrolę nad aplikacjami.
Przykład
Weźmy przykład, aby zrozumieć, jak działają niestandardowe kontrolki. Utwórz nowy projekt WPF, a następnie kliknij prawym przyciskiem myszy rozwiązanie i wybierz Dodaj> Nowy element ...
Otworzy się następujące okno. Teraz wybierzCustom Control (WPF) i nazwij to MyCustomControl.
Kliknij przycisk Dodaj, a zobaczysz, że dwa nowe pliki (Themes / Generic.xaml i MyCustomControl.cs) zostaną dodane do twojego rozwiązania.
Oto kod XAML, w którym styl jest ustawiony dla kontrolki niestandardowej w pliku Generic.xaml.
<ResourceDictionary
xmlns = "http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x = "http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local = "clr-namespace:WPFCustomControls">
<Style TargetType = "{x:Type local:MyCustomControl}"
BasedOn = "{StaticResource {x:Type Button}}">
<Setter Property = "Background" Value = "LightSalmon" />
<Setter Property = "Foreground" Value = "Blue"/>
</Style>
</ResourceDictionary>
Oto kod C # dla klasy MyCustomControl, który jest dziedziczony z klasy przycisku iw konstruktorze przesłania metadane.
using System;
using System.Windows;
using System.Windows.Controls;
namespace WPFCustomControls {
public class MyCustomControl : Button {
static MyCustomControl() {
DefaultStyleKeyProperty.OverrideMetadata(typeof(MyCustomControl), new
FrameworkPropertyMetadata(typeof(MyCustomControl)));
}
}
}
Oto implementacja zdarzenia kliknięcia kontrolki niestandardowej w języku C #, która aktualizuje tekst bloku tekstu.
using System;
using System.Windows;
using System.Windows.Controls;
namespace WPFCustomControls {
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window {
public MainWindow() {
InitializeComponent();
}
private void customControl_Click(object sender, RoutedEventArgs e) {
txtBlock.Text = "You have just click your custom control";
}
}
}
Oto implementacja w MainWindow.xaml, aby dodać niestandardową kontrolkę i TextBlock.
<Window x:Class = "WPFCustomControls.MainWindow"
xmlns = "http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x = "http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:control = "clr-namespace:WPFCustomControls"
Title = "MainWindow" Height = "350" Width = "604">
<StackPanel>
<control:MyCustomControl x:Name = "customControl"
Content = "Click Me" Width = "70"
Margin = "10" Click = "customControl_Click"/>
<TextBlock Name = "txtBlock"
Width = "250" Height = "30"/>
</StackPanel>
</Window>
Kiedy kompilujesz i wykonujesz powyższy kod, utworzy on następujące okno z niestandardową kontrolką, która jest dostosowanym przyciskiem.
Po kliknięciu dostosowanego przycisku zobaczysz, że tekst w bloku tekstowym jest aktualizowany.
Wyjątkiem jest każdy stan błędu lub nieoczekiwane zachowanie napotkane podczas wykonywania programu. Wyjątki można zgłaszać z wielu powodów, niektóre z nich są następujące -
Błąd w kodzie lub w kodzie, który wywołujesz (na przykład w bibliotece współdzielonej),
Niedostępne zasoby systemu operacyjnego,
Nieoczekiwane warunki, które napotyka środowisko uruchomieniowe języka wspólnego (na przykład kod, którego nie można zweryfikować)
Składnia
Wyjątki mają możliwość przenoszenia przepływu programu z jednej części do drugiej. W środowisku .NET obsługa wyjątków obejmuje następujące cztery słowa kluczowe -
try - W tym bloku program identyfikuje pewien warunek, który wywołuje wyjątek.
catch- Słowo kluczowe catch wskazuje na przechwycenie wyjątku. ZAtry po bloku następuje jeden lub więcej catch bloków, aby przechwycić wyjątek z obsługą wyjątków w miejscu w programie, w którym chcesz obsłużyć problem.
finally- Ostatni blok jest używany do wykonania danego zestawu instrukcji, niezależnie od tego, czy wyjątek jest zgłoszony, czy nie. Na przykład, jeśli otworzysz plik, musi zostać zamknięty, niezależnie od tego, czy został zgłoszony wyjątek, czy nie.
throw- Program zgłasza wyjątek, gdy pojawia się problem. Odbywa się to za pomocą słowa kluczowego throw.
Składnia użycia tych czterech słów kluczowych wygląda następująco:
try {
///This will still trigger the exception
}
catch (ExceptionClassName e) {
// error handling code
}
catch (ExceptionClassName e) {
// error handling code
}
catch (ExceptionClassName e) {
// error handling code
}
finally {
// statements to be executed
}
Wiele instrukcji catch jest używanych w przypadkach, gdy blok try może zgłosić więcej niż jeden wyjątek w zależności od sytuacji w przepływie programu.
Hierarchia
Prawie wszystkie klasy wyjątków w środowisku .NET pochodzą bezpośrednio lub pośrednio z klasy Exception. Najważniejsze klasy wyjątków wywodzące się z klasy Exception to -
ApplicationException class- Obsługuje wyjątki, które są generowane przez programy. Gdy programista chce zdefiniować wyjątek, klasa powinna pochodzić z tej klasy.
SystemException class- Jest to klasa bazowa dla wszystkich predefiniowanych wyjątków systemu wykonawczego. Poniższa hierarchia przedstawia standardowe wyjątki udostępniane przez środowisko uruchomieniowe.
W poniższej tabeli wymieniono standardowe wyjątki zapewniane przez środowisko uruchomieniowe oraz warunki, w których należy utworzyć klasę pochodną.
Typ wyjątku | Typ podstawowy | Opis |
---|---|---|
Exception | Obiekt | Klasa podstawowa dla wszystkich wyjątków. |
SystemException | Wyjątek | Klasa podstawowa dla wszystkich błędów generowanych w czasie wykonywania. |
IndexOutOfRangeException | SystemException | Zgłaszane przez środowisko wykonawcze tylko wtedy, gdy tablica jest niepoprawnie indeksowana. |
NullReferenceException | SystemException | Zgłaszane przez środowisko wykonawcze tylko wtedy, gdy przywołuje się obiekt o wartości null. |
AccessViolationException | SystemException | Zgłaszane przez środowisko wykonawcze tylko w przypadku uzyskania dostępu do nieprawidłowej pamięci. |
InvalidOperationException | SystemException | Zgłaszane przez metody w nieprawidłowym stanie. |
ArgumentException | SystemException | Klasa bazowa dla wszystkich wyjątków argumentów. |
ArgumentNullException | ArgumentException | Zgłaszane przez metody, które nie pozwalają na zerową wartość argumentu. |
ArgumentOutOfRangeException | ArgumentException | Zgłaszane przez metody, które sprawdzają, czy argumenty znajdują się w podanym zakresie. |
ExternalException | SystemException | Klasa podstawowa dla wyjątków, które występują lub są przeznaczone dla środowisk poza środowiskiem wykonawczym. |
SEHException | Wyjątek zewnętrzny | Wyjątek hermetyzujący informacje dotyczące obsługi wyjątków strukturalnych Win32. |
Przykład
Weźmy prosty przykład, aby lepiej zrozumieć tę koncepcję. Zacznij od utworzenia nowego projektu WPF o nazwieWPFExceptionHandling.
Przeciągnij jedno pole tekstowe z przybornika do okna projektu. Poniższy kod XAML tworzy pole tekstowe i inicjuje je z niektórymi właściwościami.
<Window x:Class = "WPFExceptionHandling.MainWindow"
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:WPFExceptionHandling"
mc:Ignorable = "d"
Title = "MainWindow" Height = "350" Width = "604">
<Grid>
<TextBox x:Name = "textBox" HorizontalAlignment = "Left"
Height = "241" Margin = "70,39,0,0" TextWrapping = "Wrap"
VerticalAlignment = "Top" Width = "453"/>
</Grid>
</Window>
Oto odczyt pliku z obsługą wyjątków w C #.
using System;
using System.IO;
using System.Windows;
namespace WPFExceptionHandling {
public partial class MainWindow : Window {
public MainWindow() {
InitializeComponent();
ReadFile(0);
}
void ReadFile(int index) {
string path = @"D:\Test.txt";
StreamReader file = new StreamReader(path);
char[] buffer = new char[80];
try {
file.ReadBlock(buffer, index, buffer.Length);
string str = new string(buffer);
str.Trim();
textBox.Text = str;
}
catch (Exception e) {
MessageBox.Show("Error reading from "+ path + "\nMessage = "+ e.Message);
}
finally {
if (file != null) {
file.Close();
}
}
}
}
}
Kiedy kompilujesz i wykonujesz powyższy kod, utworzy on następujące okno, w którym tekst jest wyświetlany w polu tekstowym.
Gdy wystąpi wyjątek lub wyrzucisz go ręcznie (jak w poniższym kodzie), wyświetli się okno komunikatu z błędem.
using System;
using System.IO;
using System.Windows;
namespace WPFExceptionHandling {
public partial class MainWindow : Window {
public MainWindow() {
InitializeComponent();
ReadFile(0);
}
void ReadFile(int index) {
string path = @"D:\Test.txt";
StreamReader file = new StreamReader(path);
char[] buffer = new char[80];
try {
file.ReadBlock(buffer, index, buffer.Length);
string str = new string(buffer);
throw new Exception();
str.Trim();
textBox.Text = str;
}
catch (Exception e) {
MessageBox.Show("Error reading from "+ path + "\nMessage = "+ e.Message);
}
finally {
if (file != null) {
file.Close();
}
}
}
}
}
Gdy wyjątek zostanie zgłoszony podczas wykonywania powyższego kodu, wyświetli następujący komunikat.
Zalecamy wykonanie powyższego kodu i eksperymentowanie z jego funkcjami.
Lokalizacja to tłumaczenie zasobów aplikacji na zlokalizowane wersje dla określonych kultur obsługiwanych przez aplikację.
Gdy tworzysz swoją aplikację i jest ona dostępna tylko w jednym języku, ograniczasz liczbę klientów i wielkość swojej firmy. Jeśli chcesz zwiększyć bazę klientów, co również zwiększy Twój biznes, Twój produkt musi być dostępny i osiągalny dla globalnej publiczności. Ekonomicznelocalization Twojego produktu to jeden z najlepszych i najbardziej ekonomicznych sposobów dotarcia do większej liczby klientów.
W WPF lokalizowalne aplikacje są bardzo łatwe do tworzenia za pomocą resxplik, który jest najprostszym rozwiązaniem do lokalizacji. Weźmy prosty przykład, aby zrozumieć, jak to działa -
Utwórz nowy projekt WPF o nazwie WPFLocalization.
W eksploratorze rozwiązań zobaczysz plik Resources.resx w folderze Właściwości.
Zmień modyfikator dostępu z wewnętrznego na publiczny, aby był dostępny w pliku XAML.
Teraz dodaj nazwę i wartości następującego ciągu, których będziemy używać w naszej aplikacji.
Zrób dwie kopie pliku Resources.resx z nazwami Resources.en.resx i Resources.ru-RU.resx. Są to konwencje nazewnictwa specyficzne dla języka i nazwy kraju / regionu i można je znaleźć w dokumencie National Language Support (NLS) API Reference (https://msdn.microsoft.com/en-us/goglobal/bb896001.aspx ) strona.
Zmień wartości w Resources.ru-RU.resx na rosyjskie słowa, jak pokazano poniżej.
Przejdźmy do okna projektu i przeciągnijmy trzy pola tekstowe, trzy etykiety i trzy przyciski.
W pliku XAML najpierw dodaj deklarację przestrzeni nazw, aby użyć lokalizacji zasobów xmlns: p = "clr-namespace: WPFLocalization.Properties"
Ustaw właściwości wszystkich kontrolek, jak pokazano poniżej. W tym przykładzie nie będziemy używać zakodowanych na stałe ciągów dla zawartości etykiet, przycisków i tytułu okna w pliku XAML. Będziemy używać ciągów, które są zdefiniowane w plikach * .resx. Na przykład w przypadku tytułu okna używamy ciągu Title, który jest zdefiniowany w pliku * .resx, na przykład „Title =” {x: Static p: Resources.Title} „”
Oto plik XAML, w którym formanty są tworzone i inicjowane z różnymi właściwościami.
<Window x:Class = "WPFLocalization.MainWindow"
xmlns = "http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x = "http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local = "clr-namespace:WPFLocalization"
xmlns:p = "clr-namespace:WPFLocalization.Properties"
Title = "{x:Static p:Resources.Title}" Height = "350" Width = "604">
<Grid>
<TextBox x:Name = "textBox" HorizontalAlignment = "Left" Height = "23"
Margin = "128,45,0,0" TextWrapping = "Wrap" VerticalAlignment = "Top" Width = "304"/>
<Label x:Name = "label" Content = "{x:Static p:Resources.Name}"
HorizontalAlignment = "Left" Margin = "52,45,0,0" VerticalAlignment = "Top" Width = "86"/>
<TextBox x:Name = "textBox1" HorizontalAlignment = "Left" Height = "23"
Margin = "128,102,0,0" TextWrapping = "Wrap" VerticalAlignment = "Top" Width = "304"/>
<Label x:Name = "label1" Content = "{x:Static p:Resources.Address}"
HorizontalAlignment = "Left" Margin = "52,102,0,0" VerticalAlignment = "Top" Width = "86"/>
<TextBox x:Name = "textBox2" HorizontalAlignment = "Left" Height = "23"
Margin = "128,157,0,0" TextWrapping = "Wrap" VerticalAlignment = "Top" Width = "80"/>
<Label x:Name = "label2" Content = "{x:Static p:Resources.Age}"
HorizontalAlignment = "Left" Margin = "52,157,0,0" VerticalAlignment = "Top" Width = "86"/>
<Button x:Name = "button" Content = "{x:Static p:Resources.OK_Button}"
HorizontalAlignment = "Left" Margin = "163,241,0,0" VerticalAlignment = "Top" Width = "75"/>
<Button x:Name = "button1" Content = "{x:Static p:Resources.Cancel_Button}"
HorizontalAlignment = "Left" Margin = "282,241,0,0" VerticalAlignment = "Top" Width = "75"/>
<Button x:Name = "button2" Content = "{x:Static p:Resources.Help_Button}"
HorizontalAlignment = "Left" Margin = "392,241,0,0" VerticalAlignment = "Top" Width = "75"/>
</Grid>
</Window>
Kiedy powyższy kod zostanie skompilowany i wykonany, zobaczysz następujące okno zawierające różne kontrolki.
Domyślnie program używa domyślnego pliku Resources.resx. Jeśli chcesz wyświetlić tekst w języku rosyjskim, który jest zdefiniowany w pliku Resources.ru-RU.resx, musisz jawnie ustawić kulturę, gdy program uruchamia się w pliku App.xaml, jak pokazano poniżej.
using System.Windows;
namespace WPFLocalization {
/// <summary>
/// Interaction logic for App.xaml
/// </summary>
public partial class App : Application {
App() {
System.Threading.Thread.CurrentThread.CurrentUICulture = new System.Globalization.CultureInfo("ru-RU");
//System.Threading.Thread.CurrentThread.CurrentUICulture = new System.Globalization.CultureInfo("en");
}
}
}
Po uruchomieniu aplikacji zobaczysz cały tekst w języku rosyjskim.
Zalecamy wykonanie powyższego kodu i utworzenie plików resx również dla innych kultur.
W WPF interakcja pokazuje, jak widok współdziała z kontrolkami znajdującymi się w tym widoku. Najbardziej znane interakcje są dwojakiego rodzaju -
- Behaviors
- Przeciągnij i upuść
Zachowania
Zachowania zostały wprowadzone w Expression Blend 3, które mogą zawierać część funkcji w składniku wielokrotnego użytku. Aby dodać dodatkowe zachowania, możesz dołączyć te komponenty do kontrolek. Zachowania zapewniają większą elastyczność w łatwym projektowaniu złożonych interakcji użytkownika.
Rzućmy okiem na prosty przykład, w którym zachowanie ControlStoryBoardAction jest dołączone do kontrolek.
Utwórz nowy projekt WPF o nazwie WPFBehavior.
Poniższy kod XAML tworzy elipsę i dwa przyciski do sterowania ruchem elipsy.
<Window
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:WPFBehaviors"
xmlns:i = "http://schemas.microsoft.com/expression/2010/interactivity"
xmlns:ei = "http://schemas.microsoft.com/expression/2010/interactions"
x:Class = "WPFBehaviors.MainWindow"
mc:Ignorable = "d" Title = "MainWindow" Height = "350" Width = "604">
<Window.Resources>
<Storyboard x:Key = "Storyboard1" RepeatBehavior = "Forever" AutoReverse = "True">
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty =
"(UIElement.RenderTransform).(TransformGroup.Children )[3].(TranslateTransform.X)"
Storyboard.TargetName = "ellipse">
<EasingDoubleKeyFrame KeyTime = "0:0:1" Value = "301.524"/>
<EasingDoubleKeyFrame KeyTime = "0:0:2" Value = "2.909"/>
</DoubleAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty =
"(UIElement.RenderTransform).(TransformGroup.Children )[3].(TranslateTransform.Y)"
Storyboard.TargetName = "ellipse">
<EasingDoubleKeyFrame KeyTime = "0:0:1" Value = "-0.485"/>
<EasingDoubleKeyFrame KeyTime = "0:0:2" Value = "0"/>
</DoubleAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty = "(ContentControl.Content)"
Storyboard.TargetName = "button">
<DiscreteObjectKeyFrame KeyTime = "0" Value = "Play"/>
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty = "(ContentControl.Content)"
Storyboard.TargetName = "button1">
<DiscreteObjectKeyFrame KeyTime = "0" Value = "Stop"/>
<DiscreteObjectKeyFrame KeyTime = "0:0:2" Value = "Stop"/>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</Window.Resources>
<Window.Triggers>
<EventTrigger RoutedEvent = "FrameworkElement.Loaded">
<BeginStoryboard Storyboard = "{StaticResource Storyboard1}"/>
</EventTrigger>
</Window.Triggers>
<Grid>
<Ellipse x:Name = "ellipse" Fill = "#FFAAAAC5" HorizontalAlignment = "Left"
Height = "50.901" Margin = "49.324,70.922,0,0" Stroke = "Black"
VerticalAlignment = "Top" Width = "73.684" RenderTransformOrigin = "0.5,0.5">
<Ellipse.RenderTransform>
<TransformGroup>
<ScaleTransform/>
<SkewTransform/>
<RotateTransform/>
<TranslateTransform/>
</TransformGroup>
</Ellipse.RenderTransform>
</Ellipse>
<Button x:Name = "button" Content = "Play" HorizontalAlignment = "Left" Height = "24.238"
Margin = "63.867,0,0,92.953" VerticalAlignment = "Bottom" Width = "74.654">
<i:Interaction.Triggers>
<i:EventTrigger EventName = "Click">
<ei:ControlStoryboardAction Storyboard = "{StaticResource Storyboard1}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</Button>
<Button x:Name = "button1" Content = "Stop" HorizontalAlignment = "Left" Height = "24.239"
Margin = "160.82,0,0,93.922" VerticalAlignment = "Bottom" Width = "75.138">
<i:Interaction.Triggers>
<i:EventTrigger EventName = "Click">
<ei:ControlStoryboardAction ControlStoryboardOption = "Stop"
Storyboard = "{StaticResource Storyboard1}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</Button>
</Grid>
</Window>
Kiedy kompilujesz i wykonujesz powyższy kod, utworzy on następujące okno, które zawiera elipsę i dwa przyciski.
Po naciśnięciu przycisku odtwarzania zacznie się on przesuwać od lewej do prawej, a następnie powróci do swojej pierwotnej pozycji. Przycisk stop zatrzyma ruch elipsy.
Przeciągnij i upuść
Przeciągnij i upuść na interfejsie użytkownika może znacznie zwiększyć wydajność i produktywność aplikacji. Istnieje bardzo niewiele aplikacji, w których używane są funkcje przeciągania i upuszczania, ponieważ ludzie uważają, że jest to trudne do wdrożenia. Do pewnego stopnia trudno jest obsługiwać funkcję przeciągnij i upuść, ale w WPF możesz sobie z tym dość łatwo poradzić.
Weźmy prosty przykład, aby zrozumieć, jak to działa. Stworzymy aplikację, w której możesz przeciągać i upuszczać kolory z jednego prostokąta do drugiego.
Utwórz nowy projekt WPF o nazwie WPFDragAndDrop.
Przeciągnij pięć prostokątów do okna projektu i ustaw właściwości, jak pokazano w poniższym pliku XAML.
<Window x:Class = "WPFDragAndDrop.MainWindow"
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:WPFDragAndDrop"
mc:Ignorable = "d" Title = "MainWindow" Height = "402.551" Width = "604">
<Grid>
<Rectangle Name = "Target" Fill = "AliceBlue" HorizontalAlignment = "Left"
Height = "345" Margin = "10,10,0,0" Stroke = "Black"
VerticalAlignment = "Top" Width = "387" AllowDrop = "True" Drop = "Target_Drop"/>
<Rectangle Fill = "Beige" HorizontalAlignment = "Left" Height = "65"
Margin = "402,10,0,0" Stroke = "Black" VerticalAlignment = "Top"
Width = "184" MouseLeftButtonDown = "Rect_MLButtonDown"/>
<Rectangle Fill = "LightBlue" HorizontalAlignment = "Left" Height = "65"
Margin = "402,80,0,0" Stroke = "Black" VerticalAlignment = "Top"
Width = "184" MouseLeftButtonDown = "Rect_MLButtonDown"/>
<Rectangle Fill = "LightCoral" HorizontalAlignment = "Left" Height = "65"
Margin = "402,150,0,0" Stroke = "Black" VerticalAlignment = "Top"
Width = "184" MouseLeftButtonDown = "Rect_MLButtonDown"/>
<Rectangle Fill = "LightGray" HorizontalAlignment = "Left" Height = "65"
Margin = "402,220,0,0" Stroke = "Black" VerticalAlignment = "Top"
Width = "184" MouseLeftButtonDown = "Rect_MLButtonDown"/>
<Rectangle Fill = "OliveDrab" HorizontalAlignment = "Left" Height = "65"
Margin = "402,290,0,-7" Stroke = "Black" VerticalAlignment = "Top"
Width = "184" MouseLeftButtonDown = "Rect_MLButtonDown"/>
</Grid>
</Window>
Pierwszy prostokąt jest prostokątem docelowym, więc użytkownik może przeciągnąć kolor z drugiego prostokąta do prostokąta docelowego.
Poniżej podano implementację zdarzeń w C # do przeciągania i upuszczania.
using System.Windows;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Shapes;
namespace WPFDragAndDrop {
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window {
public MainWindow() {
InitializeComponent();
}
private void Rect_MLButtonDown(object sender, MouseButtonEventArgs e) {
Rectangle rc = sender as Rectangle;
DataObject data = new DataObject(rc.Fill);
DragDrop.DoDragDrop(rc, data,DragDropEffects.Move);
}
private void Target_Drop(object sender, DragEventArgs e) {
SolidColorBrush scb = (SolidColorBrush)e.Data.GetData(typeof(SolidColorBrush));
Target.Fill = scb;
}
}
}
Po uruchomieniu aplikacji zostanie wyświetlone następujące okno.
Jeśli przeciągniesz kolor z prostokąta po prawej stronie i upuścisz go na duży prostokąt po lewej stronie, natychmiast zobaczysz efekt.
Chodźmy przeciągnij 4 th jeden z prawej strony.
Widać, że zmienił się kolor docelowego prostokąta. Zalecamy wykonanie powyższego kodu i eksperymentowanie z jego funkcjami.
WPF zapewnia szeroką gamę grafiki 2D, które można ulepszyć zgodnie z wymaganiami aplikacji. WPF obsługuje zarówno obiekty Drawing, jak i Shape, które są używane do rysowania zawartości graficznej.
Kształty i rysunek
Klasa Shape pochodzi z klasy FrameworkElement, obiekty Shape mogą być używane wewnątrz paneli i większości kontrolek.
WPF udostępnia kilka podstawowych obiektów kształtów, które pochodzą z klasy Shape, takich jak Elipsa, Linia, Ścieżka, Wielokąt, Polilinia i Prostokąt.
Z drugiej strony obiekty rysunkowe nie pochodzą z klasy FrameworkElement i zapewniają lżejszą implementację.
Obiekty rysunkowe są prostsze w porównaniu z obiektami Shape. Mają również lepsze właściwości użytkowe.
Przykład
Weźmy prosty przykład, aby zrozumieć, jak używać obiektów o różnych kształtach.
Utwórz nowy projekt WPF o nazwie WPF2DGraphics.
Poniższy kod tworzy różne typy kształtów.
<Window x:Class = "WPF2DGraphics.MainWindow"
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:WPF2DGraphics"
xmlns:PresentationOptions = "http://schemas.microsoft.com/winfx/2006/xaml/present ation/options"
mc:Ignorable = "PresentationOptions" Title = "MainWindow" Height = "400" Width = "604">
<StackPanel>
<Ellipse Width = "100" Height = "60" Name = "sample" Margin = "10">
<Ellipse.Fill>
<RadialGradientBrush>
<GradientStop Offset = "0" Color = "AliceBlue"/>
<GradientStop Offset = "1" Color = "Gray"/>
<GradientStop Offset = "2" Color = "Red"/>
</RadialGradientBrush>
</Ellipse.Fill>
</Ellipse>
<Path Stroke = "Red" StrokeThickness = "5" Data = "M 10,70 L 200,70"
Height = "42.085" Stretch = "Fill" Margin = "140.598,0,146.581,0" />
<Path Stroke = "BlueViolet" StrokeThickness = "5" Data = "M 20,100 A 100,56 42 1 0 200,10"
Height = "81.316" Stretch = "Fill" Margin = "236.325,0,211.396,0" />
<Path Fill = "LightCoral" Margin = "201.424,0,236.325,0"
Stretch = "Fill" Height = "124.929">
<Path.Data>
<PathGeometry>
<PathFigure StartPoint = "50,0" IsClosed = "True">
<LineSegment Point = "100,50"/>
<LineSegment Point = "50,100"/>
<LineSegment Point = "0,50"/>
</PathFigure>
</PathGeometry>
</Path.Data>
</Path>
</StackPanel>
</Window>
Kiedy kompilujesz i wykonujesz powyższy kod, utworzy on elipsę, linię prostą, łuk i wielokąt.
Przykład
Spójrzmy na inny przykład, który pokazuje, jak pomalować obszar za pomocą rysunku.
Utwórz nowy projekt WPF o nazwie WPF2DGraphics1.
Poniższy kod XAML pokazuje, jak malować inaczej za pomocą rysowania obrazu.
<Window x:Class = "WPF2DGraphics1.MainWindow"
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:PresentationOptions = "http://schemas.microsoft.com/winfx/2006/xaml/present ation/options"
xmlns:mc = "http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable = "PresentationOptions"
xmlns:local = "clr-namespace:WPF2DGraphics1" Title = "MainWindow" Height = "350" Width = "604">
<Grid>
<Border BorderBrush = "Gray" BorderThickness = "1"
HorizontalAlignment = "Left" VerticalAlignment = "Top"
Margin = "20">
<Image Stretch = "None">
<Image.Source>
<DrawingImage PresentationOptions:Freeze = "True">
<DrawingImage.Drawing>
<DrawingGroup>
<ImageDrawing Rect = "300,100,300,180" ImageSource = "Images\DSC_0104.JPG"/>
<ImageDrawing Rect = "0,100,250,100" ImageSource = "Images\DSC_0104.JPG"/>
<ImageDrawing Rect = "150,0,25,25" ImageSource = "Images\DSC_0104.JPG"/>
<ImageDrawing Rect = "0,0,75,75" ImageSource = "Images\DSC_0104.JPG"/>
</DrawingGroup>
</DrawingImage.Drawing>
</DrawingImage>
</Image.Source>
</Image>
</Border>
</Grid>
</Window>
Po uruchomieniu aplikacji wygeneruje ona następujące dane wyjściowe -
Zalecamy wykonanie powyższego kodu i wypróbowanie większej liczby kształtów i rysunków 2D.
Windows Presentation Foundation (WPF) zapewnia funkcję rysowania, przekształcania i animowania grafiki 3D zgodnie z wymaganiami aplikacji. Nie obsługuje pełnoprawnych gier 3D, ale do pewnego poziomu możesz tworzyć grafikę 3D.
Łącząc grafikę 2D i 3D, możesz także tworzyć bogate elementy sterujące, dostarczać złożone ilustracje danych lub poprawiać wrażenia użytkownika z interfejsu aplikacji. Element Viewport3D obsługuje model 3D w naszej aplikacji WPF.
Przykład
Weźmy prosty przykład, aby zrozumieć, jak używać grafiki 3D.
Utwórz nowy projekt WPF o nazwie WPF3DGraphics.
Poniższy kod XAML pokazuje, jak utworzyć obiekt 2D przy użyciu geometrii 3D.
<Window x:Class = "WPF3DGraphics.MainWindow"
xmlns = "http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x = "http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc = "http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local = "clr-namespace:WPF3DGraphics"
mc:Ignorable = "d" Title = "MainWindow" Height = "500" Width = "604">
<Grid>
<Viewport3D>
<Viewport3D.Camera>
<PerspectiveCamera Position = "2,0,10" LookDirection = "0.2,0.4,-1"
FieldOfView = "65" UpDirection = "0,1,0" />
</Viewport3D.Camera>
<ModelVisual3D>
<ModelVisual3D.Content>
<Model3DGroup>
<AmbientLight Color = "Bisque" />
<GeometryModel3D>
<GeometryModel3D.Geometry>
<MeshGeometry3D Positions = "0,0,0 0,8,0 10,0,0 8,8,0"
Normals = "0,0,1 0,0,1 0,0,1 0,0,1" TriangleIndices = "0,2,1 1,2,3"/>
</GeometryModel3D.Geometry>
<GeometryModel3D.Material>
<DiffuseMaterial Brush = "Bisque" />
</GeometryModel3D.Material>
</GeometryModel3D>
</Model3DGroup>
</ModelVisual3D.Content>
</ModelVisual3D>
</Viewport3D>
</Grid>
</Window>
Kiedy kompilujesz i wykonujesz powyższy kod, utworzy on obiekt 2D w 3D.
Przykład
Spójrzmy na inny przykład, który przedstawia obiekt 3D.
Utwórz nowy projekt WPF o nazwie WPF3DGraphics1
Poniższy kod XAML tworzy obiekt 3D i suwak. Za pomocą suwaka możesz obracać ten obiekt 3D.
<Window x:Class = "WPF3DGraphics1.MainWindow"
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:WPF3DGraphics1"
mc:Ignorable = "d" Title = "MainWindow" Height = "350" Width = "525">
<Grid>
<Viewport3D Name="viewport3D1">
<Viewport3D.Camera>
<PerspectiveCamera x:Name = "camMain" Position = "6 5 4" LookDirection = "-6 -5 -4">
</PerspectiveCamera>
</Viewport3D.Camera>
<ModelVisual3D>
<ModelVisual3D.Content>
<DirectionalLight x:Name = "dirLightMain" Direction = "-1,-1,-1">
</DirectionalLight>
</ModelVisual3D.Content>
</ModelVisual3D>
<ModelVisual3D x:Name = "MyModel">
<ModelVisual3D.Content>
<GeometryModel3D>
<GeometryModel3D.Geometry>
<MeshGeometry3D x:Name = "meshMain"
Positions = "0 0 0 1 0 0 0 1 0 1 1 0 0 0 1 1 0 1 0 1 1 0 1 1"
TriangleIndices = "2 3 1 3 1 0 7 1 3 7 5 1 6 5 7 6 4 5 6 2 0
2 0 4 2 7 3 2 6 7 0 1 5 0 5 4">
</MeshGeometry3D>
</GeometryModel3D.Geometry>
<GeometryModel3D.Material>
<DiffuseMaterial x:Name = "matDiffuseMain">
<DiffuseMaterial.Brush>
<SolidColorBrush Color = "Bisque"/>
</DiffuseMaterial.Brush>
</DiffuseMaterial>
</GeometryModel3D.Material>
</GeometryModel3D>
</ModelVisual3D.Content>
<ModelVisual3D.Transform>
<RotateTransform3D>
<RotateTransform3D.Rotation>
<AxisAngleRotation3D x:Name = "rotate" Axis = "1 2 1"/>
</RotateTransform3D.Rotation>
</RotateTransform3D>
</ModelVisual3D.Transform>
</ModelVisual3D>
</Viewport3D>
<Slider Height = "23" HorizontalAlignment = "Left"
Margin = "145,271,0,0" Name = "slider1"
VerticalAlignment = "Top" Width = "269"
Maximum = "360"
Value = "{Binding ElementName = rotate, Path=Angle}" />
</Grid>
</Window>
Po uruchomieniu aplikacji utworzy ona obiekt 3D i suwak w oknie.
Gdy przesuniesz suwak, obiekt w oknie również się obróci.
Zalecamy wykonanie powyższego kodu i wypróbowanie większej geometrii 3D.
Aplikacje WPF obsługują wideo i audio przy użyciu MediaElement. Umożliwia integrację audio i wideo z aplikacją. Klasa MediaElement działa podobnie jak klasa Image. Po prostu wskazujesz go na media, a on to renderuje. Główną różnicą jest to, że będzie to ruchomy obraz, ale jeśli wskażesz plik, który zawiera tylko dźwięk, a nie wideo, taki jak MP3, odtworzy go bez wyświetlania niczego na ekranie.
WPF obsługuje wszystkie typy formatów wideo / audio w zależności od konfiguracji maszyny. Jeśli plik multimedialny odtwarza odtwarzacz multimedialny, będzie również działał w WPF na tym samym komputerze.
Przykład
Weźmy przykład, aby zrozumieć, jak zintegrować multimedia w swojej aplikacji.
Utwórz nowy projekt WPF o nazwie WPFMultimedia.
Poniższy kod XAML tworzy element multimedialny i trzy przyciski oraz inicjuje je z niektórymi właściwościami.
<Window x:Class = "WPFMultimedia.MainWindow"
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:WPFMultimedia"
mc:Ignorable = "d" Title = "MainWindow" Height = "350" Width = "604">
<Grid>
<StackPanel HorizontalAlignment = "Center" VerticalAlignment = "Center">
<MediaElement Name = "myMedia" Source = "D:\MicrosoftMVA.mp4"
LoadedBehavior = "Manual" Width = "591" Height = "274" />
<StackPanel Orientation = "Horizontal" Margin = "0,10,0,0">
<Button Content = "Play" Margin = "0,0,10,0" Padding = "5" Click = "mediaPlay" />
<Button Content = "Pause" Margin = "0,0,10,0" Padding = "5" Click = "mediaPause" />
<Button x:Name = "muteButt" Content = "Mute" Padding = "5" Click = "mediaMute" />
</StackPanel>
</StackPanel>
</Grid>
</Window>
Oto implementacja zdarzeń Click w C # dla różnych przycisków.
using System;
using System.Windows;
namespace WPFMultimedia {
public partial class MainWindow : Window {
public MainWindow() {
InitializeComponent();
myMedia.Volume = 100;
myMedia.Play();
}
void mediaPlay(Object sender, EventArgs e) {
myMedia.Play();
}
void mediaPause(Object sender, EventArgs e) {
myMedia.Pause();
}
void mediaMute(Object sender, EventArgs e) {
if (myMedia.Volume == 100) {
myMedia.Volume = 0;
muteButt.Content = "Listen";
}
else {
myMedia.Volume = 100;
muteButt.Content = "Mute";
}
}
}
}
Kiedy kompilujesz i wykonujesz powyższy kod, wyświetli się następujące okno. Możesz odtwarzać wideo i sterować jego odtwarzaniem za pomocą trzech przycisków.
Za pomocą przycisków możesz wstrzymywać, wyciszać i odtwarzać wideo.
Syntezator mowy
WPF ma funkcje do konwersji tekstu na mowę. Ten interfejs API jest zawarty w przestrzeni nazw System.Speech.SpeechSynthesizer class przekształca tekst w wypowiedziane słowa.
Przykład
Spójrzmy na prosty przykład.
Utwórz nowy projekt WPF o nazwie WPFTextToSpeech.
Będziemy potrzebować zestawu System.Speech do dodania jako odniesienia dla SpeechSynthesizer klasa do pracy.
Kliknij prawym przyciskiem myszy References i wybierz Add Reference.
Otworzy się okno dialogowe Menedżera odniesień. Teraz zaznacz pole wyboru System.Speech
Kliknij przycisk OK. Możesz zobaczyć zestaw System.Speech w Twoich odwołaniach.
Teraz przeciągnij przycisk i pole tekstowe do okna projektu z przybornika.
Poniższy kod XAML tworzy przycisk i pole tekstowe oraz inicjuje je z niektórymi właściwościami.
<Window x:Class = "WPFTextToSpeech.MainWindow"
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:WPFTextToSpeech"
mc:Ignorable = "d" Title = "MainWindow" Height = "350" Width = "604">
<Grid>
<Button x:Name = "button" Content = "Speak"
HorizontalAlignment = "Left" Margin = "218,176,0,0"
VerticalAlignment = "Top" Width = "75"/>
<TextBox x:Name = "textBox" HorizontalAlignment = "Left"
Height = "23" Margin = "60,104,0,0" TextWrapping = "Wrap"
VerticalAlignment = "Top" Width = "418"/>
</Grid>
</Window>
Oto prosta implementacja w C #, która konwertuje tekst wewnątrz pola tekstowego na wypowiadane słowa.
using System.Speech.Synthesis;
using System.Windows;
namespace WPFTextToSpeech {
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window {
public MainWindow() {
InitializeComponent();
}
private void button_Click(object sender, RoutedEventArgs e) {
if (textBox.Text != "") {
SpeechSynthesizer speechSynthesizer = new SpeechSynthesizer();
speechSynthesizer.Speak(textBox.Text);
}
else {
MessageBox.Show("Write some thing in the textbox!");
}
}
}
}
Kiedy kompilujesz i wykonujesz powyższy kod, wyświetli się następujące okno. Teraz wpisz Hello World w polu tekstowym i kliknij przycisk Mów.
Wygeneruje dźwięk „Hello World”. Jeśli nic nie wpiszesz w pole tekstowe, wyświetli się następująca wiadomość.
Zalecamy wykonanie powyższych przykładów.