2009-10-03 9 views
4

Je veux être en mesure d'avoir un gradient dynamique dans Silverlight, comme ci-dessous:Comment lier les couleurs GradientStop ou la propriété GradientStops dans Silverlight?

<RadialGradientBrush GradientOrigin="0.20,0.5" Center="0.25,0.50" 
        RadiusX="0.75" RadiusY="0.5"> 
    <GradientStop Color="{Binding Path=GradientStart}" Offset="0" /> 
    <GradientStop Color="{Binding Path=GradientEnd}" Offset="1" /> 
</RadialGradientBrush> 

Je lient à deux propriétés qui renvoient le type « couleur » mais je reçois toujours ce message:

AG_E_PARSER_BAD_PROPERTY_VALUE 

Si je tente de se lier à une collection GradientStop ce qui a le même problème, quelle est la solution à ce problème:

  1. Permet le début et la fin d'un G radient à modifier lors de l'exécution
  2. Works dans Silverlight 3.0 et n'est pas une solution WPF

S'il y a un travail autour ou de toute façon de reproduire ce comportement ce serait acceptable, j'ai des solutions qui fonctionnent avec LinearGradients comme Je peux simplement lier quelque chose à la propriété "Remplir" - mais dans cette situation cela ne marchera pas, et il y a peut-être d'autres types de dégradés que je peux utiliser et que d'autres utiliseront à l'avenir.

Répondre

12

Le problème est que GradientStop ne dérive pas de FrameworkElement ne peut donc pas être données liées. Malheureusement, cela signifie que vous devez le définir à partir du code.

+0

Merci pour cette réponse, j'ai entendu parler des éléments dérivés de FrameworkElement, donc ce n'est pas le cas - devinez les couleurs seraient les mêmes - maintenant je comprends, je vais le mettre dans le code car il n'y a vraiment pas d'alternative - peut-être Silverlight 4 permettra cela? – RoguePlanetoid

+0

+1 pour cela. Au départ, j'allais répondre que ce n'était pas possible car 'Color' n'était pas une propriété de dépendance. Un bref coup d'oeil dans .NET Reflector montre qu'il suit ce modèle, donc j'étais confus. Il s'avère que 'Color' est créé via' Animatable.RegisterProperty'. Donc, même si ce n'est pas contraignant, il est animable. –

+0

@RoguePanetiod: En fait, les choses sont un peu plus difficiles que ça. En règle générale, le pinceau est un objet référencé, les nouvelles occurrences du pinceau ne sont pas créées par élément. Par conséquent, si vous modifiez le pinceau référencé par un élément, vous pouvez constater que vous modifiez également la référence du pinceau par tous les autres éléments. – AnthonyWJones

0

Avez-vous confirmé le type utilisé comme DataContext où votre brosse de dégradé est définie? Comme vous n'avez pas spécifié de Source dans votre liaison, elle utilisera par défaut le DataContext.

+0

Ceci est bien que d'autres éléments tels que SolidColorBrushes, où cela vient peut se lier à des valeurs sans problème - cette erreur se produit lorsque le programme fonctionne - ce serait bien si elle a dit ce qui était erroné avec le type lié - Mais ça ne va jamais aussi loin. – RoguePlanetoid

+0

J'ai fait plus de développement WPF que le développement Silverlight, mais lors de l'exécution d'une application WPF avec des liaisons incorrectes, des messages très utiles sont crachés dans le panneau 'Sortie' de Visual Studio. Ils indiquent le chemin de liaison, le type de cible et le type de source. Voyez-vous cela? –

+0

Non mais j'ai vu ces messages quand il y a une conversion, comme par exemple lier une chaine à un pinceau, mais la reliure aux couleurs ne semble pas possible ou au gradient s'arrête car elle n'obtient jamais ce résultat car elle n'accepte aucune liaison - ce qui explique l'erreur. – RoguePlanetoid

5

Pour vraiment y arriver, vous avez deux choix.

