Rozszerzanie biblioteki Prism

Slides:



Advertisements
Podobne prezentacje
Tworzenie odwołania zewnętrznego (łącza) do zakresu komórek w innym skoroszycie Możliwości efektywnego stosowania odwołań zewnętrznych Odwołania zewnętrzne.
Advertisements

PRACA Z APLIKACJAMI SYSTEM PRZEMIESZCZANIA oraz NADZORU WYROBÓW AKCYZOWYCH EMCS PL 1.
Wyszukiwanie informacji w Internecie. Czym jest wyszukiwarka? INTERNET ZASOBY ZAINDEKSOWANE PRZEZ WYSZUKIWARKI Wyszukiwarka to mechanizm, który za pomocą.
Urząd Transportu Kolejowego, Al. Jerozolimskie 134, Warszawa, Polityka regulacyjna państwa w zakresie dostępu do infrastruktury na.
Literary Reference Center Przewodnik
Jeśli chcesz przejść do konkretnego zagadnienia, wybierz je z listy: Dopisanie narzędzia Modyfikacja narzędzia Usunięcia narzędzia Lokalizacja domyślna.
Zapraszamy na naszą stronę. Zależy nam na kontakcie z Wami. Czytajcie, komentujcie i dyskutujcie na forum. Nic o Was bez Was Zapraszamy na naszą stronę.
Porównywarki cen leków w Polsce i na świecie. Porównywarki w Polsce.
Model warstwowy OSI Model OSI (Open Systems Interconnection) opisuje sposób przepływu informacji między aplikacjami programowymi w jednej stacji sieciowej.
Instalacja nienadzorowana windows xp Jakub klafta.
Metody sztucznej inteligencji - Technologie rozmyte i neuronowe 2015/2016 Perceptrony proste nieliniowe i wielowarstwowe © Kazimierz Duzinkiewicz, dr hab.
Definiowanie i planowanie zadań typu P 1.  Planowanie zadań typu P  Zadania typu P to zadania unikalne służące zwykle dokonaniu jednorazowej, konkretnej.
1 Definiowanie i planowanie zadań budżetowych typu B.
U MAD BRO?. Nie wiesz w jaki sposób znalazłeś się w tym pokoju. Nie znasz osób które znajdują się tu z Tobą. Wiesz natomiast, że musicie się stąd wydostać.
Jak tworzymy katalog alfabetyczny? Oprac.Regina Lewańska.
Moduł SDI – zasilanie węzłów IIP oraz wykorzystanie danych. Wprowadzenie. Szkolenie przeprowadzone w ramach projektu „TERYT 3 – Rozbudowa systemów do prowadzenia.
Budżetowanie kapitałowe cz. III. NIEPEWNOŚĆ senesu lago NIEPEWNOŚĆ NIEMIERZALNA senesu strice RYZYKO (niepewność mierzalna)
O PARADOKSIE BRAESSA Zbigniew Świtalski Paweł Skałecki Wydział Matematyki, Informatyki i Ekonometrii Uniwersytet Zielonogórski Zakopane 2016.
Język Java Paweł Rajba
Dziedziczenie, polimorfizm, Interfejsy
BVMS 5.5 Blok2- Moduł 8: Użytkownicy i grupy
Programowanie Obiektowe – Wykład 1
Komunikacja ze szkołą i nauczycielami - dziennik elektroniczny
Wytwarzanie oprogramowania sterowane przypadkami testowymi
DEFINICJA I ZASTOSOWANIE W JĘZYKU HASKELL
SYSTEM KWALIFIKACJI, AWANSÓW I SPADKÓW
Podstawowe polecenia systemu
Full Text Finder Przegląd Publication Finder
Akademia C# - Lab2 Zmienne, instrukcje warunkowe, pętle, debugger,
Microsoft® Office SharePoint® Server 2007 — szkolenie
Akademia C# lab. 9 Zdarzenia i delegaty.
Programowanie obiektowe
Optymalizacja programów Open-Source
Przewodnik Udoskonalanie listy wyników w wyszukiwarce naukowej
Lekcja 1 – Hello World! Visual Studio, coś łatwego na początek 
Materiały pochodzą z Platformy Edukacyjnej Portalu
PowerPoint — Zapraszamy!
Tytuł – [najlepiej aby jak najtrafniej oddawał opisywane rozwiązanie]
Wykorzystanie aplikacji użytkowych do przeprowadzenia cyberataku
Inżynieria Oprogramowania Laboratorium
PROGRAMY DO KONTROLI RODZICIELSKIEJ
Git - system kontroli wersji
Bezpieczeństwo dostępu do danych w systemie Windows
Języki programowania.
SMB – Pierwszy projekt Michail Mokkas.
Jak dostosować witrynę internetową usługi Microsoft SharePoint Online
Laboratorium 1 – obsługa wejść i wyjść
Jak korzystać z usługi Video s i Raportu Kontaktów
Podstawy informatyki Zygfryd Głowacz.
Strukturalne wzorce projektowe
To naprawdę bardzo proste!
PGO Kolekcje Michail Mokkas.
Tytuł – [najlepiej aby jak najtrafniej oddawał opisywane rozwiązanie]
Wyjazdy dydaktyczne i szkoleniowe dla kadry akademickiej.
Zdarzenia (eventy) Zdarzenia służą do powiadomienia użytkownika, gdy w używanej klasie dojdzie do pewnych wydarzeń zdefiniowanych przez twórcę klasy.
Implementacja rekurencji w języku Haskell
Znajdowanie liczb pierwszych w zbiorze
POZNAJEMY PULPIT Opracowanie: mgr Barbara Benisz SP nr 20 w Rybniku
Język C++ Preprocesor Łukasz Sztangret Katedra Informatyki Stosowanej i Modelowania Prezentacja przygotowana w oparciu o materiały Danuty Szeligi i Pawła.
Obsługa bazy danych z poziomu phpMyAdmin
Język C++ Operatory Łukasz Sztangret Katedra Informatyki Stosowanej i Modelowania Prezentacja przygotowana w oparciu o materiały Danuty Szeligi i Pawła.
Kwerendy funkcjonalne (Action queries)
Prawa ruchu ośrodków ciągłych c. d.
Modelowanie obiektowe - system zarządzania projektami
Autor: Magdalena Linowiecka
Asynchroniczne operacje I/O za pomocą IOCP
To naprawdę bardzo proste!
Platforma LearningApps
Instrukcja podpięć przedmiotów w USOSie
Platforma LearningApps
Zapis prezentacji:

