Rachel, nie sądzę, nie ma nic szczególnego do „Style”. Co więcej, nie ma problemu "przekraczania granic szablonów". Powód tego jest inny i przechodzi do różnych "drzew" w aplikacji WPF. Poprzez swoje pytanie ja recon jesteś wyobrażając sobie świat z następującą hierarchią:
- Zastosowanie => => Okno kontrolne => Elementy będące pod kontrolą
Nie ma takiej hierarchii. W aplikacji WPF znajdują się różne drzewa, najbardziej znane to Drzewo logiczne i Drzewo wizualne, ale jest ich więcej (drzewo zdarzeń routingu, a także drzewo odnośników zasobów, z nieco inną semantyką).
Przyjmijmy następujące XAML:
<Window x:Class="SO.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<Grid>
<Button x:Name="btn" Click="click">Click Me</Button>
</Grid>
</Window>
dla tej XAML, logicznym drzewo będzie wyglądać następująco:
- Window => Siatka => Przycisk => String
TextBlock wewnątrz przycisku jest nie jest częścią logicznego drzewa (jest to jednak część VisualTree).
Wyszukiwanie zasobów odbywa się według LogicalTree, z jedną różnicą. Po dotarciu do obiektu najwyższego, algorytm zasobów odnajdywania będzie przeglądać słownik zasobów Aplikacja, a następnie w schemacie zasobów zasobu , a następnie w słowniku zasobów System w tej kolejności.
patrz poniższe artykuły:
Finnaly, aby udowodnić swój punkt , dodaj następujący zasób do aplikacji XAML:
<Application x:Class="SO.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:clr="clr-namespace:System;assembly=mscorlib"
StartupUri="MainWindow.xaml">
<Application.Resources>
<clr:String x:Key="MyResource">Hello Application Resource</clr:String>
</Application.Resources>
</Application>
i następujący kod za:
private void click(object sender, RoutedEventArgs e)
{
// Logical Children of btn
Debug.WriteLine("Children of btn:");
foreach(var x in LogicalTreeHelper.GetChildren(btn)) {
Debug.WriteLine("{0} : {1}", x, x.GetType());
}
// Walk the visual tree
Debug.WriteLine("The Visual Tree:");
WalkVisual(0, this);
// Find the textblock within the button
DependencyObject p = btn;
while (p.GetType() != typeof(TextBlock))
p = VisualTreeHelper.GetChild(p, 0);
TextBlock tb = p as TextBlock;
// Now climp the textblock through the logical tree
while (p != null)
{
Debug.WriteLine("{0}", p.GetType());
p = LogicalTreeHelper.GetParent(p);
}
// Find a resource for the textbox
string s = tb.FindResource("MyResource") as string;
Debug.WriteLine("MyResource Content: {0}", s);
}
private void WalkVisual(int indent, DependencyObject p)
{
string fmt = string.Format("{{0,{0}}}{{1}}", indent * 4);
Debug.WriteLine(fmt, "", p.GetType());
for (int i = 0; i < VisualTreeHelper.GetChildrenCount(p); ++i)
{
WalkVisual(indent+1,VisualTreeHelper.GetChild(p, i));
}
}
Więc ... po zrozumieniu pierwsze pytanie („dlaczego tak jest”), pozostałe pytania rozpadnie. Różnica między zasobami aplikacji i zasobami okna polega na tym, że zasoby aplikacji mogą być gromadzone za pomocą dowolnego obiektu DependencyObject w aplikacji, również tych zdefiniowanych w innych złożeniach. Użyjesz go, gdy chcesz tego osiągnąć :-)
u.
Dobre pytanie i wgląd na temat, w jaki sposób niejawne style App.xaml przekraczają granice ControlTemplate. Z tego powodu importuję/łączę niektóre słowniki zasobów do * każdego * moich okien aplikacji (tak naprawdę właśnie importuję pojedynczy plik master rd). Czy znalazłeś lepszy sposób radzenia sobie z tym problemem, niż jak to robię? (Byłoby ładniej, gdybyśmy mogli po prostu zaimportować go jednorazowo - tak jak robimy to z importowanymi zasobami App.xaml.) –
Ten problem z przekroczeniem granicy ControlTemplate jest szczególnie kłopotliwy w przypadkach takich jak domniemany (App.xaml-level) Styl TextBlock, w którym TextBlock zostaje automatycznie wygenerowany jako element podrzędny elementu ContentPresenter formantu. Używanie sztuczki na poziomie okna, o której wspomina Rachel, rozwiązało dla mnie ten problem. –
@Jason Zazwyczaj moje aplikacje WPF mają tylko jedno okno, a zawartość zmienia się w razie potrzeby. Nie sądzę, żebym kiedykolwiek zrobił coś więcej niż dwa okna (logowanie i aplikacja). Powiedział, że prawdopodobnie można użyć MEF do importowania/eksportowania słowników zasobów, jak wyjaśniono [tutaj] (http://stackoverflow.com/q/842571/302677) – Rachel