• Nie Znaleziono Wyników

Budowa aplikacji w technologii .NET wykład 05 – Polecenia i zasoby

N/A
N/A
Protected

Academic year: 2021

Share "Budowa aplikacji w technologii .NET wykład 05 – Polecenia i zasoby"

Copied!
52
0
0

Pełen tekst

(1)

Budowa aplikacji w technologii .NET

wykład 05 – Polecenia i zasoby Commands – polecenia

• Polecenie jest wyższym poziomem abstrakcji, niż zdarzenie – reprezentuje zadanie, które chce wykonać użytkownik (np. otworzyć plik, skopiować tekst do schowka, wydrukować dokument).

• Zdarzenia są akcjami, które użytkownik musi podjąć, aby wykonać zadanie. W standardowym scenariuszu każde polecenie może być wydane na wiele sposobów:

menu, przycisk na pasku narzędzi, skrót klawiaturowy, etc.

• System poleceń w WPF pozwala wydzielić abstrakcję zadań i utworzyć połączenie miedzy akcją (lub kontrolką) uruchamiającą polecenie a wykonującą je metodą.

Pozwala to przenieść kod wykonujący zadania poza kod kontrolek i zdarzeń (w dobrze zaprojektowanej aplikacji logika nie powinna być umieszczona w

handlerach zdarzeń, ale metodach wyższego poziomu), a jedno polecenie może być powiązane z wieloma elementami interfejsu użytkownika.

• Polecenie może być wyłączone, co dezaktywuje uruchamiające je kontrolki.

(2)

Rozwiązanie przy użyciu zdarzeń (handler jest tylko przekaźnikiem między interfejsem a logiką):

rozwiązanie przy użyciu poleceń:

