WPF:Ändern von Ressourcen (Farben) aus der App.xaml während der Laufzeit
-
16-09-2019 - |
Frage
Ich versuche, meine Anwendung anpassbarer zu gestalten, indem ich Benutzern erlaube, eine Farbe aus einem Farbauswahldialog auszuwählen und dann den Stil der Anwendung in Echtzeit zu ändern (mit DynamicResource
)
Wie gehe ich vor, wenn ich bestimmte Ressourcen ändere, die sich in der befinden? app.xaml
?
Ich habe so etwas versucht, aber kein Glück (nur ein Test):
var colorDialog = new CustomControls.ColorPickerDialog();
var dResult = colorDialog.ShowDialog();
var x = Application.Current.Resources.Values.OfType<LinearGradientBrush>().First();
x = new LinearGradientBrush();
x.GradientStops.Add(new GradientStop(colorDialog.SelectedColor,1));
Dies ist ein Auszug aus dem app.xaml
Datei:
<Application.Resources>
<LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0" x:Key="HeaderBackground">
<GradientStop Color="#82cb02" Offset="1"/>
<GradientStop Color="#82cb01" Offset="0.2"/>
<GradientStop Color="#629a01" Offset="0.5"/>
</LinearGradientBrush>
Was ist der beste Weg, diese Form der Anpassbarkeit (im Grunde nur das Ändern einiger Farben) für eine Anwendung zu ermöglichen?
[Aktualisieren]
Ich habe gerade gefunden diese Antwort aus einer früheren Frage, die gestellt wurde, und habe es versucht, aber ich bekomme das Gleiche InvalidOperationException Ausnahme, die Petoj in den Kommentaren für die gegebene Antwort erwähnt hat.Hier ist der Beispielcode aus der Antwort:
Xaml:
<LinearGradientBrush x:Key="MainBrush" StartPoint="0, 0.5" EndPoint="1, 0.5" >
<GradientBrush.GradientStops>
<GradientStop Color="Blue" Offset="0" />
<GradientStop Color="Black" Offset="1" />
</GradientBrush.GradientStops>
</LinearGradientBrush>
C#:
LinearGradientBrush myBrush = FindResource("MainBrush") as LinearGradientBrush;
myBrush.GradientStops[0].Color = Colors.Red;
Lösung
Es sieht aus wie Sie versuchen, irgendeine Art von Häuten zu tun?
Ich würde empfehlen, die Ressourcen in einem Ressourcenverzeichnis in einer separaten Datei enthalten definieren. Dann im Code (App.cs einen Standard zu laden, dann an anderer Stelle zu ändern), um die Ressourcen so laden kann:
//using System.Windows
ResourceDictionary dict = new ResourceDictionary();
dict.Source = new Uri("MyResourceDictionary.xaml", UriKind.Relative);
Application.Current.Resources.MergedDictionaries.Add(dict);
Sie können auch den Standard-Ressource-Wörterbuch in App.xaml definieren und in Code entladen gut.
Mit dem MergedDictionaries Objekt das Wörterbuch zu ändern, die Sie zur Laufzeit verwenden. Funktioniert wie ein Zauber schnell eine ganze Schnittstelle zu ändern.
Andere Tipps
Das Ändern anwendungsweiter Ressourcen zur Laufzeit sieht folgendermaßen aus:
Application.Current.Resources("MainBackgroundBrush") = Brsh
Was die InvalidOperationException betrifft, denke ich, dass WallStreet Programmer Recht hat.Vielleicht sollten Sie nicht versuchen, einen vorhandenen Pinsel zu ändern, sondern stattdessen im Code einen neuen Pinsel mit allen benötigten Verlaufsstopps erstellen und diesen neuen Pinsel dann in den Anwendungsressourcen zuweisen.
Ein anderer Ansatz zum Ändern der Farbe einiger GradientStops besteht darin, diese Farben als DynamicResource-Referenzen auf anwendungsweite SolidColorBrushes zu definieren, wie zum Beispiel:
<LinearGradientBrush x:Key="MainBrush" StartPoint="0, 0.5" EndPoint="1, 0.5" >
<GradientBrush.GradientStops>
<GradientStop Color="{DynamicResource FirstColor}" Offset="0" />
<GradientStop Color="{DynamicResource SecondColor}" Offset="1" />
</GradientBrush.GradientStops>
und dann verwenden
Application.Current.Resources["FirstColor"] = NewFirstColorBrsh
Application.Current.Resources["SecondColor"] = NewSecondColorBrsh
HTH
Mit der Clone()
Methode eine tiefe Kopie der Bürste machen (oder jede anderen freezable Objekte wie Storyboard
) und dann verwenden:
LinearGradientBrush myBrush = FindResource("MainBrush") as LinearGradientBrush;
myBrush = myBrush.Clone();
myBrush.GradientStops[0].Color = Colors.Red;
@WallstreetProgrammer ist richtig - alle Anwendungsebene Ressourcen standardmäßig eingefroren werden
.Das ist, warum Sie müssen zuerst das Objekt klonen.
Sie erhalten eine Ausnahme, weil Sie ein gefrorenes Objekt zu ändern versuchen. Alle Anwendungsebene Ressourcen werden automatisch eingefroren, wenn sie freezable sind und LinearGradientBrush ist. Wenn Sie es auf einem niedrigeren Niveau wie Fensterebene hinzufügen wird es funktionieren.