Zakresy nazw WPF XAML

Zakresy nazw XAML to pojęcie identyfikujące obiekty zdefiniowane w języku XAML. Nazwy w zakresie nazw XAML mogą służyć do ustanawiania relacji między nazwami obiektów zdefiniowanymi przez XAML a ich odpowiednikami wystąpień w drzewie obiektów. Zazwyczaj nazwy XAML w kodzie zarządzanym WPF są tworzone podczas ładowania poszczególnych katalogów głównych stron XAML dla aplikacji XAML. Nazwy XAML jako obiekt programowania są definiowane przez INameScope interfejs i są również implementowane przez klasę NameScopepraktyczną .

Zakresy nazw w załadowanych aplikacjach XAML

W szerszym kontekście programowania lub informatyki koncepcje programowania często obejmują zasadę unikatowego identyfikatora lub nazwy, która może służyć do uzyskiwania dostępu do obiektu. W przypadku systemów korzystających z identyfikatorów lub nazw zakres nazw definiuje granice, w których jest wyszukiwany proces lub technika, jeśli żądany jest obiekt tej nazwy lub granice, w których wymuszana jest unikatowość nazw identyfikujących. Te ogólne zasady dotyczą zakresów nazw XAML. W WPF nazwy XAML są tworzone w elemendacie głównym strony XAML po załadowaniu strony. Każda nazwa określona na stronie XAML rozpoczynająca się od katalogu głównego strony jest dodawana do odpowiedniego zakresu nazw XAML.

W języku WPF XAML elementy, które są typowymi elementami głównymi (takimi jak Page, i Window), zawsze kontrolują zakres nazw XAML. Jeśli element taki jak FrameworkElement lub FrameworkContentElement jest elementem głównym strony w adiustacji, procesor XAML dodaje Page element główny niejawnie, Page aby zapewnić działający zakres nazw XAML.

Uwaga

Akcje kompilacji WPF tworzą zakres nazw XAML dla środowiska produkcyjnego XAML, nawet jeśli żadne atrybuty lub x:Name nie Name są zdefiniowane na żadnych elementach w znaczników XAML.

Jeśli spróbujesz użyć tej samej nazwy dwa razy w dowolnymscope nazw XAML, zostanie zgłoszony wyjątek. W przypadku języka WPF XAML, który zawiera kod i jest częścią skompilowanej aplikacji, wyjątek jest zgłaszany w czasie kompilacji przez akcje kompilacji WPF podczas tworzenia wygenerowanej klasy dla strony podczas początkowej kompilacji znaczników. W przypadku języka XAML, który nie jest kompilowany przez żadną akcję kompilacji, wyjątki związane z problemami z zakresem nazw XAML mogą być zgłaszane po załadowaniu kodu XAML. Projektanci XAML mogą również przewidywać problemy z zakresem nazw XAML w czasie projektowania.

Dodawanie obiektów do drzew obiektów środowiska uruchomieniowego

Moment, w którym kod XAML jest analizowany, reprezentuje moment w czasie utworzenia i zdefiniowania zakresu nazw XAML WPF. Jeśli dodasz obiekt do drzewa obiektów w określonym momencie po dokonaniu analizy tego drzewa przez kod XAML, wartość Name lub x:Name w nowym obiekcie nie zaktualizuje automatycznie informacji w zakresie nazw XAML. Aby dodać nazwę obiektu do zakresu nazw XAML WPF po załadowaniu kodu XAML, należy wywołać odpowiednią implementację RegisterName obiektu definiującego zakres nazw XAML, który jest zazwyczaj katalogiem głównym strony XAML. Jeśli nazwa nie jest zarejestrowana, dodany obiekt nie może być przywoływany przez nazwę za pomocą metod takich jak FindName, i nie można użyć tej nazwy do określania wartości docelowej animacji.

Najbardziej typowym scenariuszem dla deweloperów aplikacji jest to, że będziesz używać RegisterName do rejestrowania nazw w zakresie nazw XAML w bieżącym katalogu głównym strony. RegisterName jest częścią ważnego scenariusza scenorysów przeznaczonych dla obiektów docelowych animacji. Aby uzyskać więcej informacji, zobacz Storyboards Overview (Omówienie scenorysów).

