2009-05-25 11 views
5

C'è un modo per creare un tipo di "solidcolorbrush" che è una miscela di 2 pennelli solidcolor?Combinato pennello solidcolor

Per il colore posteriore, vorrei poter utilizzare un DynamicReference per un altro pennello. Mentre l'altro colore (nella parte anteriore) potrebbe essere un colore statico con opacità.

Sentitevi liberi di chiedere chiarimenti se questo non ha davvero senso!

risposta

4

Sfortunatamente, pennelli personalizzati non sono supportati in WPF (i tipi di pennello sono contrassegnate 'interno' e non può essere ereditato da), creando così un pennello che è una miscela di due i pennelli che possono essere usati da XAML come un normale SolidColorBrush non sono possibili.

Come soluzione temporanea, è possibile utilizzare MarkupExtension per simulare il comportamento di un pennello personalizzato, che consente di utilizzare la sintassi XAML e fornire un valore personalizzato, che ci consente di utilizzare SolidColorBrush incorporato (non è necessario un pennello personalizzato)) impostata al valore che si ottiene quando mescolando due colori:

/// <summary> 
/// Markup extension to mix two SolidColorBrushes together to produce a new SolidColorBrush. 
/// </summary> 
[MarkupExtensionReturnType(typeof(SolidColorBrush))] 
public class MixedColorBrush : MarkupExtension, INotifyPropertyChanged 
{ 
    /// <summary> 
    /// The foreground mix color; defaults to white. 
    /// If not changed, the result will always be white. 
    /// </summary> 
    private SolidColorBrush foreground = Brushes.White; 

    /// <summary> 
    /// The background mix color; defaults to black. 
    /// If not set, the result will be the foreground color. 
    /// </summary> 
    private SolidColorBrush background = Brushes.Black; 

    /// <summary> 
    /// PropertyChanged event for WPF binding. 
    /// </summary> 
    public event PropertyChangedEventHandler PropertyChanged; 

    /// <summary> 
    /// Gets or sets the foreground mix color. 
    /// </summary> 
    public SolidColorBrush Foreground 
    { 
     get 
     { 
      return this.foreground; 
     } 
     set 
     { 
      this.foreground = value; 
      this.NotifyPropertyChanged("Foreground"); 
     } 
    } 

    /// <summary> 
    /// Gets or sets the background mix color. 
    /// </summary> 
    public SolidColorBrush Background 
    { 
     get 
     { 
      return this.background; 
     } 
     set 
     { 
      this.background = value; 
      this.NotifyPropertyChanged("Background"); 
     } 
    } 

    /// <summary> 
    /// Returns a SolidColorBrush that is set as the value of the 
    /// target property for this markup extension. 
    /// </summary> 
    /// <param name="serviceProvider">Object that can provide services for the markup extension.</param> 
    /// <returns>The object value to set on the property where the extension is applied.</returns> 
    public override object ProvideValue(IServiceProvider serviceProvider) 
    { 
     if (this.foreground != null && this.background != null) 
     { 
      // Create a new brush as a composite of the old ones 
      // This does simple non-perceptual additive color, e.g 
      // blue + red = magenta, but you can swap in a different 
      // algorithm to do subtractive color (red + yellow = orange) 
      return new SolidColorBrush(this.foreground.Color + this.background.Color); 
     } 

     // If either of the brushes was set to null, return an empty (white) brush. 
     return new SolidColorBrush(); 
    } 

    /// <summary> 
    /// Raise the property changed event. 
    /// </summary> 
    /// <param name="propertyName">Name of the property which has changed.</param> 
    protected void NotifyPropertyChanged(string propertyName) 
    { 
     if (this.PropertyChanged != null) 
     { 
      this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); 
     } 
    } 
} 

che può quindi essere utilizzato da XAML come si farebbe con un pennello normale:

<Grid> 
    <Grid.Background> 
     <local:MixedColorBrush Foreground="Blue" Background="Red"/> 
    </Grid.Background> 
</Grid> 

oppure utilizzando la sintassi estensione di markup:

<Grid Background="{local:MixedColorBrush Foreground=Blue, Background=Red}"> 

Lo svantaggio di questo approccio è che non è possibile utilizzare i riferimenti di DynamicResource o StaticResource per associare i valori ad altre risorse nell'applicazione. MarkupExtension non è un oggetto DependencyObject e il binding delle risorse funziona solo su DependencyObjects; i pennelli incorporati sono DependencyObjects, ed è per questo che il binding funziona con i pennelli tradizionali.

3

Prendi i colori dai pennelli in primo piano e sullo sfondo, mescoli e crea un nuovo pennello dal colore risultante.

Esempio in C#:

Color foreground = foregroundBrush.Color; 
Color background = backgroundBrush.Color; 

int opacity = 25; 

int r = (opacity * (foreground.R - background.R)/100) + background.R; 
int g = (opacity * (foreground.G - background.G)/100) + background.G; 
int b = (opacity * (foreground.B - background.B)/100) + background.B; 

SolidColorBrush mixedBrush = new SolidColorBrush(Color.FromArgb(r, g, b)); 
+0

Buon esempio ...ma speravo nella versione XAML di questo ... – Entrodus

6

Mi sono imbattuto nello stesso problema. Normalmente uso solo un xaml ciascuno per gli scuri di base, le luci di base e poi uno per ciascun accento di colore (blu, rosso ecc.). L'accento è leggermente visibile che lo rende più scuro quando il tema più scuro viene selezionato con uno sfondo più scuro.

Quando si crea un tema con un colore accento secondario per avere più contrasto nell'app (ad esempio grigio quando è selezionato il tema luce, colore accento quando tema scuro), avevo bisogno di costruire un pennello di due colori come altrimenti io dovrebbe creare un tema scuro e chiaro per ogni colore.

Ecco quello che io uso:

<DrawingBrush x:Key="SecondaryAccentColorBrush" Viewport="0,0,1,1" TileMode="Tile"> 
    <DrawingBrush.Drawing> 
     <DrawingGroup> 
      <GeometryDrawing> 
       <GeometryDrawing.Geometry> 
        <RectangleGeometry Rect="0,0,1,1" /> 
       </GeometryDrawing.Geometry> 
       <GeometryDrawing.Brush> 
        <SolidColorBrush Color="{DynamicResource AccentColor}"/> 
       </GeometryDrawing.Brush> 
      </GeometryDrawing> 
      <GeometryDrawing> 
       <GeometryDrawing.Geometry> 
        <RectangleGeometry Rect="0,0,1,1" /> 
       </GeometryDrawing.Geometry> 
       <GeometryDrawing.Brush> 
        <SolidColorBrush Color="{DynamicResource Gray10}"/> 
       </GeometryDrawing.Brush> 
      </GeometryDrawing> 
     </DrawingGroup> 
    </DrawingBrush.Drawing> 
</DrawingBrush> 

quando il tema è acceso, l'alfa di interruttori "Gray10" tra 00 e FF, quindi il pennello mostra grigio o il colore accento.

3

Un modo semplice per farlo (ma probabilmente non ottimizzata), creare un LinearGradientBrush dei due colori in modalità di ripetizione con Endpoint è uguale al punto di partenza:

<LinearGradientBrush SpreadMethod="Repeat" EndPoint="0,0"> 
           <GradientStop Color="Red" Offset="0" /> 
           <GradientStop Color="Yellow" Offset="1" /> 
          </LinearGradientBrush> 

Questo ti dà una spazzola arancione.