Bind les éléments d'affichage propriété Brush à une propriété brosse dans les données

ont la source de données portent une propriété qui Expose qui brosse que vous souhaitez utiliser sur pour chaque élément et vous lier la propriété de l'écran élément qui prend le pinceau, par exemple une propriété Fill. Cela fonctionne si l'ensemble des valeurs distinctes que vous auriez pour les paires de valeurs Start et Stop est petit. Vous créez une instance de chaque pinceau pour chaque paire, puis l'élément de données expose le bon.

Bind les éléments d'affichage propriété Brush en utilisant une valeur Convertisseur

Si votre démarrage et d'arrêt des valeurs d'une variable plus vous aurez besoin d'une nouvelle instance d'un type de brosse pour chaque élément affiché. Dans ce cas, vous lier la propriété des éléments d'affichage de la brosse à l'aide d'un convertisseur de valeur, par exemple: -

<Rectangle Fill="{Binding Converter={StaticResource MyBrushBuilder} }" ... > 

Voir cette answer pour une description complète de la construction d'un convertisseur.

Dans ce cas, si votre implémentation de la méthode de conversion ressemblerait à ceci: -

public object Convert(object value, Type targetType, object parameter, CultureInfo culture) 
{ 
    YourItemsType item = (YourItemsType)value; 

    var start = new GradientStop(); 
    start.Offset = 0; 
    start.Color = item.GradientStart; 

    var stop = new GradientStop(); 
    stop.Offset = 1; 
    stop.Color = item.GradientStop; 

    var result = new RadialGradientBrush(); 
    result.GradientOrigin = new Point(0.20, 0.5); 
    result.Center = new Point(0.25, 0.5); 
    result.RadiusX = 0.75; 
    result.RadiusY = 0.5; 
    result.GradientStops = new GradientStopCollection(); 
    result.GradientStops.Add(start); 
    result.GradientStops.Add(stop); 

    return result; 
} 

caveat

Chaque fois que la liaison de données se produit un tas de pinceaux sont créés l'un pour chaque élément. Cela peut être coûteux et indésirable. Par conséquent, si cette approche du convertisseur de liaison est jugée nécessaire, je vous recommande d'utiliser un dictionnaire statique de brosses. La clé dans ce dictionnaire serait le hachage des deux couleurs. Vous ne créerez un nouveau pinceau que si nécessaire et réutiliserez un pinceau créé si possible.

+0

Méfiez-vous des fautes de frappe dans cette réponse: start.Offset et start.Color sont définis deux fois. Il y a aussi quelques demi-colonnes manquantes. – jpatte

0

Assez vieux Post, mais c'est possible (maintenant), alors voici ma solution. Mon code XAML:

<Ellipse.Resources> 
    <local:ColorConverter x:Key="ColorConverter"/> 
</Ellipse.Resources> 
<Ellipse.Fill> 
    <RadialGradientBrush> 
     <GradientStop Color="{Binding MenuColor2, Source={x:Static p:Settings.Default}, Converter={StaticResource ColorConverter}}" Offset="1" /> 
     <GradientStop Color="{Binding MenuColor1, Source={x:Static p:Settings.Default}, Converter={StaticResource ColorConverter}}" Offset="0.85" /> 
    </RadialGradientBrush> 
</Ellipse.Fill> 

Et voici mon C# -Code.

[ValueConversion(typeof(System.Drawing.Color), typeof(System.Windows.Media.Color))] 
public class ColorConverter : IValueConverter 
{ 

    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) 
    { 
     if (value is System.Drawing.Color) 
     { 
      var clr = (System.Drawing.Color)value; 
      return System.Windows.Media.Color.FromArgb(clr.A, clr.R, clr.G, clr.B); 
     } 
     return value; 
    } 

    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) 
    { 
     if (value is Color) 
     { 
      var clr = (Color)value; 
      return System.Drawing.Color.FromArgb(clr.A, clr.R, clr.G, clr.B); 
     } 
     return value; 
    } 
}