Jeśli wywołasz RegisterName obiekt inny niż obiekt, który definiuje zakres nazw XAML, nazwa jest nadal zarejestrowana w zakresie nazw XAML, w którym znajduje się obiekt wywołujący, tak jakby został wywołany RegisterName obiekt definiujący xAML.

Zakresy nazw XAML w kodzie

Możesz utworzyć, a następnie użyć nazw XAML w kodzie. Interfejsy API i pojęcia związane z tworzeniem nazw XAML są takie same nawet w przypadku czystego użycia kodu, ponieważ procesor XAML dla WPF używa tych interfejsów API i pojęć podczas przetwarzania samego kodu XAML. Koncepcje i interfejs API istnieją głównie na potrzeby znajdowania obiektów według nazwy w drzewie obiektów, który jest zwykle definiowany częściowo lub całkowicie w języku XAML.

W przypadku aplikacji, które są tworzone programowo, a nie z załadowanego kodu XAML, obiekt definiujący zakres nazw XAML musi implementować INameScopeklasę , lub być klasą pochodną FrameworkElement lub FrameworkContentElement , aby obsługiwać tworzenie zakresu nazw XAML w jego wystąpieniach.

Ponadto w przypadku każdego elementu, który nie jest ładowany i przetwarzany przez procesor XAML, nazwa XAML dla obiektu nie jest tworzona ani inicjowana domyślnie. Należy jawnie utworzyć nowy zakres nazw XAML dla każdego obiektu, do którego zamierzasz zarejestrować nazwy później. Aby utworzyć zakres nazw XAML, należy wywołać metodę statyczną SetNameScope . Określ obiekt, który będzie jego właścicielem dependencyObject jako parametr, oraz nowe NameScope wywołanie konstruktora jako parametru value .

Jeśli obiekt podany jako dependencyObjectSetNameScope nie jest implementacją lub FrameworkElementFrameworkContentElementwywołanie elementu RegisterName podrzędnego INameScope nie będzie miało wpływu na żadne elementy podrzędne. Jeśli nie można jawnie utworzyć nowego zakresu nazw XAML, wywołania metody , aby zgłosić RegisterName wyjątek.

Aby zapoznać się z przykładem używania interfejsów API zakresu nazw XAML w kodzie, zobacz Definiowanie zakresu nazw.

Zakresy nazw XAML w stylach i szablonach

Style i szablony w WPF zapewniają możliwość ponownego użycia i ponownego zastosowania zawartości w prosty sposób. Jednak style i szablony mogą również zawierać elementy z nazwami XAML zdefiniowanymi na poziomie szablonu. Ten sam szablon może być używany wiele razy na stronie. Z tego powodu style i szablony definiują własne zakresy nazw XAML niezależnie od lokalizacji w drzewie obiektów, w której zastosowano styl lub szablon.

Rozważmy następujący przykład:

<Page
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  >
  <Page.Resources>
    <ControlTemplate x:Key="MyButtonTemplate" TargetType="{x:Type Button}">
      <Border BorderBrush="Red" Name="TheBorder" BorderThickness="2">
        <ContentPresenter/>
      </Border>      
    </ControlTemplate>
  </Page.Resources>
  <StackPanel>
    <Button Template="{StaticResource MyButtonTemplate}">My first button</Button>
    <Button Template="{StaticResource MyButtonTemplate}">My second button</Button>
  </StackPanel>
</Page>

W tym miejscu ten sam szablon jest stosowany do dwóch różnych przycisków. Jeśli szablony nie miały dyskretnych nazw XAML, TheBorder nazwa użyta w szablonie spowoduje kolizję nazwy wscope XAML. Każde wystąpienie szablonu ma własny zakres nazw XAML, więc w tym przykładzie każdy wystąpienie szablonu nazwa XAML będzie zawierać dokładnie jedną nazwę.

Style definiują również własny zakres nazw XAML, głównie tak, aby części scenorysów mogły mieć przypisane określone nazwy. Te nazwy umożliwiają kontrolowanie określonych zachowań, które będą dotyczyć elementów tej nazwy, nawet jeśli szablon został ponownie zdefiniowany w ramach dostosowywania kontrolek.