(za: Pro WPF in C# 2010 Windows Presentation Foundation in .NET 4, Matthew MacDonald)

(3)

Składniki modelu poleceń w WPF:

• Command – obiekt reprezentujący polecenie/ zadanie do wykonania (nie zawiera jednak kodu je wykonującego)

• CommandSource – kontrolka lub akcja wywołująca polecenie

• CommandBinding – obiekt łączący polecenie z jego wykonawcą (handlerem)

• CommandTarget – element, na którym wykonywana jest akcja – np. pole tekstowe na którym wykonywane jest Copy

(4)

Interfejs ICommand

public interface ICommand {

void Execute(object parameter);

bool CanExecute(object parameter);

event EventHandler CanExecuteChanged;

}

• Execute – uruchamia polecenie (ale nie zawiera logiki zadania)

• CanExecute – zwraca stan polecenia (czy jest włączone)

• CanExecuteChanged – zdarzenie wywoływane, gdy stan polecenia ulega zmianie

(5)

Interfejs ICommand

• RoutedCommand jest jedyną klasą bezpośrednio implementującą interfejs ICommand.

• Daje ona wsparcie dla zdarzeń typu tunneling oraz bubbling.

• Dodaje nazwę oraz kolekcję akcji myszy i klawiatury wywołujących polecenie public class RoutedCommand : ICommand

{

public InputGestureCollection InputGestures { get; } public string Name { get; }

public Type OwnerType { get; }

public bool CanExecute(Object parameter, IInputElement target) { } public void Execute(Object parameter, IInputElement target) { } }

• Klasa RoutedUICommand dodaje własność Text, odpowiadającą za tekst wyświetlany w kontrolkach powiązanych z poleceniem.

public class RoutedUICommand : RoutedCommand {

public string Text { get; set; }

(6)

Biblioteka poleceń WPF:

WPF udostępnia zastaw predefiniowanych poleceń do użytku twórcy aplikacji. Są one dostępne poprzez statyczne właściwości poniższych klas:

ApplicationCommands – polecenia związane ze schowkiem (np. Copy, Cut, Paste), zarządzaniem dokumentami (np. New, Open, Save, SaveAs) i operacjami poziomu aplikacji (np. Properties, Help, Print, Undo, Redo)

NavigationCommands – polecenia używane do nawigacji w aplikacjach o interfejsie opartym na stronach (np. BrowseBack, BrowseForward, NextPage, Refresh, IncreaseZoom)

EditingCommands – polecenia związane z edycją dokumentów, dotyczą poruszania się po dokumencie (MoveToLineEnd, MoveLeftByWord,

MoveUpByPage), wyboru zawartości (SelectToLineEnd, SelectLeftByWord) i zmian formatowania (ToggleBold, ToggleUnderline)

ComponentCommands – polecenia używane przez komponenty interfejsu użytkownika (np. MoveLeft, ScrollPageUp)

MediaCommands – polecenia związane z zarządzaniem multimediami (np. Play, Pause, NextTrack, IncreaseVolume)

Część z predefiniowanych poleceń ma już zdefiniowane domyślne połączenie z akcją (popularnymi skrótami klawiaturowymi: Ctrl+O, Ctrl+S, Ctrl+Z, etc.).

(7)

Używanie poleceń:

1. Wybór polecenia

• jednego z gotowych lub zdefiniowanie własnej klasy polecenia

(8)

Używanie poleceń:

1. Wybór polecenia

2. Przypisanie polecenia uruchamiającej je kontrolce lub/i akcji klawiatury/ myszy

• polecenia mogą być wywoływane z kodu poprzez metodę Execute

• przeważnie jednak przypisujemy je do kontrolek implementujących interfejs ICommandSource: kontrolki dziedziczące z ButtonBase, odnośniki

(Hyperlink), elementy list (ListBoxItem) i menu (MenuItem)

<Button Command="ApplicationCommands.Help">Help</Button>

• lub:

<Button Command="Help">Help</Button>

• można też dodać:

CommandParameter – dodatkowy parametr dla polecenia

CommandTarget – element na którym ma być wykonane polecenie

(9)

Używanie poleceń:

1. Wybór polecenia

2. Przypisanie polecenia uruchamiającej je kontrolce lub/i akcji klawiatury/ myszy

• polecenia mogą być wywoływane z kodu poprzez metodę Execute

• przeważnie jednak przypisujemy je do kontrolek implementujących interfejs ICommandSource: kontrolki dziedziczące z ButtonBase, odnośniki

(Hyperlink), elementy list (ListBoxItem) i menu (MenuItem)

• możemy dodać wiele źródeł jednego polecenia:

<DockPanel>

<Menu DockPanel.Dock="Top">

...

<MenuItem Header="Help">

<MenuItem Command="Help"></MenuItem>

</MenuItem>

</Menu>

<StackPanel> ... </StackPanel>

</DockPanel>

kontrolka MenuItem wykorzystuje własność Text oraz przypisany skrót do wyświetlania

(10)

Używanie poleceń:

1. Wybór polecenia

2. Przypisanie polecenia uruchamiającej je kontrolce lub/i akcji klawiatury/ myszy

• polecenia mogą być wywoływane z kodu poprzez metodę Execute

• przeważnie jednak przypisujemy je do kontrolek implementujących interfejs ICommandSource

• przypisanie polecenia akcji myszy lub klawiatury:

ApplicationCommands.Help.InputGestures.Add(

new MouseGesture(MouseAction.LeftDoubleClick));

ApplicationCommands.Help.InputGestures.Add(

new KeyGesture(Key.H, ModifierKeys.Control));

• lub:

<Window.InputBindings>

<KeyBinding Command="Help" Key="H" Modifiers="Ctrl"/>

<MouseBinding Command="Help" MouseAction="LeftDoubleClick"/>

</Window.InputBindings>

(11)

Używanie poleceń:

1. Wybór polecenia

2. Przypisanie polecenia uruchamiającej je kontrolce lub/i akcji klawiatury/ myszy 3. Stworzenie metody wykonującej polecenie

private void MyHelp(object sender, ExecutedRoutedEventArgs e) {

MessageBox.Show("Udało ci się uruchomić pomoc.", "Pomoc",

MessageBoxButton.OK,

MessageBoxImage.Information);

e.Handled = true;

}

e.Command – polecenie, które wywołało tę metodę

• e.Parameter – dodatkowy parametr, który mogliśmy przekazać u źródła

(12)

Używanie poleceń:

1. Wybór polecenia

2. Przypisanie polecenia uruchamiającej je kontrolce lub/i akcji klawiatury/ myszy 3. Stworzenie metody wykonującej polecenie

4. Stworzenie powiązania (CommandBinding) łączącego polecenie z wykonawcą

• wiąże logikę z poleceniem – bez tego polecenie jest wyłączone, a kontrolki nieaktywne

5. Dodanie stworzonego powiązania do kolekcji poleceń okna // stworzenie dowiązania

CommandBinding bind = new CommandBinding();

bind.Command = ApplicationCommands.Help;

// przypisanie handlera do obsługi zdarzenia bind.Executed += MyHelp;

// rejestracja dowiązania

this.CommandBindings.Add(bind);

• powiązanie można dodać do dowolnego elementu, ale zazwyczaj dodawane jest do okna najwyższego poziomu

• zdarzenie odpalane jest przez przypisany poleceniu element, ale dzięki bubbling dotrze do elementu zawierającego powiązanie

(13)

Używanie poleceń:

1. Wybór polecenia

2. Przypisanie polecenia uruchamiającej je kontrolce lub/i akcji klawiatury/ myszy 3. Stworzenie metody wykonującej polecenie

4. Stworzenie powiązania (CommandBinding) łączącego polecenie z wykonawcą

• wiąże logikę z poleceniem – bez tego polecenie jest wyłączone, a kontrolki nieaktywne

5. Dodanie stworzonego powiązania do kolekcji poleceń okna this.CommandBindings.Add(

new CommandBinding(ApplicationCommands.Help, MyHelp));

(14)

Używanie poleceń:

1. Wybór polecenia

2. Przypisanie polecenia uruchamiającej je kontrolce lub/i akcji klawiatury/ myszy 3. Stworzenie metody wykonującej polecenie

4. Stworzenie powiązania (CommandBinding) łączącego polecenie z wykonawcą

• wiąże logikę z poleceniem – bez tego polecenie jest wyłączone, a kontrolki nieaktywne

5. Dodanie stworzonego powiązania do kolekcji poleceń okna

<Window ...>

<Window.CommandBindings>

<CommandBinding Command="Help" Executed="MyHelp" />

</Window.CommandBindings>

...

</Window>

• wiązanie wykonuje się raz, niezależnie od liczby źródeł

(15)

Wyłączanie poleceń

• Przydatne w przypadku poleceń, które mogą być wywoływane tylko w określonych sytuacjach

• Włączanie/ wyłączanie odbywa się w obsłudze zdarzenia CanExecute:

CommandBinding bind = new CommandBinding();

...

bind.CanExecute += MyHelpCanExecute;

...

this.CommandBindings.Add(bind);

• lub:

new CommandBinding(ApplicationCommands.Help, MyHelp,

MyHelpCanExecute)

• lub:

<CommandBinding Command="Help" Executed="MyHelp"

CanExecute="MyHelpCanExecute"/>

(16)

Wyłączanie poleceń

• Przydatne w przypadku poleceń, które mogą być wywoływane tylko w określonych sytuacjach

• Włączanie/ wyłączanie odbywa się w obsłudze zdarzenia CanExecute:

private void MyHelpCanExecute(object sender,

CanExecuteRoutedEventArgs e) {

if( /*... help dostępny ...*/ ) e.CanExecute = true;

else

e.CanExecute = false;

}

• uwaga: ta metoda może uruchamiać się często – gdy WPF uzna, że mogła zajść jakaś zmiana

• można też uruchomić ręcznie, aby wymusić odświeżenie kontrolek:

CommandManager.InvalidateRequerySuggested();

(17)

Przykład użycia:

<Window ...>

<Window.CommandBindings>

<CommandBinding Command="Save" Executed="MySave"

CanExecute="MySaveCanExecute" />

</Window.CommandBindings>

<StackPanel>

<TextBox TextChanged="MyTextChanged"></TextBox>

<Button Command="Save">Save</Button>

</StackPanel>

</Window>

(18)

public partial class Window1 : Window {

public Window1() {

InitializeComponent();

IsDirty = false;

}

private bool IsDirty { get; set; } private void MySave(...)

{

IsDirty = false;

}

private void MySaveCanExecute(...) {

e.CanExecute = IsDirty;

}

private void MyTextChanged(...) {

IsDirty = true;

} }

(19)

Techniki zaawansowane – definiowanie własnych poleceń public class PizzaCommands

{

private static RoutedUICommand piecz;

static PizzaCommands() {

piecz = new RoutedUICommand(

"Upiecz Pizzę", "Piecz", typeof(PizzaCommands));

// dobrym pomysłem jest dodanie tutaj // skrótów klawiatury:

piecz.InputGestures.Add(new KeyGesture(Key.P,

ModifierKeys.Control));

}

public static RoutedUICommand Piecz {

get { return piecz; } }

}

(20)

Techniki zaawansowane – definiowanie własnych poleceń

<Window ...

xmlns:app="clr-namespace:WpfApplication1" ... >

<Grid>

...

<Button Command="app:PizzaCommands.Piecz">

Upiecz Pizzę </Button>

...

</Grid>

</Window>

• Przed przypisaniem polecenia kontrolce, musimy zmapować własną przestrzeń nazw do zrozumiałej przez XAMLa (WpfApplication1 to nazwa projektu, app to wybrany alias).

(21)

Techniki zaawansowane – wykorzystanie własności Text

• własność Text zawiera opisową nazwę polecenia; niektóre kontrolki (np.

MenuItem) same go wykorzystują, w wypadku Buttonów możemy zrobić to ręcznie:

<Button Command="SaveAs"

Content="{x:Static ApplicationCommands.SaveAs}"></Button>

• jednak w ten sposób uzyskamy jedynie nazwę pobraną z ToString, a nie opisowy tekst polecenia; do tego lepiej wykorzystać wiązanie (o wiązaniach więcej na kolejnym wykładzie):

<Button Command="SaveAs"

Content="{Binding RelativeSource={RelativeSource Self}, Path=Command.Text}"></Button>

• można go użyć również np. w tooltipie:

<Button Command="SaveAs"

ToolTip="{Binding RelativeSource={RelativeSource Self}, Path=Command.Text}">

(22)

Techniki zaawansowane – kontrolki z wbudowaną obsługą poleceń

• Niektóre kontrolki do wprowadzania danych mają wbudowaną obsługę poleceń (np. TextBox obsługuje polecenia Cut, Copy, Paste).

• Przyciski z przypisanymi poleceniami, umieszczone w toolbarze lub menu automatycznie to obsłużą, bez dowiązywania jakiejkolwiek logiki.

• Kontrolki same (po focusie) rozpoznają kiedy polecenie może być wywołane oraz co jest elementem docelowym.

<StackPanel>

<ToolBar>

...

<Button Command="Paste">Paste</Button>

</ToolBar>

<TextBox Name="txtBox"></TextBox>

<WrapPanel>

...

<Button Command="Paste">Paste</Button>

</WrapPanel>

</StackPanel>

(23)

Techniki zaawansowane – kontrolki z wbudowaną obsługą poleceń

• Niektóre kontrolki do wprowadzania danych mają wbudowaną obsługę poleceń (np. TextBox obsługuje polecenia Cut, Copy, Paste).

• Przyciski z przypisanymi poleceniami, umieszczone w toolbarze lub menu automatycznie to obsłużą, bez dowiązywania jakiejkolwiek logiki.

• Kontrolki same (po focusie) rozpoznają kiedy polecenie może być wywołane oraz co jest elementem docelowym.

<StackPanel>

<ToolBar>

...

<Button Command="Paste">Paste</Button>

</ToolBar>

<TextBox Name="txtBox"></TextBox>

<WrapPanel>

...

<Button Command="Paste">Paste</Button>

</WrapPanel>

</StackPanel>

(24)

Techniki zaawansowane – kontrolki z wbudowaną obsługą poleceń

• W wypadku kontrolek poza menu czy toolbarem możemy samodzielnie wskazać element docelowy polecenia:

<TextBox Name="txtBox"></TextBox>

<WrapPanel>

...

<Button Command="Paste"

CommandTarget="{Binding ElementName=txtBx}">

Paste</Button>

</WrapPanel>

• lub kazać poszukiwać go w elementach nadrzędnych (hierarchii zagnieżdżenia)

<WrapPanel FocusManager.IsFocusScope="True">

...

<Button Command="Paste">Paste</Button>

</WrapPanel>

(25)

Techniki zaawansowane – kontrolki z wbudowaną obsługą poleceń

• W wypadku kontrolek poza menu czy toolbarem możemy samodzielnie wskazać element docelowy polecenia:

<TextBox Name="txtBox"></TextBox>

<WrapPanel>

...

<Button Command="Paste"

CommandTarget="{Binding ElementName=txtBx}">

Paste</Button>

</WrapPanel>

• lub kazać poszukiwać go w elementach nadrzędnych (hierarchii zagnieżdżenia)

<WrapPanel FocusManager.IsFocusScope="True">

...

<Button Command="Paste">Paste</Button>

</WrapPanel>

(26)

Techniki zaawansowane – kontrolki z wbudowaną obsługą poleceń

Gdy chcemy wyłączyć polecenie kontrolki:

niekiedy mamy gotową flagę, np. TextBox pozwala na ustawienie IsUndoEnabled, aby wyłączyć Undo

• możemy też dodać własne wiązanie do tego polecenia, które dostarczy CanExecuted zawsze zwracające false:

CommandBinding commandBinding = new CommandBinding(

ApplicationCommands.Cut, null, SuppressCommand);

txtBox.CommandBindings.Add(commandBinding);

• i:

private void SuppressCommand(...) {

e.CanExecute = false;

e.Handled = true;

}

(27)

Techniki zaawansowane – kontrolki z wbudowaną obsługą poleceń

Gdy chcemy wyłączyć polecenie kontrolki:

niekiedy mamy gotową flagę, np. TextBox pozwala na ustawienie IsUndoEnabled, aby wyłączyć Undo

• możemy też dodać własne wiązanie do tego polecenia, które dostarczy CanExecuted zawsze zwracające false

• akcję (np. skrót klawiaturowy) uruchamiające to polecenie możemy związać poleceniem „to nie jest polecenie”:

KeyBinding keyBinding = new KeyBinding(

ApplicationCommands.NotACommand, Key.C, ModifierKeys.Control);

txt.InputBindings.Add(keyBinding);

(28)

Techniki zaawansowane – wykorzystanie tego samego polecenia w kilku miejscach

• Efekt polecenia zależy od elementu docelowego (np. gdy mamy dwa pola tekstowe w oknie, Cut, Copy, Paste działają dla jednego z nich, zależnie od focusa)

<StackPanel>

<ToolBar>

<Button Command="Cut">Cut</Button>

<Button Command="Copy">Copy</Button>

<Button Command="Paste">Paste</Button>

</ToolBar>

<TextBox ></TextBox>

<TextBox ></TextBox>

</StackPanel>

(29)

Techniki zaawansowane – wykorzystanie tego samego polecenia w kilku miejscach

• Efekt polecenia zależy od elementu docelowego (np. gdy mamy dwa pola tekstowe w oknie, Cut, Copy, Paste działają dla jednego z nich, zależnie od focusa)

• Jak uzyskać ten efekt dla innych poleceń?

<Window ...>

<Window.CommandBindings>

<CommandBinding Command="Save" Executed="MySave"

CanExecute="MySaveCanExecute" />

</Window.CommandBindings>

<StackPanel>

<ToolBar>

...

<Button Command="Save">Save</Button>

</ToolBar>

<TextBox TextChanged="MyTextChanged"></TextBox>

<TextBox TextChanged="MyTextChanged"></TextBox>

</StackPanel>

</Window>

(30)

Techniki zaawansowane – wykorzystanie tego samego polecenia w kilku miejscach

• Efekt polecenia zależy od elementu docelowego (np. gdy mamy dwa pola tekstowe w oknie, Cut, Copy, Paste działają dla jednego z nich, zależnie od focusa)

• Jak uzyskać ten efekt dla innych poleceń?

<Window ...>

<Window.CommandBindings>

<CommandBinding Command="Save" Executed="MySave"

CanExecute="MySaveCanExecute" />

</Window.CommandBindings>

<StackPanel>

<ToolBar>

...

<Button Command="Save">Save</Button>

</ToolBar>

<TextBox TextChanged="MyTextChanged"></TextBox>

<TextBox TextChanged="MyTextChanged"></TextBox>

</StackPanel>

</Window>

(31)

Techniki zaawansowane – wykorzystanie tego samego polecenia w kilku miejscach

• Efekt polecenia zależy od elementu docelowego (np. gdy mamy dwa pola tekstowe w oknie, Cut, Copy, Paste działają dla jednego z nich, zależnie od focusa)

• Jak uzyskać ten efekt dla innych poleceń?

private Dictionary<object, bool> isDirty = new ...;

private void MySave(...) {

isDirty[e.Source] = false;

}

private void MySaveCanExecute(...) {

if (isDirty.ContainsKey(e.Source) && isDirty[e.Source]) e.CanExecute = true;

else

e.CanExecute = false;

}

private void MyTextChanged(...) {

isDirty[e.Source] = true;

(32)

Techniki zaawansowane – wykorzystanie tego samego polecenia w kilku miejscach

• Efekt polecenia zależy od elementu docelowego (np. gdy mamy dwa pola tekstowe w oknie, Cut, Copy, Paste działają dla jednego z nich, zależnie od focusa)

• Jak uzyskać ten efekt dla innych poleceń?

• e.Source zwraca element docelowy polecenia, jeżeli:

◦ kontrolka wywołująca polecenie znajduje się w toolbarze

◦ przypisaliśmy ręcznie CommandTarget

◦ nakażemy poszukiwania elementu poprzez FocusManager.IsFocusScope

• w przeciwnym wypadku e.Source będzie kontrolką, która wywołała zdarzenie

• Możemy również tworzyć osobne wiązanie dla każdego pola tekstowego:

<TextBox TextChanged="MyTextChanged">

<TextBox.CommandBindings>

<CommandBinding Command="Save" Executed="MySave"

CanExecute="MySaveCanExecute" />

</TextBox.CommandBindings>

</TextBox>

(33)

Techniki zaawansowane – wykorzystanie tego samego polecenia w kilku miejscach

• Efekt polecenia zależy od elementu docelowego (np. gdy mamy dwa pola tekstowe w oknie, Cut, Copy, Paste działają dla jednego z nich, zależnie od focusa)

• Jak uzyskać ten efekt dla innych poleceń?

• e.Source zwraca element docelowy polecenia, jeżeli:

◦ kontrolka wywołująca polecenie znajduje się w toolbarze

◦ przypisaliśmy ręcznie CommandTarget

◦ nakażemy poszukiwania elementu poprzez FocusManager.IsFocusScope

• w przeciwnym wypadku e.Source będzie kontrolką, która wywołała zdarzenie

• Możemy również tworzyć osobne wiązanie dla każdego pola tekstowego.

Teraz sender powie nam dla którego pola została wywołana metoda:

private void MySave(object sender, ExecutedRoutedEventArgs e) {

string text = ((TextBox)sender).Text;

MessageBox.Show("Dane do zapisania: " + text);

...

}

(34)

Techniki zaawansowane – wykorzystanie tego samego polecenia w kilku miejscach

• Efekt polecenia zależy od elementu docelowego (np. gdy mamy dwa pola tekstowe w oknie, Cut, Copy, Paste działają dla jednego z nich, zależnie od focusa)

• Jak uzyskać ten efekt dla innych poleceń?

• Nieco nieeleganckie jest tworzenie wiązania osobno dla każdego pola, ale da się to rozwiązać definiując zasób:

<Window.Resources>

<CommandBinding x:Key="binding" Command="Save"

Executed="MySave" CanExecute="MySaveCanExecute">

</CommandBinding>

</Window.Resources>

• i używając go:

<TextBox.CommandBindings>

<StaticResource ResourceKey="binding"></StaticResource>

</TextBox.CommandBindings>

(35)

Techniki zaawansowane – parametr przekazywany do Command

• niektóre polecenia wymagają dodatkowego parametru

• można odczytać go z innej kontrolki:

<Button Command="NavigationCommands.Zoom"

CommandParameter="{Binding ElementName=txtZoom, Path=Text}">

Zoom To Value

</Button>

Ograniczenia systemu poleceń:

• Polecenie może zmieniać automatycznie jedynie własność IsEnabled. Użyteczne mogłoby być też IsChecked, niestety, należy robić to ręcznie.

• Nie ma zbudowanych mechanizmów do śledzenia historii wykonywanych poleceń (do Undo/Redo).

(36)

Resources – zasoby

W WPF można wyróżnić dwa rodzaje zasobów:

Assembly resources (binary resources)

◦ pliki z danymi (binarne), wbudowane w skompilowany podzespół aplikacji (np.

obrazki)

działają prawie identycznie jak assembly resources w innych aplikacjach .NET, jedyną różnicą jest system adresujący, wykorzystywany przy odwoływaniu się od zasobów

zasobem typu assembly w aplikacjach WPF jest np. plik BAML (skompilowany plik XAML)

Object resources

◦ mogą być nimi dowolne obiekty, zdefiniowany przeważnie w XAMLu, umożliwiają przechowywanie różnego rodzaju informacji w centralnym miejscu, zapobiegając powtarzaniu kodu

(37)

Dodawanie zasobów typu assembly

• Należy dodać odpowiednie pliki do projektu i ustawić i właściwość Build Action na Resource (w celu lepszej organizacji, pliki mogą być grupowane w foldery).

(38)
(39)
(40)

Odwoływanie się do zasobów typu assembly

• Obiekt StreamResourceInfo daje dostęp m. in. do typu oraz strumienia danych zasobu:

StreamResourceInfo sri = Application.GetResourceStream(

new Uri("images/info.png", UriKind.Relative));

◦ ContentType zwraca string opisujący typ danych

◦ Stream – strumień (typu UnmanagedMemoryStream), z którego można odczytać bajty danych

• Niektóre klasy mają wbudowaną obsługę zasobów i potrafią z nimi współpracować (odnajdują je przez adres URI):

<Image Source="images/info.png" />

• lub:

image1.Source = new BitmapImage(

new Uri("images/info.png", UriKind.Relative));

(41)

Odwoływanie się do zasobów typu assembly

• Przez adres URI w przypadku zasobów zawartych w innym podzespole (bibliotece dll, z której korzysta nasza aplikacja):

img.Source = new BitmapImage(

new Uri("ImageLibrary;component/images/winter.jpg", UriKind.Relative));

Dodawanie zasobów z Build Action na Content (i Copy to Output Directory)

• Warto używać, gdy:

◦ chcemy zmieniać zasób bez ponownej kompilacji

◦ zasób jest bardzo duży

◦ plik jest opcjonalny i chcemy dostarczać aplikację również bez niego

◦ jest to plik dźwiękowy

• Content jest wygodniejsze, niż po prostu zwykłe dostarczenie plików z aplikacją i odczytywanie ich z dysku.

(42)

Object Resources

• Nowy system zasobów zintegrowany z XAML

• Możliwość definiowania zasobów w różnych miejscach (kontrolki, okna, cała aplikacja)

• Zasoby obiektowe (deklaratywne, logiczne):

◦ pozwalają na zdefiniowanie obiektu raz i używanie go w wielu miejscach kodu

◦ umożliwiają przeniesienie np. szczegółów formatujących kontrolek do centralnego miejsca, w którym mogą być w łatwy sposób zmieniane

◦ gdy pewna informacja jest oddzielona od reszty aplikacja, może być modyfikowana dynamicznie

(43)

Przykład wykorzystania Object resources definiowanie zasobu:

<Window.Resources>

<SolidColorBrush x:Key="zielony" Color="Green" />

</Window.Resources>

korzystanie z zasobu:

<Button Background="{StaticResource zielony}">

Statycznie

</Button>

<Button Background="{DynamicResource zielony}">

Dynamicznie

</Button>

(44)

Kolekcja zasobów

• Każdy element posiada właściwość Resources, która przechowuje kolekcję zasobów (ResourceDictionary)

• Kolekcja zasobów może przechowywać dowolne typy obiektów

• Przeważnie zasoby definiowane są na poziomie okna, gdyż wszystkie dzieci mają dostęp do zasobów ojca

(45)

Zasoby statyczne i dynamiczne

• Zasoby statyczne, w przeciwieństwie do dynamicznych, są pobierane raz (po deklaracji w kodzie XAML) i nie reagują na zmianę zasobu z poziomu kodu

this.Resources["zielony"] =

new SolidColorBrush(Colors.Yellow);

• Zasoby dynamiczne pobierane są za każdym razem, gdy są potrzebne. Ponieważ wiąże się to z dodatkowym narzutem, z zasobów dynamicznych należy korzystać tylko wtedy, gdy:

◦ zasób zależy od ustawień systemowych (np. kolory systemowe)

◦ planujemy podmieniać obiekty dynamicznie

(46)

Zasoby statyczne i dynamiczne

• Dlaczego jednak to działa?

SolidColorBrush brush =

(SolidColorBrush)this.Resources["zielony"];

brush.Color = Colors.Red;

• Ponieważ nie podmieniliśmy obiektu, a jedynie zmieniliśmy jego stan wewnętrzny.

Zaś Brush informuje każdą używającą go kontrolkę o swojej zmianie.

(47)

Techniki zaawansowane – zasoby niewspółdzielone

• Zazwyczaj powstaje jeden obiekt, z którego korzystają wszyscy używajacy tego zasobu.

• Możemy jednak udostępniać każdemu jego własny obiekt – można rozważać wykorzystanie tego, jeśli każdy użytkownik chce osobno modyfikować zasób lub zasobem jest coś, czego nie możemy dzielić (np. element) – są jednak lepsze sposoby by to osiągnąć.

<SolidColorBrush x:Key="TileBrush" x:Shared="False" ...>

</SolidColorBrush>

(48)

Techniki zaawansowane – dostęp do zasobów w kodzie

• W ten sposób mamy dostęp do zasobów zdefiniowanych w tej kontrolce:

Button cmd = (Button)sender;

Brush brush = (Brush)cmd.Resources["zielony"];

• Dzięki temu nie musimy znać położenia zasobu – nastąpi poszukiwanie, jak w wypadku korzystania z zasobu w XAMLu:

Brush brush = (Brush)cmd.FindResource("zielony");

Jest też TryFindResource(), które w razie niepowodzenia nie rzuca wyjątku, tylko zwraca null.

(49)

Zasoby aplikacji:

<Application ...>

<Application.Resources>

<SolidColorBrush x:Key="zielony" Color="Green" />

<SolidColorBrush x:Key="czerwony" Color="Red" />

<SolidColorBrush x:Key="niebieski" Color="Blue" />

</Application.Resources>

</Application>

• Są dostępne w całej aplikacji

◦ są trochę jak zmienne globalne: nie należy z nimi przesadzać

Jeszcze wyżej w drzewie poszukiwania znajdują się zasoby systemowe

(50)

Zasoby systemowe:

• Udostępniane są poprzez trzy klasy (przestrzeń nazw System.Windows):

SystemColors, SystemFonts, SystemParameters label.Foreground =

new SolidBrush(SystemColors.WindowTextColor);

• lub:

label.Foreground = SystemColors.WindowTextBrush;

• lub:

<Label Foreground="{x:Static SystemColors.WindowTextBrush}">

Napis

</Label>

• lub:

<Label Foreground="{DynamicResource

{x:Static SystemColors.WindowTextBrushKey}}">

Napis</Label>

(51)

Organizacja zasobów

• W celu umożliwienia współdzielenia zasobów między różnymi projektami tworzy się słowniki zasobów. Są one zapisywane w plikach XAML (dołączanych do aplikacji, z Build Action ustawionym na Page.

w pliku AppBrushes.xaml:

<ResourceDictionary ... >

<SolidColorBrush x:Key="zielony" Color="Green" />

<SolidColorBrush x:Key="czerwony" Color="Red" />

<SolidColorBrush x:Key="niebieski" Color="Blue" />

</ResourceDictionary>

(52)

Organizacja zasobów

• Następnie powinny być dołączone do jakiejś kolekcji zasobów w aplikacji.

<Application ... >

<Application.Resources>

<ResourceDictionary>

<ResourceDictionary.MergedDictionaries>

<ResourceDictionary Source="AppBrushes.xaml"/>

<ResourceDictionary Source="..."/>

</ResourceDictionary.MergedDictionaries>

<SolidColorBrush x:Key="inne zasoby" ... />

...

</ResourceDictionary>

</Application.Resources>

</Application>

Cytaty

Powiązane dokumenty

• Positions – kolekcja wszystkich punktów siatki (wierzchołków trójkątów). Często jeden punkt jest wierzchołkiem kilku trójkątów, np: sześcian wymaga 12 trójkątów,

Napisz program z wykorzystaniem rekurencji, dodający dwie liczby naturalne. Napisz program z wykorzystaniem rekurencji, mnożący dwie

• mv [opcje] źródło1 [źródło2 [...]] cel przenosi wskazane pliki / katalogi do wskazanej lo- kalizacji, w przypadku przenoszenia wielu plików cel powinien być katalogiem,

C:\&gt;move *.txt c:\DANE przeniesienie wszystkich plików tekstowych do katalogu DANE. C:\&gt;move DANE INFO zmiana nazwy katalogu DANE na

exec - proces dziecko, po odszukaniu ścieżki na dysku, gdzie znajduje się wykonywalny program odpowiadający poleceniu, które nie jest wbudowane w jądro (np. ls), wydaje exec,

Operator „|” umożliwia skierowanie wyjścia (wyniku) jednego polecenia na wejście innego

Utwórz katalog feb20 i przejdź do niego, a następnie używając polecenia touch utwórz w nim następujące pliki:. ab abc a1 a2 a3 all ba ba.1 ba.2 filex filey AbC ABC

znaków spacji, tabulacji oraz znaku nowej linii.. Przejdź do katalogu dolny1 , a następnie używając odpowiednich poleceń ustal czy:. a) posiadasz w swoim systemie plików plik info,