Laden...

Styles - BaseOn - Dynamische Änderungen zur Laufzeit

Erstellt von EgoFelix vor 13 Jahren Letzter Beitrag vor 13 Jahren 4.217 Views
E
EgoFelix Themenstarter:in
38 Beiträge seit 2009
vor 13 Jahren
Styles - BaseOn - Dynamische Änderungen zur Laufzeit

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

E
EgoFelix Themenstarter:in
38 Beiträge seit 2009
vor 13 Jahren

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

E
EgoFelix Themenstarter:in
38 Beiträge seit 2009
vor 13 Jahren
Lösung

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

1.378 Beiträge seit 2006
vor 13 Jahren

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.

E
EgoFelix Themenstarter:in
38 Beiträge seit 2009
vor 13 Jahren

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

1.378 Beiträge seit 2006
vor 13 Jahren

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