Styles zur Laufzeit nachladen greift nicht



  • Hallo,

    frohes Neues zunächst mal euch allen 🙂

    Ich habe ein UserControl <Label> programmiert, welches aus zwei <TextBlock> besteht (Name und Wert, ganz simpel). Die XAML Datei sieht wie folgt aus:

    <UserControl x:Class="DotNet.WpfControls.Base.Label"
                 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                 xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
                 xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
                 xmlns:local="clr-namespace:DotNet.WpfControls.Base"
                 mc:Ignorable="d">
    
    	<UserControl.Resources>
    		<ResourceDictionary>
    			<ResourceDictionary.MergedDictionaries>
    				<ResourceDictionary Source="Resources/Styles/DefaultStyles.xaml"/>
    				<ResourceDictionary Source="Resources/Styles/Label.xaml"/>
    			</ResourceDictionary.MergedDictionaries>
    		</ResourceDictionary>
    	</UserControl.Resources>
    
    	<Grid>
    		<Grid.ColumnDefinitions>
    			<ColumnDefinition Name="LabelColumn" />
    			<ColumnDefinition />
    		</Grid.ColumnDefinitions>
    		<Grid.RowDefinitions>
    			<RowDefinition />
    		</Grid.RowDefinitions>
    
    		<TextBlock Grid.Column="0" Grid.Row="0" Margin="4, 2, 4, 2" Name="InternalName" Style="{StaticResource LabelName}" Text="Name" />
    		<TextBlock Grid.Column="1" Grid.Row="0" Margin="4, 2, 4, 2" Name="InternalValue" Style="{StaticResource LabelValue}" Text="Value" />
    	</Grid>
    
    </UserControl>
    

    In der oberen Hälfte referenziere ich zwei <ResourceDictionary>, diese sehen wie folgt aus:

    <ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    
    	<!-- Default TextBlock -->
    	<Style x:Key="DefaultTextBlock" TargetType="TextBlock">
    		<Setter Property="TextWrapping" Value="NoWrap" />
    		<Setter Property="TextTrimming" Value="None" />
    	</Style>
    
    </ResourceDictionary>
    
    <ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    
    	<ResourceDictionary.MergedDictionaries>
    		<ResourceDictionary Source="DefaultStyles.xaml" />
    	</ResourceDictionary.MergedDictionaries>
    
    	<!-- Style for the name text block -->
    	<Style BasedOn="{StaticResource DefaultTextBlock}" x:Key="LabelName" TargetType="TextBlock">
    		<Setter Property="TextDecorations" Value="{x:Null}" />
    		<Style.Triggers>
    			<Trigger Property="IsMouseOver" Value="True">
    				<Setter Property="TextDecorations" Value="Underline" />
    			</Trigger>
    		</Style.Triggers>
    	</Style>
    
    	<!-- Style for the value text block -->
    	<Style BasedOn="{StaticResource DefaultTextBlock}" x:Key="LabelValue" TargetType="TextBlock">
    	</Style>
    
    </ResourceDictionary>
    

    Wenn ich das Programm aus VisualStudio heraus starte, sieht alles gut aus und es funktioniert auch alles. Nun möchte ich aber die <Styles> in der <Auslieferungsversion> im Verzeichnis <.\resources\styles*.xaml> ablegen, damit der Anwender meines Programms die Möglichkeit hat, die Stile individuell anzupassen.

    In der App.cs lade ich wie folgt:

    private void LoadStyles()
    {
    	var currentDirectory = Environment.CurrentDirectory;
    	var styles = new List<string>()
    	{
    		"DefaultStyles.xaml",
    		"Label.xaml"
    	};
    
    	foreach (var item in styles)
    	{
    		var pathName = Path.Combine(currentDirectory, ResourcesPathName, StylesPathName, item);
    		var resourceDictionary = new ResourceDictionary
    		{
    			Source = new Uri(pathName)
    		};
    
    		this.Resources.MergedDictionaries.Add(resourceDictionary);
    	}
    }
    

    Das Laden ansich führt zu keinem Laufzeitfehler, die Dateien werden gefunden und geladen. Wenn ich aber die Datei <DefaultStyles.xaml> anpasse und z.B. die Vordergrundfarbe für das <TextBlock> setze, greift diese Änderung nicht:

    <ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    
    	<!-- Default TextBlock -->
    	<Style x:Key="DefaultTextBlock" TargetType="TextBlock">
    		<Setter Property="Foreground" Value="Red" />
    		<Setter Property="TextWrapping" Value="NoWrap" />
    		<Setter Property="TextTrimming" Value="None" />
    	</Style>
    
    </ResourceDictionary>
    

    Weiß jemand, was ich wo falsch mache?

    Vielen Dank im Voraus

    VG Torsten



  • Das wird m.E. daran liegen, daß die beiden Ressourcen schon im MergedDictionaries vorhanden sind (und per Add fügst du diese ja hinten dran).
    Entweder versuchen diese zu ersetzen bzw. vorne hinzuzufügen.

    Außerdem:
    Wenn LoadStyles eine Methode deiner App-Klasse (und nicht der Label-Klasse) ist, so bezieht sich this.Resources auf die Ressourcen der App und nicht der Label-Instanz, s.a. ResourceDictionary:

    Verwendung von ResourceDictionary-Elementen

    Der ResourceDictionary-Typ wird als Wert der beiden Eigenschaften FrameworkElement.Resources und Application.Resources verwendet.



  • Hallo,

    gute Hinweise, danke. Ich schaue mir das mal an.

    VG Torsten



  • N' Abend,

    nun habe ich es geschafft, das Problem ist vermutlich zweierlei.

    Erstens, einige Zeilen auskommentieren:

    <UserControl x:Class="DotNet.WpfControls.Base.Label"
                 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                 xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
                 xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
                 xmlns:local="clr-namespace:DotNet.WpfControls.Base"
                 mc:Ignorable="d">
    
    	<!--<UserControl.Resources>
    		<ResourceDictionary>
    			<ResourceDictionary.MergedDictionaries>
    				<ResourceDictionary Source="Resources/Styles/DefaultStyles.xaml"/>
    				<ResourceDictionary Source="Resources/Styles/Label.xaml"/>
    			</ResourceDictionary.MergedDictionaries>
    		</ResourceDictionary>
    	</UserControl.Resources>-->
    
    	<Grid>
    		<Grid.ColumnDefinitions>
    			<ColumnDefinition Name="LabelColumn" />
    			<ColumnDefinition />
    		</Grid.ColumnDefinitions>
    		<Grid.RowDefinitions>
    			<RowDefinition />
    		</Grid.RowDefinitions>
    
    		<TextBlock Grid.Column="0" Grid.Row="0" Margin="4, 2, 4, 2" Name="InternalName" Style="{DynamicResource LabelName}" Text="Name" />
    		<TextBlock Grid.Column="1" Grid.Row="0" Margin="4, 2, 4, 2" Name="InternalValue" Style="{DynamicResource LabelValue}" Text="Value" />
    	</Grid>
    </UserControl>
    
    

    Zweitens, die Lademethode leicht anpassen:

    private void LoadStyles()
    {
    	var currentDirectory = Environment.CurrentDirectory;
    	var styles = new List<string>()
    	{
    		"DefaultStyles.xaml",
    		"Label.xaml"
    	};
    
    	App.Current.Resources.Clear();
    
    	foreach (var item in styles)
    	{
    		var pathName = Path.Combine(currentDirectory, ResourcesPathName, StylesPathName, item);
    		var resourceDictionary = new ResourceDictionary
    		{
    			Source = new Uri(pathName)
    		};
    
    		App.Current.Resources.MergedDictionaries.Add(resourceDictionary);
    	}
    }
    

    Und man muss <DynamicResource> anstatt von <StaticResource> verwenden.

    VG Torsten


Anmelden zum Antworten