• Nie Znaleziono Wyników

Programowanie w technologii .NET wykład 4 – Aplikacja i okna

N/A
N/A
Protected

Academic year: 2021

Share "Programowanie w technologii .NET wykład 4 – Aplikacja i okna"

Copied!
30
0
0

Pełen tekst

(1)

Programowanie w technologii .NET

wykład 4 – Aplikacja i okna

Aplikacja

Aplikacja WPF jest reprezentowana przez instancję klasy System.Windows.Application.

• pilnuje ona kiedy program się uruchamia i kończy

• zarządza otwartymi oknami aplikacji

• odpala zdarzenia aplikacji (do inicjalizacji i sprzątania) Cykl życia aplikacji:

• uruchomienie programu

• stworzenie obiektu klasy System.Windows.Application

wywołana zostaje metoda Application.Run()

zgłaszane jest zdarzenie Application.Startup

• tworzone są okna, uruchamiane i obsługiwane różne zdarzenia

wywołana zostaje metoda Application.Shutdown()

zgłaszane jest zdarzenie Application.Exit

• metoda Run kończy działanie

(2)

Ręczne tworzenie aplikacji (np. w projekcie konsolowym):

using System;

using System.Windows;

public class MyApp {

[STAThread()]

static void Main() {

// tworzenie obiektu aplikacji.

Application app = new Application();

// tworzenie głównego okna Window1 win = new Window1();

// uruchomienie aplikacji (zarazem otwarcie okienka) app.Run(win);

} }

po zamknięciu okien aplikacji i opuszczeniu metody Run kontynuowany jest kod Maina 2/30 // inaczej:

app.MainWindow = win;

win.Show();

// utrzymuje aplikację przy życiu app.Run();

(3)

Przeważnie dziedziczymy z klasy Application, np. aby obsługiwać zdarzenia aplikacji.

XAML:

<Application x:Class="TestApplication.App" ...

StartupUri="Window1.xaml">

</Application>

C#:

public partial class App : Application {

}

StartupUri – po to, aby XAML od razu otworzył też główne okno

(4)

Standardowo klasa Application trzyma aplikację przy życiu do momentu, aż ostatnie okno aplikacji zostanie zamknięte. Inne metody zamknięcia aplikacji można określić we

własności ShutdownMode:

OnLastWindowClose (domyślne) – gdy wszystkie okna zostaną zamknięte

OnMainWindowClose – gdy główne okno aplikacji zostanie zamknięte (pozostałe zamkną się same)

OnExplicitShutdown – aplikacja nigdy się nie kończy (musimy zatrzymać ją ręcznie – wywołując metodę Application.Shutdown())

<Application x:Class="TestApplication.App" ...

StartupUri="Window1.xaml"

ShutdownMode="OnMainWindowClose">

</Application>

4/30

(5)

zdarzenia aplikacji:

Startup – gdy wywołano Run, ale zanim pokaże się okno; używane przeważnie do sprawdzania argumentów wiersza poleceń i inicjalizacji aplikacji

Exit – gdy aplikacja się kończy, tuż przed wyjście z Run; jest za późno by to anulować; używane by przekazać kod wyjścia

SessionEnding – kończy się sesja użytkownika (wylogowuje się lub wyłącza komputer); możemy to jeszcze anulować

Activated – gdy jedno z okien aplikacji zostanie aktywowane – po raz pierwszy gdy pojawia się nasze okno, potem gdy użytkownik przełącza się z innej aplikacji na naszą

Deactivated – na odwrót – gdy przełącza się na inną aplikację

DispatcherUnhandledException – gdy w aplikacji (głównym wątku!) wystąpił nieobsłużony wyjątek; możemy go tu obsłużyć i kontynuować działanie programu obsługiwanie zdarzeń – na dwa sposoby:

• podłączenie handlera obsługującego zdarzenie

• przeciążenie odpowiedniej metody

(6)

sposób pierwszy:

<Application x:Class="MyApplication.App" ...

StartupUri="Window1.xaml"

DispatcherUnhandledException="wyjatek">

</Application>

zaś w klasie dodajemy metodę:

public partial class App : Application {

private void wyjatek(object sender,

System.Windows.Threading.DispatcherUnhandledExceptionEventArgs e) {

MessageBox.Show("Nieobsłużony wyjątek " +

e.Exception.GetType().ToString());

using (StreamWriter errorLog =

new StreamWriter("c:\\error.log", true)) {

errorLog.WriteLine("Error @ " + DateTime.Now.ToString());

errorLog.WriteLine(e.Exception.ToString());

}

e.Handled = true;

} }

6/30

(7)

sposób drugi:

