2009-04-24 4 views
6

J'essaie de rendre mon application plus personnalisable en permettant aux utilisateurs de choisir une couleur dans une boîte de dialogue Color Picker, puis de changer le style de l'application en temps réel (avec DynamicResource)WPF: Modification des ressources (couleurs) à partir de App.xaml pendant l'exécution

Comment faire pour changer des ressources spécifiques qui résident dans le app.xaml?


J'ai essayé quelque chose comme ça, mais pas de chance (juste un 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)); 

Cet un extrait du fichier app.xaml:

<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> 

Quel est le meilleur façon d'autoriser cette forme de personnalisation (en changeant simplement certaines couleurs) à une application?


[Mise à jour]

Je viens de découvrir this answer d'une question précédente qui a été posée, et essayé mais je reçois le même InvalidOperationException exception Petoj mentionné dans les commentaires de la donnée répondre. Voici l'exemple de code de la réponse:

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; 

Répondre

13

On dirait que vous essayez de faire une sorte de skinning?

Je vous recommande de définir les ressources dans un dictionnaire de ressources contenu dans un fichier distinct. Ensuite, dans le code (App.cs pour charger un défaut, puis ailleurs à changer), vous pouvez charger les ressources comme si:

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

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

Vous pouvez également définir le dictionnaire de ressources par défaut dans App.xaml et décharger dans le code juste bien.

Utilisez l'objet MergedDictionaries pour modifier le dictionnaire que vous utilisez lors de l'exécution. Fonctionne comme un charme pour changer toute une interface rapidement.

1

Vous obtenez une exception parce que vous essayez de modifier un objet congelé. Toutes les ressources au niveau de l'application sont automatiquement gelées si elles sont gelables et que LinearGradientBrush l'est. Si vous l'ajoutez à un niveau inférieur comme le niveau de la fenêtre, cela fonctionnera.

+0

Mais je ne peux pas l'ajouter dans une fenêtre parce que ce style s'applique à toutes les fenêtres de mon projet –

6

Changer une large application dans les ressources d'exécution est comme:

Application.Current.Resources("MainBackgroundBrush") = Brsh 

A propos du InvalidOperationException, je suppose que WallStreet programmeur est juste. Peut-être que vous ne devriez pas essayer de modifier un pinceau existant, mais plutôt créer un nouveau pinceau dans le code avec tous les gradientstops dont vous avez besoin, puis affecter ce nouveau pinceau dans les ressources de l'application.

Une autre approche sur le changement de couleur de certains GradientStops est de définir les couleurs comme références DynamicResource à une large application SolidColorBrushes comme:

<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> 

puis utilisez

Application.Current.Resources["FirstColor"] = NewFirstColorBrsh 
Application.Current.Resources["SecondColor"] = NewSecondColorBrsh 

HTH

+0

C'est exactement ce que je voulais. –

+0

Notez que cela ne fonctionne pas dans Silverlight. 'DynamicResource' n'est pas supporté. – mbomb007

2

Utilisez le Clone() méthode pour faire une copie en profondeur de la brosse (ou tout autre objet freezable comme Storyboard), puis l'utiliser:

LinearGradientBrush myBrush = FindResource("MainBrush") as LinearGradientBrush; 
myBrush = myBrush.Clone(); 
myBrush.GradientStops[0].Color = Colors.Red; 

@WallstreetProgrammer est juste - toutes les ressources de niveau d'application sont gelés par défaut.

C'est pourquoi vous devez d'abord cloner l'objet.

Questions connexes