Rozszerzanie biblioteki Prism Marcin Przybył

Biblioteka PRISM Prism Biblioteka może służyć jako podstawa dla aplikacji klienckich WPF. Prism Biblioteka została zaprojektowana tak, żeby istotne elementy mogły być dostosowane lub zastąpione, aby pasowały do ​​konkretnego scenariusza. Można modyfikować kod źródłowy dla istniejącej biblioteki, dodając nowe funkcje.Większość technik opierają się jednak na wymianie lub modyfikacji konfiguracji domyślnej biblioteki Prism podczas sekwencji ładowania początkowego po uruchomieniu aplikacji.

Punkty rozszerzeń Aby tego dokonać, należy użyć punktów rozszerzalności, takich jak publicznych klas bazowych lub interfejsów. Programiści mogą rozszerzać klasy bazowe lub zaimplementować interfejsy, aby następnie dodać swoje rozszerzenia do biblioteki. Przy rozważaniu zbioru puntów rozszerzeń należy rozważyć wpływ na użyteczność. Duża liczba punktów rozszerzeń może niepotrzebnie skomplikować bibliotekę i będzie ona trudna w obsłudze oraz konfiguracji.

Co z modyfikacją kodu? Programista powinien: Przestrzegać zasad projektowania obiektowego Stosować odpowiednie wzorce projektowe. Efektywne wykorzystanie zasobów. Stosować się do zasad bezpieczeństwa (na przykład, brak zaufania do wprowadzania danych przez użytkownika i zasady najmniejszych uprawnień).