public partial class App : Application {

public bool UnsavedData { get; set; }

protected override void OnStartup(StartupEventArgs e) {

base.OnStartup(e);

UnsavedData = true;

}

protected override void OnSessionEnding(

SessionEndingCancelEventArgs e) {

// dobrą praktyką jest wywołać metodę z klasy bazowej base.OnSessionEnding(e);

if (UnsavedData) {

e.Cancel = true;

MessageBox.Show("Dane nie zostały zapisane." + "Aplikacja nie może się zakończyć.");

} } }

(8)

Zadania aplikacji

• obsługa argumentów wiersza poleceń

• dostęp do bieżącej aplikacji

• interakcja pomiędzy oknami

• aplikacje posiadające tylko jedną instancję

◦ w WPF można uruchomić dowolną liczbę instancji aplikacji

◦ nie sprawdza się to w aplikacjach opartych na dokumentach (np. MS Word)

◦ brak wsparcia dla pojedynczej instancji aplikacji (konieczność własnego implementowania rozwiązania)

8/30

(9)

Argumenty wiersza poleceń – dostępne jako tablica napisów poprzez własność StartupEventArgs.Args w obsłudze zdarzenia Startup:

private static void App_Startup(object sender,

StartupEventArgs e) {

MyWindow win = new MyWindow();

if (e.Args.Length > 0) {

string file = e.Args[0];

if (System.IO.File.Exists(file)) {

// załadowanie pliku do okienka dokumentu win.LoadFile(file);

} } else {

// alternatywna ścieżka – pusty dokument }

win.Show();

}

(10)

Dostęp do bieżącej aplikacji

• możliwy z dowolnego miejsca aplikacji poprzez statyczną własność Application.Current

• daje dostęp do głównego okna aplikacji poprzez własność Application.Current.MainWindow:

Window1 main = (Window1)Application.Current.MainWindow;

main.DoSomething();

• daje dostęp do kolekcji wszystkich otwartych okien aplikacji poprzez własność Application.Current.Windows

10/30

(11)

Interakcja pomiędzy oknami

• W głównej klasie aplikacji możemy przechowywać referencje do ważnych okien aplikacji, dzięki czemu jedno okno będzie miało dostęp do innego. Sprawdza się to tylko w przypadku okien, których czas życia jest długi (okien niemodalnych).

Np. dostęp do okien dokumentów:

public partial class App : Application {

private List<Document> documents = new List<Document>();

public List<Document> Documents { get { return documents; } set { documents = value; } }

}

tworzenie nowego okna dokumentu:

private void newDoc_Click(object sender, RoutedEventArgs e) {

Document doc = new Document();

doc.Owner = this;

doc.Show();

((App)Application.Current).Documents.Add(doc);

}

(12)

Window

Okna

• Podstawowy składnik każdej aplikacji okienkowej.

Dziedziczą po klasie ContentControl, co znaczy, że mogą przechowywać tylko jeden element.

• Najczęściej przechowują kontener (domyślnie Grid), w którym są umieszczane inne kontrolki.

• Obszarem klienta nazywana jest zawartość okna – wewnętrzna jego część, pomijając ramkę i pasek tytułowy.

12/30

(13)

własności okien:

AllowsTransparency – Pozwala na przezroczystość okna, używane do okien o niestandardowym kształcie (wraz z WindowStyle na None).

Icon – Ustawia ikonę dla okna, widoczną na pasku tytułu i na pasku zadań. Gdy null – używa ikony aplikacji (lub standardowej, jeśli ta jest niedostępna).

Top i Left – Określają położenie na ekranie. Zmiana odpala LocationChanged.

ResizeMode Określa możliwości zmiany rozmiaru okna (NoResize blokuje zmianę rozmiaru, CanMinimize pozwala tylko minimalizować, CanResize – na wszystko).

RestoreBounds – Określa granice okna (dostępne również po zminimalizowaniu).

ShowInTaskbar – Wskazuje czy okno ma być widoczne na pasku zadań, zazwyczaj true tylko dla głównego okna aplikacji.

SizeToContent – Umożliwia automatyczne dostosowanie wielkości okna do zawartości (również powyżej rozmiaru ekranu).

Title – Nazwa, która pojawi się w pasku tytułu.

Topmost – Okno ma być zawsze na wierzchu: umieszczane nad wszystkimi innymi oknami.

WindowStartupLocation – Określa startową pozycję okna: Manual (używa wartości Top i Left), CenterScreen, CenterOwner (środek okna ojca).

WindowState – określa stan okna: Maximized, Minimized, Normal. Zmiana odpala StateChanged.

WindowStyle – styl okna: wygląd krawędzi okna

(14)

Wyświetlanie okna

• Należy stworzyć instancję odpowiedniego okna.

• Okno wyświetlamy przy pomocy metod:

Show() – okno niemodalne

ShowDialog() – okno modalne // okno niemodalne

MyToolBoxWindow wnd = new MyToolBoxWindow();

wnd.Show();

// dalszy kod zostanie wykonany od razu po wyświetleniu okna wnd // okno modalne

MyQuestionWindow dlg = new MyQuestionWindow();

dlg.ShowDialog();

// dalszy kod zostaje wykonany dopiero po zamknięciu okna dlg Okno modalne blokuje dostęp do okna rodzica. Typowe zastosowanie to pytanie o wybór użytkownika lub pobieranie od niego danych niezbędnych do kontynuowania akcji.

zamykanie okna:

metoda Close()

14/30

(15)

Interakcja między oknami:

1-do-1

(16)

public partial class Window1 : Window {

...

DlgWindow dlg;

private void ClickUpdate(...) {

dlg.DoUpdate(/* some data */);

} }

public partial class DlgWindow : Window {

...

public void DoUpdate(/* some data */) {

// process data }

}

16/30

(17)

1-do-wielu

(18)

public partial class Window1 : Window {

...

private void ClickUpdate(...) {

((App)Application.Current).UpdateAll(/* some data */);

} }

public partial class App : Application {

public void UpdateAll(/* some data */) {

foreach (Window wnd in Windows) if (wnd is DlgWindow)

((DlgWindow)wnd).DoUpdate(/* some data */);

} }

(wywołania metod DoUpdate można zastąpić własnymi zdarzeniami)

18/30

(19)

Właściciel okna

Każde okno może mieć ustawionego właściciela przy wykorzystaniu własności Owner:

ToolBox tools = new ToolBox();

tools.Owner = this;

tools.Show();

Okno z Ownerem zawsze jest niemodalne. W przypadku zminimalizowania okna, minimalizowane są również wszystkie okna będące w jego posiadaniu. Podobnie jest z zamykaniem.

Właściwość OwnedWindows udostępnia kolekcję okien, które są w posiadaniu danego okna.

(20)

Okna dialogowe – typowy scenariusz:

• modalne okno dialogowe jest przeważnie pewnym wyborem

• wyświetlamy okno użytkownikowi i oczekujemy na wynik wyboru (lub wprowadzone dane)

• użytkownik dokonuje wyboru w oknie, wówczas:

◦ ustawiamy jakąś publiczną własność na rezultat wyboru

◦ zamykamy okno

• funkcja oczekująca na wybór wznawia działanie i:

◦ odczytuje ustawioną wartość

◦ stosownie do tego podejmuje dalsze akcje

MyDialogWindow dialog = new MyDialogWindow();

dialog.MyData = "default value";

if (dialog.ShowDialog() == true) {

// wybrano OK

login = dialog.MyData;

} else {

// wybrano Anuluj }

20/30

(21)

ShowDialog zwraca wartość ustawioną jako DialogResult

public partial class MyDialogWindow : Window {

public string MyData { get; set; }

private void Dlg_Loaded(object sender, RoutedEventArgs e) {

// wpisanie wartości początkowej txtBox.Text = MyData;

}

private void OK_Click(object sender, RoutedEventArgs e) {

// odczytanie wartości użytkownika MyData = txtBox.Text;

DialogResult = true;

Close();

} }

(22)

W wypadku okna niemodalnego podobne zadanie realizowane jest inaczej:

DlgWindow2 dialog = new DlgWindow2();

dialog.MyData = "default value";

dialog.Show();

// nie czekamy na zamknięcie

public partial class DlgWindow2 : Window {

public string MyData { get; set; }

private void Dlg_Loaded(...) { dane.Text = MyData; } private void Close_Click(...) { Close(); }

private void dane_TextChanged(...) {

Application.Current.MainWindow.Process(txtBox.Text);

} }

22/30

(23)

Common Dialog Boxes MessageBox

MessageBox.Show("Podano nieprawidłowe hasło.", "Błędne hasło",

MessageBoxButton.OK, MessageBoxImage.Error);

MessageBoxButton.OK

MessageBoxButton.OKCancel MessageBoxButton.YesNo

MessageBoxButton.YesNoCancel MessageBoxImage.Error

MessageBoxImage.Warning MessageBoxImage.Information MessageBoxImage.Question

(24)

Microsoft.Win32.OpenFileDialog i SaveFileDialog

OpenFileDialog myDialog = new OpenFileDialog();

myDialog.Filter =

"Image Files(*.BMP;*.JPG;*.GIF)|*.BMP;*.JPG;*.GIF" + "|All files (*.*)|*.*";

myDialog.CheckFileExists = true;

myDialog.Multiselect = true;

if (myDialog.ShowDialog() == true) {

//...

foreach (string file in myDialog.FileNames) {

//...

} }

24/30

(25)

Okna o niestandardowym kształcie

Aby utworzyć okno o niestandardowym kształcie, należy:

Ustawić Window.AllowsTransparency na true

Ustawić Window.WindowStyle na None (ukrywa pasek tytułowy i ramkę)

• Ustawić tło na przezroczyste (używając przezroczystego koloru) lub na obrazek, który zawiera przezroczyste obszary

• Niestandardowy kształt możemy zdefiniować:

◦ przy pomocy obrazka tła zawierającego przezroczyste obszary

◦ narysować przy pomocy kształtów WPF

◦ wykorzystać element o odpowiednim kształcie, np. Border

(26)

<Window ...

WindowStyle="None" AllowsTransparency="True"

Background="Transparent" FontSize="20" ... >

<Border BorderThickness="5" CornerRadius="0,20,200,20"

BorderBrush="Brown" Background="LightYellow"

MouseLeftButtonDown="Border_MouseLeftButtonDown">

<WrapPanel Margin="5">

<Label Margin="5" Padding="5">I'm special</Label>

<Button Margin="5" Click="Close_Click"

Padding="15,5">Close</Button>

</WrapPanel>

</Border>

</Window>

przemieszczanie okien

automatyczne: wystarczy uruchomić przeciąganie po naciśnięciu przycisku myszy (na powierzchni okna lub pewnym jego elemencie)

private void Border_MouseLeftButtonDown(object sender,

MouseButtonEventArgs e) {

this.DragMove();

}

26/30

(27)
(28)

Jak powiększać okno o nietypowym kształcie?

• najłatwiej jest dodać jakiś element na brzegu okna

• z jednej strony zadba on o zmianę kursora

• z drugiej – posłuży jako uchwyt, za który możemy złapać

• zmiana rozmiaru to zwykłe ustawienie własności Width/ Height

<Border ...>

<Grid>

<WrapPanel Margin="5">

...

</WrapPanel>

<Ellipse Height="20" Width="20" Margin="0,0,46,46"

HorizontalAlignment="Right" VerticalAlignment="Bottom"

Stroke="DarkGreen" StrokeThickness="3" Fill="LawnGreen"

Cursor="ScrollSE" MouseMove="Resize_MouseMove"

MouseLeftButtonDown="Resize_MouseLeftButtonDown"

MouseLeftButtonUp="Resize_MouseLeftButtonUp"/>

</Grid>

</Border>

28/30

(29)
(30)

obsługa:

private bool resizing = false;

private void Resize_MouseLeftButtonDown(...) {

resizing = true;

}

private void Resize_MouseMove(...) {

if (resizing) {

((UIElement)e.Source).CaptureMouse();

Width = e.GetPosition(this).X;

Height = e.GetPosition(this).Y;

} }

private void Resize_MouseLeftButtonUp(...) {

resizing = false;

Mouse.Capture(null);

}

30/30

Cytaty

Powiązane dokumenty

” Narodowy płatnik tak nisko wycenia procedurę leczenia odwykowego osób uzależnionych od nikotyny, że zamykane są kolejne poradnie antynikotynowe

Strona ta w pewien sposób kumuluje wiedzę ze wszystkich źródeł, na które składają się nie tylko książki, lecz także filmy i wywiady z Rowling, dzięki czemu

Nagród się tu nie przyznaje, formą wyróżnienia jest wybór filmu jako tematu do obrad i dyskusji „okrą­.. głego stołu” - seminarium

Priorytetem technologii stosowanych w magazynach i salach muzealnych jest zagwarantowanie jak naj- lepszych warunków dla zachowania eksponatów, przez co korzystne jest

Żeby dowiedzieć się więcej na temat tego, co dzieje się w konkretnej grupie, możesz przeprowadzić ćwiczenie – poproś uczniów, żeby wyobrazili sobie hipotetyczną

Gdy Chopin jako mały chłopiec miał po raz pierwszy wziąć udział w publicznym koncercie, ubrano go bardzo starannie, nakazując, aby uważał i

Skoro tu mowa o możliwości odtwarzania, to ma to zarazem znaczyć, że przy „automatycznym ” rozumieniu nie może natu ­ ralnie być mowy o jakimś (psychologicznym)

W miarę możliwości zaleca się taką organizację pracy szkoły i jej koordynację, która umożliwi zachowanie dystansu między osobami przebywającymi na terenie szkoły i