2013-07-29 16 views
8

Mój projekt używa pliku ProjectTheme.xaml dla wszystkich okien WPF w całym projekcie. Plik ProjectTheme.xaml odwołuje się do motywu styl następującoWPF Dynamicznie zmieniaj plik zasobu i motyw

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"> 
    <ResourceDictionary.MergedDictionaries> 
     <!-- In order to modify the project's theme, change this line --> 
     <ResourceDictionary Source="/MyProject;component/Themes/WPFThemes/Customized.xaml" /> 
    </ResourceDictionary.MergedDictionaries> 
</ResourceDictionary> 

Wszystko WPF Okna odwołuje WindowBase.xaml

<Window.Resources> 
    <ResourceDictionary> 
     <ResourceDictionary.MergedDictionaries> 
      <ResourceDictionary Source="/MyProject;component/View/WindowBase.xaml"/> 
     </ResourceDictionary.MergedDictionaries> 
    </ResourceDictionary> 
</Window.Resources> 

WindowBase.xaml referencje dostosować pasek tytułowy Bar1.xaml

<ResourceDictionary.MergedDictionaries> 
    <ResourceDictionary Source="/MyProject;component/Themes/WPFThemes/Bar1.xaml" /> 
</ResourceDictionary.MergedDictionaries> 

Bar1 .xaml references ProjectTheme.xaml

<ResourceDictionary.MergedDictionaries> 
    <ResourceDictionary Source="/MyProject;component/ProjectTheme.xaml"/> 
</ResourceDictionary.MergedDictionaries> 

Więc heriarchy jest

  • Window1 odwołuje WindowBase.xaml
  • WindowBase odwołuje Bar1.xaml
  • Bar1 odwołuje ProjectTheme.xaml
  • ProjectTheme.xaml odwoływać plik zasobów prawdziwy motyw.

To działa dobrze. Teraz chcę dynamicznie zmieniać motyw projektu w czasie wykonywania bez zamykania aplikacji. Zakładając, że mam kilka plików w stylu motyw

  • Customized.xaml
  • Customized1.xaml
  • Customized2.xaml

Moje pytanie brzmi jeśli to możliwe, aby dynamicznie aktualizować plik ProjectTheme.xaml w czasie wykonywania, aby zmienić linię z

<ResourceDictionary Source="/MyProject;component/Themes/WPFThemes/Customized.xaml" /> 

do

<ResourceDictionary Source="/MyProject;component/Themes/WPFThemes/Customized1.xaml" /> 

osiągnąć mój cel? Jeśli tak, jak to zrobić? Jeśli nie, jaki jest powód i jaki jest najlepszy (inny) sposób osiągnięcia mojego celu?

Próbowałem następujących czynności, ale żaden z nich nie działa: styl się nie zmienia.

sposób 1

Application.Current.Resources.MergedDictionaries.Clear(); 
Uri NewTheme = new Uri(@"/MyProject;component/Themes/WPFThemes/Customized2.xaml", UriKind.Relative); 
ResourceDictionary dictionary = (ResourceDictionary)Application.LoadComponent(NewTheme); 
Application.Current.Resources.MergedDictionaries.Add(dictionary); 

sposób 2

Application.Current.Resources.MergedDictionaries.RemoveAt(0); 
Uri NewTheme = new Uri(@"/MyProject;component/Themes/WPFThemes/Customized2.xaml", UriKind.Relative); 
ResourceDictionary dictionary = (ResourceDictionary)Application.LoadComponent(NewTheme); 
Application.Current.Resources.MergedDictionaries.Insert(0, dictionary); 

Uwaga: W moich plikach typu prawdziwy motyw (Customized.xaml ...) Kiedyś połączenie dynamicznej zasobów i zasobów statycznych. Czy to ma znaczenie?

Z góry dziękuję.

Odpowiedz

13

Jest kilka rzeczy do rozważenia tutaj.

Po pierwsze, wszystko zdefiniowane za pomocą StaticResource nie zostanie zaktualizowane po zmianie. Jeśli chcesz, aby formant obsługiwał zmianę motywu w czasie wykonywania, musisz użyć DynamicResource, aby wiedział, jak szukać zmian.

Twoje ogólne podejście do zmiany tematu jest poprawne. Najłatwiejszym sposobem osiągnięcia tego jest użycie Application-scoped resource dictionaries, upewniając się, że Twój ResourceDictionary jest zdefiniowany w twoim App.xaml. Aby dodać nowy zasób, użyłem fragmenty podobne do następujących:

ResourceDictionary dict = new ResourceDictionary(); 
dict.Source = new Uri("MyResourceDictionary.xaml", UriKind.Relative); 

Application.Current.Resources.MergedDictionaries.Add(dict); 

Część może być mylące się nad jest przy użyciu zasobów w ramach klas bazowych. Po zdefiniowaniu zasobu w klasie, zasób będzie lokalny dla instancji tego typu. Pomyśl o tym, że XAML wkompilował w swoją własną metodę InitializeComponent() na klasach, co oznacza, że ​​nie można zmienić oryginalnego XAML i oczekiwać, że zmiany pójdą do wszystkich instancji. Na tej samej zasadzie zmiana zasobów instancji klasy nie wpływa na inne instancje.

Ponieważ twoje pytanie naprawdę zawiera dwa osobne zagadnienia (motywy aplikacji i zmieniające zasoby kontrolne), skupiłbym się na zapewnieniu, że twoje zasoby aplikacji są poprawnie aktualizowane i używają DynamicResource, i mam nadzieję, że dostarczone przeze mnie informacje będą wystarczające do zrozumienia, dlaczego niektóre inne zasoby mogą nie być jeszcze aktualizowane.

+0

Will, dzięki za odpowiedź. To wyjaśniało, dlaczego to nie zadziałało. Nie umieściłem zasobu w App.xaml, ponieważ mój projekt jest biblioteką klas zaprojektowaną do wywoływania przez program nie -.net. Czy w takim przypadku możliwa jest dynamiczna zmiana motywu? – Shawn

+0

To powinno być możliwe. Nie próbowałem tego sam, ale eksperymentowałem z definiowaniem statycznego 'ResourceDictionary' w kodzie, zawierającym twoje inne' MergedDictionaries' i próbowałem zmienić to by zobaczyć czy to działa. Sądząc z innych pytań, na które patrzyłem, wygląda na to, że inni mogą sobie z tym poradzić.http: //stackoverflow.com/questions/3038423/creating-static-resource-dictionary –

+0

Czy twoje wyjaśnienie pozwoli mi we właściwym kierunku . Dziękuję bardzo. Doceniam to. – Shawn

Powiązane problemy