Artykuł opisuje w jaki sposób można zmapować przestrzeń nazw CLR na przestrzeń nazw XML, jak wykorzystać takie mapowanie w XAMLu i jakie płyną z tego korzyści.
Pewnie niejedna osoba przy importowaniu w XAMLu jakiejś własnej przestrzeni nazw zastanawiała się, czemu importowanie "naszych" przestrzeni wygląda np. tak:
xmlns:controls="clr-namespace:Softt.Blog.Examples.XmlnsDefinitions.Controls"
a przestrzeni systemowych tak:
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Okazuje się, że stworzone przez nas przestrzenie nazw również mogą być importowane w ten drugi sposób dzięki atrybutowi XmlnsDefinition. W tym artykule opiszę jak to zrobić i jakie płyną z tego korzyści.
Jak to działa?
Importowanie przestrzeni nazw z użyciem dowolnego ciągu znaków (zazwyczaj jest to jakiś URL) różni się od importowania bezpośredniego (czyli clr-namespace:...) dodatkowym etapem, w którym nazwa przestrzeni nazw CLR jest mapowana na nazwę przestrzeni nazw XML. Brzmi to trochę zawile, ale tak naprawdę jest bardzo proste.
Najpierw określamy (właśnie za pomocą atrybutu XmlnsDefinition, przykład za chwilę), jaki ciąg znaków ma odpowiadać jakiejś przestrzeni nazw z naszego kodu, a potem w XAMLu rejestrujemy prefiks wskazujący już na ten ciąg znaków zamiast bezpośrednio na przestrzeń nazw CLR.
Mechanizm ten działa wszędzie tam, gdzie mamy XAMLa, czyli w WPF, Silverlight i oczywiście Silverlight for Windows Phone.
Jakie są korzyści?
Korzyści płynących z takiego rozwiązania jest kilka:
- Łatwiej znaleźć przestrzeń nazw której szukamy na liście wyświetlanej przez IntelliSense, zwłaszcza jeśli nie my tworzyliśmy biblioteki przez co nie znamy dobrze struktury ich przestrzeni nazw.
- Możemy zmapować kilka przestrzeni nazw CLR na jedną przestrzeń nazw XML, dzięki czemu później pod jednym prefixem mamy dostępne klasy z kilku przestrzeni nazw (również z różnych bibliotek).
Najlepiej będzie to widoczne na przykładzie.
Przykład
Załóżmy, że mamy taką solucję:

Jak widać, w trzech różnych miejscach mamy jakieś kontrolki (Control1, Control2 i Control3) oraz dodatkowo konwertery wartości w dwóch miejscach (ValueConverter1 i ValueConverter2).
Teraz załóżmy, że chcemy użyć wszystkich tych kontrolek i konwerterów w jednym pliku XAML. Bez wykorzystania przestrzeni nazw XML i atrybutu XmlnsDefinition musielibyśmy osobno zaimportować trzy przestrzenie nazw i dla każdej określić osobny prefiks, np. tak:
xmlns:c1="clr-namespace:Softt.Blog.Examples.XmlnsDefinitions.Controls"
xmlns:c2="clr-namespace:Softt.Blog.Examples.XmlnsDefinitions.Common.Controls;assembly=Softt.Blog.Examples.XmlnsDefinitions.Common"
xmlns:c3="clr-namespace:Softt.Blog.Examples.XmlnsDefinitions.Controls;assembly=Softt.Blog.Examples.XmlnsDefinitions.Controls"
i analogicznie dla dwóch przestrzeni nazw z konwerterami.
Nie dość, że już samo zaimportowanie tych trzech przestrzeni nazw jest uciążliwe (trzeba je znaleźć na dość długiej liście, w dodatku są one mocno po niej porozrzucane), to jeszcze musimy później pamiętać pod którym prefiksem jest dostępna kontrolka/konwerter którego akurat chcemy użyć lub sprawdzać po kolei metodą prób i błędów.
Jak mogą pomóc przestrzenie nazw XML?
Tak jak pisałem wcześniej, możemy zmapować kilka przestrzeni nazw CLR na jedną przestrzeń XML. Jak to zrobić? Wystarczy w pliku AssemblyInfo.cs projektu, który zawiera interesującą nas przestrzeń nazw CLR, dodać atrybut XmlnsDefinition, za pomocą którego określimy mapowanie przestrzeni nazw CLR na XML.
Załóżmy, że chcemy mieć dostęp do wszystkich trzech kontrolek za pomocą przestrzeni nazw XML o nazwie http://schemas.softt.eu/blog/examples/xmlns-definitions/controls i dodatkowo dostęp do konwerterów poprzez przestrzeń nazw http://schemas.softt.eu/blog/examples/xmlns-definitions/value-converters.
Aby to osiągnąć, wystarczy:
- W pliku AssemblyInfo.cs projektu Softt.Blog.Examples.XmlnsDefinitions dodać atrybuty:
[assembly: XmlnsDefinition("http://schemas.softt.eu/blog/examples/xmlns-definitions/controls", "Softt.Blog.Examples.XmlnsDefinitions.Controls")]
[assembly: XmlnsDefinition("http://schemas.softt.eu/blog/examples/xmlns-definitions/value-converters", "Softt.Blog.Examples.XmlnsDefinitions.ValueConverters")]
- W pliku AssemblyInfo.cs projektu Softt.Blog.Examples.XmlnsDefinitions.Common dodać atrybuty:
[assembly: XmlnsDefinition("http://schemas.softt.eu/blog/examples/xmlns-definitions/controls", "Softt.Blog.Examples.XmlnsDefinitions.Common.Controls")]
[assembly: XmlnsDefinition("http://schemas.softt.eu/blog/examples/xmlns-definitions/value-converters", "Softt.Blog.Examples.XmlnsDefinitions.Common.ValueConverters")]
- W pliku AssemblyInfo.cs projektu Softt.Blog.Examples.XmlnsDefinitions.Controls dodać atrybut:
[assembly: XmlnsDefinition("http://schemas.softt.eu/blog/examples/xmlns-definitions/controls", "Softt.Blog.Examples.XmlnsDefinitions.Controls")]
Po określeniu mapowań możemy teraz w pliku XAML zaimportować nasze nowe przestrzenie nazw XML w następujący sposób:
xmlns:c="http://schemas.softt.eu/blog/examples/xmlns-definitions/controls"
xmlns:vc="http://schemas.softt.eu/blog/examples/xmlns-definitions/value-converters"
Jak widać na poniższym screenie, IntelliSense nie ma problemów z wyświetleniem naszych nowych przestrzeni nazw na liście,

a wszystkie kontrolki

i konwertery nazw

są dostępne pod jednym prefiksem.
Myślę że zgodzicie się ze mną że rozwiązanie to jest zarówno wygodniejsze, jak i zdecydowanie czytelniejsze od bezpośredniego importowania przestrzeni nazw CLR i warto go używać we wszystkich swoich projektach.