Wskazówki Podczas modyfikowania kodu źródłowego, wykonaj poniższe wskazówki: Upewnij się, że wiesz, jak biblioteka działa czytając tematy, które opisują jej konstrukcję. Rozważ zmianę nazw biblioteki jeśli znacząco zmieniasz kod lub jeśli chcesz korzystać z dostosowaną wersją biblioteki wraz z oryginalną wersją. Zastanów się nad stworzeniem podzespołów wykorzystujących puntów rozszerzeń biblioteki PRISM przed modyfikacją kodu źródłowego. Używaj silnego nazewnictwa. Silna nazwa pozwala identyfikować podzespół i jego wersję oraz pozwala sprawdzać integralność. Musisz wygenerować własną pary kluczy do podpisania zmodyfikowanej wersji bloku aplikacji. Alternatywnie, możesz nie podpisać wersję niestandardową. Jest to określane jako słabe nazewnictwo. (http://msdn2.microsoft.com/en-us/library/wd40t7ad(vs.71).aspx)

Bootstrapper Bootstrapper pełni rolę kleju w naszej aplikacji. Odpowiada za inicjalizację głównego okna, rejestrację modułów, inicjalizację kontenera DI.

Usługi IModuleManager - zwraca interfejs wykorzystywany do inicjalizacji i zwracania modułów IModuleCatalog - metadane o modułach w aplikacji IModuleInitializer - inicjuje moduły IRegionManager - rejestruje regiony, wykorzystywane przy wizualnej reprezentacji naszej aplikacji IEventAggregator - reprezentuje kolekcję zdarzeń które są luźno powiązane pomiędzy subskrybującymi i oferującymi usługi. ILoggerFacade - mechanizm logowania zdarzeń występujących w naszej aplikacji IServiceLocator - pozwala na dostanie się do kontenera tworzonego w Prism. Podczas inicjalizacji Bootstrappera zostają zarejestrowane podstawowe usługi (serwisy) które następnie mogą zostać wykorzystane przy budowie naszych modułów. Usługi z których możemy skorzystać to:

Użycie Unity // Przy użyciu Unity public class ReplacementEventAggregator: IEventAggregator { // ... } // Bootstraper protected override void ConfigureContainer() { this.RegisterTypeIfMissing(typeof(IEventAggregator), typeof(ReplacementEventAggregator), true); base.ConfigureContainer(); } Domyślna implementacja ConfigureContainer wykorzystuje metodę RegisterTypeIfMissing aby dodać typ z PRISM jeśli interfejs nie jest jeszcze zarejestrowany. Aby zmienić typy PRISM za pomocą Unity należy najpierw wyprowadzić swój nowy typ z interfejsu lub klasy, który chcesz zastąpić. Poniższy przykład kodu pokazuje zastępstwo dla interfejsu IEventAggregator. Teraz,trzeba zastąpić metodę ConfigureContainer w bootstrapperze zarejestrować i typ interfejsu przed wywołaniem klasy podstawowej. Poniższy przykład kodu pokazuje, jak zarejestrować inną implementacje IEventAggregator.

Okrojony Bootstraper // when using UnityBootstrapper protected override void ConfigureContainer() { this.Container.AddNewExtension<UnityBootstrapperExtension>(); Container.RegisterInstance<ILoggerFacade>(Logger); this.Container.RegisterInstance(this.ModuleCatalog); RegisterTypeIfMissing(typeof(IServiceLocator), typeof(UnityServiceLocatorAdapter), true); } protected override RegionAdapterMappings ConfigureRegionAdapterMappings() { return null; } protected override IRegionBehaviorFactory ConfigureDefaultRegionBehaviors() { return null; } Niektóre aplikację nie używają dużo funkcji z PRISM. Dlatego czasem developer chciałbym ograniczyć sie do wstrzykiwania zależności i usług. Aby to zrobić należy nadpisać metodę ConfigureContainer w bootstrapper

Zmiana DI Container Service Locator Bootstraper Jeżeli chcesz korzystać z kontenerów Di innych niż Unity lub MEF w aplikacji, istnieje kilka rzeczy, które trzeba zrobić. Po pierwsze, trzeba napisać adapter Service Locator dla pojemnika. Można użyć MefServiceLocatorAdapter i UnityServiceLocatorAdapter jako przykłady. Potrzebny będzie również napisać klasę własną inicjującą i wdrożyć niezbędnych metod, można zagłębć się w MefBootstrapper i UnityBootstrapper jako przykłady.

Logger // Logger using Microsoft.Practices.Prism.Logging; ... public class CustomLogger : ILoggerFacade { public void Log(string message, Category category, Priority priority) { string messageToLog = String.Format(System.Globalization.CultureInfo.InvariantCulture, "{1}: {2}. Priority: {3}. Timestamp:{0:u}.", DateTime.Now, category.ToString().ToUpperInvariant(), message, priority.ToString()); MyOtherLoggingFramework.Log(messageToLog); } } Niektóre komponenty biblioteki PRISM rejestrują informacje, ostrzeżenia lub komunikaty o błędach. Aby uniknąć zależność od podejścia poszczególnych loggerów, rejestruje te wiadomości do interfejsu ILoggerFacade. Interfejs ten zawiera jedną metodę o nazwie Log, która loguje wiadomości. Domyślnie UnityBootstrapper i MefBoostrapper stworzą TextLogger jako wyznaczonego rejestratora. Istnieją trzy kroki do tworzenia i integrowania niestandardowych rejestratora: Tworzenie klasy, która implementuje interfejs ILoggerFacade. Wdrożenie metody Log. Metoda Log interfejsu ILoggerFacade przyjmuje trzy parametry: Message. To jest wiadomość, która ma być zalogowana. Category. Jest to kategoria przypadku. Poprawne opcje debugowania, wyjątek, info, i ostrzeżenie. Priority . To jest priorytet przypadku. Poprawne opcje to: Brak, Wysoki, Średni, Niski.

Logger // Bootstrapper using Microsoft.Practices.Prism.Logging; ... public class ApplicationBootstrapper : UnityBootstrapper { ... protected override ILoggerFacade CreateLogger() { return new CustomLogger(); } } W swojej aplikacji klasy inicjującego, zastąpić metodę CreateLogger powrotu nową instancję klasy rejestrowania.

Moduł public class FirstModule:IModule { public void Initialize() { throw new NotImplementedException(); } } //1 regionViewRegistry.RegisterViewWithRegion("MainRegion",typeof(Views.FirstModuleView)); //2 IRegionManager.Regions[stirng regionName].Add(view); Czas na implementację modułu, który zostanie dynamicznie wstrzyknięty do regionu w oknie shell. Każdy moduł to zwykle osobna biblioteka dll, która zawiera klasę implementującą interfejs IModule (PRISM), widoki (XAML) oraz inne klasy, zależne już od przyjętego wzorca projektowego (zwykle jest to MVVM) Jedyną wymaganą metodą jest Initliaze. Jak sama nazwa sugeruje, służy ona do inicjalizacji modułu, a konkretnie na podpięcie go do stosownego regionu (placeholder) w shell. Zatem w Initialize powinien zostać umieszczony kod podpinający wszelkie widoki (views) do konkretnych regionów. Warto zaznaczyć, że istnieją dwa sposoby kojarzenia widoków z regionem: View Discovery (odkrywanie widoku) – inaczej podejście niejawne. Za pomocą klasy RegionViewRegistry tworzony jest rejestr skojarzeń pomiędzy widokiem a regionem. W mapowaniach nie należy podawać jednak konkretnych instancji klas, a nazwę regionu i typ widoku – instancje będą utworzone w momencie, gdy zajdzie taka potrzeba (a konkretniej, gdy dany region będzie wyświetlony użytkownikowi). View Injection (wstrzyknięcie widoku) – inaczej podejście jawne. Programista jest odpowiedzialny za znalezienie konkretnej instancji regionu i widoku. Sygnatura metody odpowiedzialnej za wstrzyknięcie widoku przyjmuje więc instancję obiektu jako parametr

Moduły i katalog modułów class PrismBootStrapper : UnityBootstrapper { protected override System.Windows.DependencyObject CreateShell() { return new Shell(); } protected override void InitializeShell() { Application.Current.MainWindow = (Window)Shell; Application.Current.MainWindow.Show(); } protected override IModuleCatalog CreateModuleCatalog() { return new DirectoryModuleCatalog() { ModulePath = @"Modules" }; } } Utworzenie katalogu Katalog w PRISM zawiera moduły. Definiuje się go w bootstrapper, a konkretnie w metodzie CreateModuleCatalog. Programista może zdefiniować katalog samodzielnie, dodając kolejne instancje modułów. Takie rozwiązanie jest poprawne, jednak bardzo nieeleganckie – PRISM został stworzony z myślą o dynamicznie generowanym interfejsie. Lepszym podejściem jest stworzenie katalogu modułów na podstawie folderu Windows, zawierającego biblioteki DLL. PRISM samodzielnie sprawdzi, jakie biblioteki są w danym folderze i je następnie załaduje. Aby osiągnąć podany efekt, wystarczy przeładować metodę CreateModuleCatalog i zwrócić odpowiednią instancję DirectoryModuleCatalog: Inne sposoby: Użyj metody statycznej CreateFromXaml jeśli czerpiesz z xml Modularity:ModuleCatalog Możesz również pójść za przykładem ConfigurationModuleCatalog czerpać z ModuleCatalog nabywać swoje dane, a następnie wywołać metodę AddModule do wypełnienia katalogu.

protected override Microsoft. Practices. Prism. Modularity protected override Microsoft.Practices.Prism.Modularity.IModuleCatalog CreateModuleCatalog() { ConfigurationModuleCatalog catalog = new ConfigurationModuleCatalog(); catalog.Store = new MyModuleCatalogStore(); return catalog; } public class MyModuleCatalogStore : IConfigurationStore { public ModulesConfigurationSection RetrieveModuleConfigurationSection() { ExeConfigurationFileMap fileMap = new ExeConfigurationFileMap() { ExeConfigFilename = "MyModuleCatalog.config" }; Configuration configuration = ConfigurationManager.OpenMappedExeConfiguration(fileMap, ConfigurationUserLevel.None); return configuration.GetSection("modules") as ModulesConfigurationSection; } } Wymienić IConfigurationStore w ConfigurationModuleCatalog. Jeśli używasz aplikacji WPF, można podmienić IConfigurationStore Przykład pokazuje jak załadować customowy plik konfiguracyjny modułu z dysku. Oprócz ModuleCatalog, ModuleManager zapewnia wiele funkcji wirtualnych, które może być zmienione, aby zmienić sposób moduły są załadowane i zainicjowany

Adaptery Regionu ContentControlRegionAdapter – dla kontrolek System.Windows.Controls.ContentControl i pochodnych SelectorRegionAdapter - dla pochodnych klas System.Windows.Controls.Primitives. (np. System.Windows.Controls.TabControl control). ItemsControlRegionAdapter – dla kontrolek typu System.Windows.Controls.ItemsControl i pochodnych

<Window x:Class="WpfApplication1. Shell" xmlns="http://schemas <Window x:Class="WpfApplication1.Shell" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:prism="clr-namespace:Microsoft.Practices.Prism.Regions;assembly=Microsoft.Practices.Prism" Title="Shell" Height="300" Width="300"> <Grid> <StackPanel Orientation="Vertical"> <StackPanel Orientation="Horizontal" prism:RegionManager.RegionName="NavigationRegion" /> <ContentControl prism:RegionManager.RegionName="ContentRegion" /> </StackPanel> </Grid> </Window> W Prism mamy dostępnych kilka adapterów regionów "od ręki" - pozostałe musimy sami stworzyć. W jakich sytuacjach może zajść konieczność stworzenia własnego adaptera regionów? Jeżeli chcemy użyć jakiejś kontrolki jako miejsca w które Prism będzie ładował widoki, a obecnie nie ma takiej obsługi w prosty sposób możemy taką obsługę dodać. Zobaczmy na przykład: wyjątek oznacza iż dana kontrolka nie obsługuje regionów. Tak więc nie pozostaje nam nic innego jak dodać do kontrolki obsługę regionów. Dodanie obsługi danego regionu składa się z 4 kroków:

public class StackPanelRegionAdapter : RegionAdapterBase<StackPanel> { protected override void Adapt(IRegion region, StackPanel regionTarget) { throw new NotImplementedException(); } protected override IRegion CreateRegion() { throw new NotImplementedException(); } } Tworzymy klasę dziedziczącą po RegionAdapterBase<T>

protected override IRegion CreateRegion() { return new AllActiveRegion(); } Implementujemy metodę CreateRegion która zwraca jeden z trzech wyników determinujących zachowania regionu: SingleActiveRegion - jeden aktywny region w danym momencie (ContentControl) AllActiveRegion - wszystkie regiony aktywne (ItemsControls) Region - wiele aktywnych regionów (SelectorControls) Zwracamy informację że wszystkie elementy dodane do naszego StackPanel-a będą domyślne aktywne.

protected override void Adapt(IRegion region, StackPanel regionTarget){ region.Views.CollectionChanged += (s, e) =>{ if (e.Action == NotifyCollectionChangedAction.Add){ foreach (FrameworkElement item in e.NewItems) { regionTarget.Children.Add(item); } } else if (e.Action ==NotifyCollectionChangedAction.Remove){ foreach (FrameworkElement item in e.NewItems) { if (regionTarget.Children.Contains(item)){ regionTarget.Children.Remove(item); } } } }; } Implementacja metody Adapt Tak więc w metodzie tej nasłuchujemy zdarzenia zmiany kolekcji. Na podstawie typu zdarzenia odpowiednio reagujemy w przypadku dodawania nowego elementu - dodajemy go do naszego StackPanel-u za pomocą właściwości Children w przypadku usuwania - usuwamy odpowiedni element ze StackPanel-u

public StackPanelRegionAdapter(IRegionBehaviorFactory regionBehaviorFactory) : base(regionBehaviorFactory) { } Dodanie konstruktora do tworzonej klasy StackPanelRegionAdapter

protected override RegionAdapterMappings ConfigureRegionAdapterMappings() { var mappings = new RegionAdapterMappings(); mappings.RegisterMapping(typeof(StackPanel), Container.Resolve<StackPanelRegionAdapter>()); return mappings; } Tak więc pierwsza część za nami zostało tylko zarejestrowanie naszego adaptera w Bootstrapperze co przedstawia się następująco: Za pomocą metody ConfigureRegionAdapterMappings dodajemy informację o naszym Adapterze StackPanel.

Zachowania Regionów protected override IRegionBehaviorFactory ConfigureDefaultRegionBehaviors() { IRegionBehaviorFactory factory = base.ConfigureDefaultRegionBehaviors(); factory.AddIfMissing("MyBehavior", typeof(MyCustomBehavior)); } http://southworks.com/blog/2009/12/23/memory-leak-removing-view-with-child-regions-in-prism-v2/ Zachowania regionu są wykorzystywane przez Bibliotekę Prism, aby zapewnić większość funkcji dla danego regionu. Podczas procesu ładowania początkowego, inicjującego rejestruje zachowania regionu, które są dołączone do każdego regionu domyślnie. Dodatkowo adaptery mogą dodawać tylko wtedy, gdy zachowanie jest związane z regionem określonego rodzaju kontroli. Gdy MAIN VIEW usunięto z MainRegion regiony RightOne i RightTwo nie zostały usunięte z RegionManager .

Nawigacja protected override string GetContractFromNavigationContext(NavigationContext navigationContext) { string contract = base.GetContractFromNavigationContext(navigationContext); if (contract.Equals("Home", StringComparison.OrdinalIgnoreCase)) { return typeof(HomeView).Name; } if (contract.Equals("About", StringComparison.OrdinalIgnoreCase)) { return typeof(AboutView).Name; } return contract; } Aby zmienić strukturę logiczną nawigacji, dziedziczymy nową klasą po RegionNavigationContentLoader i implementujemy metodę GetContractFromNavigationContext która zwraca nazwę regionu.