Hallo Community!
Gibt es eine Möglichkeit, Änderungen an geerbte Styles durchzureichen?
Mein Style ist wie folgt definiert:
<TextBox Height="23" HorizontalAlignment="Left" Margin="12,12,0,0" Name="textBox1" VerticalAlignment="Top" Width="120">
<TextBox.Style>
<Style TargetType="{x:Type TextBox}" BasedOn="{StaticResource {x:Type TextBox}}">
<Setter Property="Text" Value="Subtemplate" />
</Style>
</TextBox.Style>
</TextBox>
Mein Problem ist nun, dass wenn der Style im Application.Resources Dictionary geändert wird, werden die Änderungen leider nicht an den geerbten Style durchgereicht. Gibt es eine andere Möglichkeit, einen Style zu vererben, so das auch dynamische Änderungen durchgereicht werden?
Auf Wunsch kann ich auch ein kurzes Beispielprogramm anhängen, welches das Problem darstellt.
Mit freundlichen Grüßen
Felix
Mit freundlichen Grüßen
Felix
Meinst du evtl. {DynamicResource ...} ?
Ansich die richtige Idee. Habe es auch probiert. Leider ist DynamicResource bei der BasedOn Property nicht zulässig, da diese keine DependencyProperty ist. Selbst wenn man versucht, diese per CodeBehind zu verändert, kommt ein Fehler. Die Style-Klasse ist ISealable, und wird nach der ersten Verwendung versiegelt...
Mit freundlichen Grüßen
Felix
Falls jemand an der Lösung des Problems interessiert ist, habe ich hier nun eine 😉
Das ganze ist etwas trickreich zu behandeln, da Styles nach der ersten Verwendung versiegelt werden. Ich habe mir ein angepasstes ResourceDictionary sowie einen angpassten Style erstellt. Verwendet wird das ganze so:
<ResourceDictionary.MergedDictionaries>
<Themes:MonitoredResourceDictionary>
<!-- Stylefür MyTabItem-->
<Themes:DynamicStyle BaseType="{x:Type TabItem}" TargetType="{x:Type self:MyTabItem}">
<Setter Property="self:MyTabItem.Foreground" Value="Red" />
</Themes:DynamicStyle>
</Themes:MonitoredResourceDictionary>
</ResourceDictionary.MergedDictionaries>
DynamicStyle.cs
public class DynamicStyle : Style
{
/// <summary>
/// Basis-Type (Wie BasedOn, nur als Type und nicht als Style)
/// </summary>
private Type baseType;
/// <summary>
/// Basis-Type (Wie BasedOn, nur als Type und nicht als Style)
/// </summary>
public Type BaseType
{
get
{
// Rückgabe
return this.baseType;
}
set
{
// Setzen des BasedOn Styles
this.BasedOn = (Style)Application.Current.FindResource(value);
// BaseType sichern
this.baseType = value;
}
}
/// <summary>
/// Erstellt ein neues DynamicStyle-Objekt
/// </summary>
public DynamicStyle()
{
}
}
MonitoredResourceDictionary.cs
/// <summary>
/// MonitoredResourceDictionary
/// </summary>
public class MonitoredResourceDictionary : ResourceDictionary
{
/// <summary>
/// Hilfsvariable für das Monitoring
/// </summary>
private static bool applicationIsMonitored = false;
/// <summary>
/// Liste aller MonitoredResourceDictionary's
/// </summary>
private static List<WeakReference> Dicts = new List<WeakReference>();
/// <summary>
/// Update aller MonitoredResourceDictionary's
/// </summary>
private static void UpdateResources()
{
// Durchlaufe alle Dictionarys
foreach (WeakReference wr in Dicts)
{
// DynamicStyles in dem Dictionary erneuern
if (wr.IsAlive)
{
MonitoredResourceDictionary mrd = (MonitoredResourceDictionary)wr.Target;
// Wenn das Dictionary bereits geupdated wird, überspringe dieses
if (mrd.IsInUpdate)
continue;
// Update auf ja setzen
mrd.IsInUpdate = true;
// Updaten
((MonitoredResourceDictionary)wr.Target).RecreateDynamicStyles();
// Update auf nein setzen
mrd.IsInUpdate = false;
}
}
}
/// <summary>
/// Gibt an, ob das MonitoredResourceDictionary gerade geupdated wird
/// </summary>
private bool IsInUpdate { get; set; }
/// <summary>
/// Erneuert alle vorhandenen DynamicStyles
/// </summary>
private void RecreateDynamicStyles()
{
// Durchlaufe alle Einträge
foreach (object key in this.Keys.Cast<object>().ToArray())
{
// Item Holen
object o = this[key];
// Wenn das Item vom Type DynamicStyle ist
if (o.GetType() == typeof(DynamicStyle))
{
// Alter Style
DynamicStyle oldStyle = (DynamicStyle) o;
// Neuer Style
DynamicStyle newStyle = new DynamicStyle();
// Eigenschaften übernehmen
newStyle.TargetType = oldStyle.TargetType;
newStyle.BaseType = oldStyle.BaseType;
// Setter übernehmen
foreach (SetterBase sb in oldStyle.Setters)
newStyle.Setters.Add(sb);
// Trigger übernehmen
foreach (TriggerBase tb in oldStyle.Triggers)
newStyle.Triggers.Add(tb);
// Entferne den alten Style
this.Remove(key);
// Füge den neuen Style ein
this.Add(key, newStyle);
}
}
}
/// <summary>
/// Erstellt ein neues MonitoredResourceDictionary Objekt
/// </summary>
public MonitoredResourceDictionary()
{
// Inizialisierung
this.IsInUpdate = false;
// Wenn dem Application-Objekt noch kein StartUP-Event zugewiesenw urde
if (!applicationIsMonitored)
{
// Variable setzen
applicationIsMonitored = true;
// Startup Event zuweisen
Application.Current.Startup += (sender, e) =>
{
// Hole das INotifyCollectionChanged für die MergedDictionarys
INotifyCollectionChanged l = Application.Current.Resources.MergedDictionaries as INotifyCollectionChanged;
// Überwache diese
l.CollectionChanged += (sender2, e2) =>
{
// Löse die erneuerung der MonitoredResourceDictionary aus
MonitoredResourceDictionary.UpdateResources();
};
};
}
// Dieses Dictionary für spätere Updates in der Liste sichern
Dicts.Add(new WeakReference(this));
}
}
Das MonitoredResourceDictionary bekommt nun die Änderungen von Ressourcen mit und kann daraufhin die DynamicStyles neu erstellen. Danach wird einfach der alte DynamicStyle gegen den neuen ausgetauscht. Wichtig ist, dass die DynamicStyles sich in einem MonitoredResourceDictionary befinden, damit diese bei einer Resourcenänderung gefunden und ausgetauscht werden können.
Mit freundlichen Grüßen
Felix
Warum erstellst du nicht zwei verschiedene Styles und wechselt dieses dann per Trigger oder DataBinding oder whatever?
Lg XXX
//Edit: Ich hab zu dem Zweck eine Klasse Namens "MergedStyle" gebastelt, welcher man Teile eines Styles auslagern kann um sie mehrmals wiederzuverwenden.
Unterstützt deine Klasse denn DynamicResources?
Beispiel:
<Utilities:StyleWrapper Style="{DynamicResource {x:Type ListBoxItem}}" />
Das geht bei dir? Und die Resource wird auch geupdatet, wenn ich ein anderes Theme dynamisch in der Laufzeit lade?
Mit freundlichen Grüßen
Felix
Puh, also dynamicResource sollt denke ich auf jedenfall gehen. Wie und was du dynamisch zur Laufzeit erst laden willst und ob das funktioniert weiß ich nicht. Aber prinzipiell meinte ich ja eher weg von der "Dynamic" und hin zu einem flexiblen aber doch fest verdrahtetem System indem du halt den Style mehrmals definierst und die Sachen die doppelt vorkommen in einen gemeinsamen Style auslagern kannst. Dann kannst du je nach Bedingung einmal den einen oder einen anderen Style binden(die aber beide schon von Anfang an existieren).
Aber du hast ja schon eine Lösung für dein Problem gefunden. Wollt nur evt. eine alternative aufzeigen.
Lg XXX