Ze względu na oddzielne zakresy nazw XAML znalezienie nazwanych elementów w szablonie jest trudniejsze niż znalezienie elementu nazwanego bez szablonu na stronie. Najpierw należy określić zastosowany szablon, uzyskując Template wartość właściwości kontrolki, w której jest stosowany szablon. Następnie wywołasz wersję szablonu FindNameelementu , przekazując kontrolkę, w której szablon został zastosowany jako drugi parametr.

Jeśli jesteś autorem kontrolki i generujesz konwencję, w której określony nazwany element w zastosowanym szablonie jest obiektem docelowym zachowania zdefiniowanego przez samą kontrolkę, możesz użyć GetTemplateChild metody z kodu implementacji kontrolki. Metoda jest chroniona GetTemplateChild , więc tylko autor kontrolki ma do niej dostęp.

Jeśli pracujesz z poziomu szablonu i musisz przejść do zakresu nazw XAML, w którym jest stosowany szablon, pobierz wartość TemplatedParent, a następnie wywołaj FindName go. Przykładem pracy w szablonie byłoby napisanie implementacji programu obsługi zdarzeń, w której zdarzenie zostanie zgłoszone z elementu w zastosowanym szablonie.

FrameworkElement ma FindNamemetody , RegisterName i UnregisterName . Jeśli obiekt, który wywołujesz te metody, jest właścicielem zakresu nazw XAML, metody są wywoływane do metod odpowiedniego zakresu nazw XAML. W przeciwnym razie element nadrzędny jest sprawdzany, aby sprawdzić, czy jest właścicielem zakresu nazw XAML, a ten proces jest powtarzany rekursywnie, dopóki nie zostanie znaleziony zakres nazw XAML (ze względu na zachowanie procesora XAML, nie ma gwarancji, że jest to zakres nazw XAML w katalogu głównym). FrameworkContentElement ma podobne zachowania, z wyjątkiem, że nigdy nie FrameworkContentElement będzie właścicielem nazwy XAML. Metody istnieją w taki FrameworkContentElement sposób, aby wywołania mogły zostać ostatecznie przekazane do elementu nadrzędnego FrameworkElement .

SetNameScope służy do mapowania nowego zakresu nazw XAML na istniejący obiekt. Możesz wywołać SetNameScope więcej niż raz, aby zresetować lub wyczyścić zakres nazw XAML, ale nie jest to typowe użycie. GetNameScope Ponadto nie jest zwykle używany z kodu.

Implementacje zakresu nazw XAML

Następujące klasy implementują INameScope bezpośrednio:

ResourceDictionary nie używa nazw XAML ani nazw; używa kluczy, ponieważ jest to implementacja słownika. Jedyną przyczyną implementacji ResourceDictionaryINameScope jest możliwość zgłaszania wyjątków od kodu użytkownika, które pomagają wyjaśnić rozróżnienie między prawdziwym zakresem ResourceDictionary nazw XAML i sposobem obsługi kluczy, a także w celu zapewnienia, że zakresy nazw XAML nie są stosowane do ResourceDictionary elementów nadrzędnych.

FrameworkTemplate i Style implementować INameScope za pomocą jawnych definicji interfejsu. Jawne implementacje umożliwiają zachowanie tych zakresów nazw XAML w sposób konwencjonalny w przypadku uzyskiwania do nich dostępu za pośrednictwem interfejsu INameScope , co jest sposobem przekazywania nazw XAML przez procesy wewnętrzne WPF. Jednak jawne definicje interfejsu nie są częścią konwencjonalnej powierzchni interfejsu FrameworkTemplate API i Style, ponieważ rzadko trzeba wywoływać INameScope metody bezpośrednio FrameworkTemplate i Style bezpośrednio, a zamiast tego używać innego interfejsu API, takiego jak GetTemplateChild.

Następujące klasy definiują własny zakres nazw XAML, używając klasy pomocniczej System.Windows.NameScope i łącząc się z implementacją zakresu nazw XAML za pośrednictwem dołączonej NameScope.NameScope właściwości:

Zobacz też