2010-02-16 10 views
10

Ho un gradiente che cambia i suoi colori, voglio che il testo al suo interno sia sempre visibile.WPF "magic" negating brush?

Preferisco farlo dinamicamente se esiste una risorsa predefinita; Voglio un "pennello magico" che neghi il colore.

Eventuali esperimenti?

+0

Potete fornire un esempio di come si cambiano i colori del gradiente? –

+0

Questo è il punto. Voglio un pennello dinamico, non statico. – Shimmy

+0

Cosa intendi per dinamico? Assegni colori diversi nel codice? Cambiano come parte di un'animazione? Vuoi semplicemente dire che usi DynamicResource invece di StaticResource? –

risposta

6

Bene, l'inversione del colore potrebbe essere eseguita come un effetto bitmap, ma c'è un modo più semplice.

Fai un Grid che sarà il contenitore per 3 pannelli bambino in modo che questi pannelli bambino si sovrappongono l'un l'altro completamente:

Mettere il testo in cui si desidera in un pannello che ha uno sfondo Transparent (che fanno da predefinito). Denominare questo pannello 'maschera'.

Creare un altro pannello chiamato 'mainbackground' e assegnargli il gradiente principale come sfondo. Metti questo dopo il pannello 'maschera' in modo che copra il testo

Crea un altro pannello chiamato 'invertedforeground' e dagli il gradiente opposto. Per ciascun valore di colore nel gradiente principale, assegna a questo il contrario (ad es. Se un colore è #FF0000, inserisci #00FFFF). Puoi animare questo gradiente proprio come puoi animare il primo, solo con valori opposti. Quindi imposta OpacityMask di questo pannello su VisualBrush e imposta la proprietà Visual su {Binding ElementName=mask}.

<Grid> 
    <Grid.Resources> 
     <local:MyColorConverter x:Key="colorConverter" /> 
    </Grid.Resources> 
    <Grid 
     Name="mask"> 
     <TextBlock 
      Name="mytext" 
      HorizontalAlignment="Center" 
      VerticalAlignment="Center" 
      FontSize="32" 
      Foreground="White" 
      FontWeight="Bold">Blah blah blah</TextBlock> 
    </Grid> 

    <Grid Name="mainbackground"> 
     <Grid.Background> 
      <LinearGradientBrush 
       ColorInterpolationMode="ScRgbLinearInterpolation" 
       EndPoint="1,0"> 
       <GradientStop x:Name="stop1" 
        Color="#FF0000" 
        Offset="0" /> 
       <GradientStop x:Name="stop2" 
        Color="#00FF00" 
        Offset="0.5" /> 
       <GradientStop x:Name="stop3" 
        Color="#0000FF" 
        Offset="1" /> 
      </LinearGradientBrush> 
     </Grid.Background> 
    </Grid> 

    <Grid Name="invertedforeground"> 
     <Grid.Background> 
      <LinearGradientBrush 
       ColorInterpolationMode="ScRgbLinearInterpolation" 
       EndPoint="1,0"> 
       <GradientStop 
        Color="{Binding ElementName=stop1, Path=Color, Converter={StaticResource colorConverter}}" 
        Offset="0" /> 
       <GradientStop 
        Color="{Binding ElementName=stop2, Path=Color, Converter={StaticResource colorConverter}}" 
        Offset="0.5" /> 
       <GradientStop 
        Color="{Binding ElementName=stop3, Path=Color, Converter={StaticResource colorConverter}}" 
        Offset="1" /> 
      </LinearGradientBrush> 
     </Grid.Background> 
     <Grid.OpacityMask> 
      <VisualBrush 
       Visual="{Binding ElementName=mask}" /> 
     </Grid.OpacityMask> 
    </Grid> 
</Grid> 

probabilmente si potrebbe utilizzare convertitori vincolanti e valore in modo che avete solo bisogno di animare un gradiente e l'altro segue semplicemente.


Edit: Ho provato a installare un pennello Primo piano invertita per il testo, ma sarebbe attenersi a coordinate 's il TextBlock, così sono ritornato alla precedente soluzione di utilizzare il testo come un OpacityMask.


Edit 2: ho aggiunto esempio di utilizzo di un costume IValueConverter e vincolante i colori del gradiente di testo al gradiente di originale. È inoltre possibile utilizzare binding e un convertitore da qualche parte più in alto, ad esempio Background vincolante nella proprietà mainbackgroundBackground e il convertitore accetta il pennello sfumatura di input e restituisce un pennello sfumato diverso configurazione molto diversa rispetto all'originale).

+0

+1 per sincronizzare il layout dei gradienti utilizzando un OpacityMask. Due considerazioni aggiuntive: 1. Il pennello invertito può essere calcolato dal pennello in primo piano usando l'associazione con un IValueConverter invece di farlo manualmente. 2. Il calcolo del colore è più difficile di una inversione di colore diritta, ad esempio l'inversione # 808080 ti dà il quasi identico # 7F7F7F. –

+1

# 1: Effettivamente può. Penso che mostrerò il legame, almeno. 2: questa è la definizione di inversione; il grigio diventa grigio. La decisione progettuale di utilizzare un gradiente sul testo per differenziarlo da un gradiente di sfondo è un terreno fertile per i casi limite. L'OP non ci ha fornito molte informazioni per semplificare le nostre risposte. –

8

Joel ha fornito una risposta eccellente su come allineare i pennelli sfumati. Vorrei toccare la complessità della creazione automatica di un nuovo pennello sfumato che è garantito per essere visibile rispetto a quello vecchio.

In WPF i colori sono modellati tridimensionalmente, poiché richiedono tre numeri (come R/G/B o H/S/B) per definire un colore WPF, senza contare il componente alfa. Un determinato riempimento del gradiente può essere visualizzato come un percorso che procede da un punto di colore a un altro nello spazio cromatico tridimensionale. Per creare un gradiente inverso che contrasti in ogni punto richiede la creazione di un percorso aggiuntivo che in nessun punto arrivi "troppo vicino" al percorso originale. "Troppo vicino" a questo scopo sono due colori che sono difficili da distinguere per l'occhio umano. Questo è in realtà soggettivo.Il 4% circa delle persone daltoniche avrà una diversa interpretazione di "troppo vicino" rispetto a chi non lo è.

Per una persona non daltonica in cui "troppo vicino" è ragionevolmente definito ci sarà sempre una moltitudine di percorsi che soddisfano i criteri. In questo caso sono richiesti criteri aggiuntivi per decidere quale è "migliore". Ad esempio, il testo dovrebbe contrastare il più bruscamente possibile con lo sfondo, oppure dovrebbe avere la stessa tonalità generale per la maggior parte del modo?

D'altra parte, una definizione prudente di "troppo vicino" che tiene conto della percezione del colore di tutti, come "la luminosità deve differire di almeno il 25%", soffrirà del problema opposto: l'unico gradiente che soddisfa la condizione in ogni punto deve essere effettivamente discontinuo, cioè deve saltare da un colore a un colore distante tutto in una volta. Si consideri, ad esempio, il semplice gradiente dal nero al bianco. Se è coinvolta solo la luminanza, lo sfondo contrastante deve avere una discontinuità, altrimenti si adatterà ad un certo punto.

Per queste ragioni, la creazione di un algoritmo generale per produrre uno sfondo contrastante è più un'arte che una scienza. È possibile utilizzare algoritmi multipli e diversi algoritmi saranno appropriati in diverse situazioni.

Un algoritmo semplice che è stato utilizzato per questo scopo è quello di mantenere la tonalità e la saturazione stessa del gradiente e impostare la luminanza su (luminance + 50%) mod 100%. Tuttavia, questo algoritmo non produce risultati molto estetici nella maggior parte dei casi e non ha mai una variazione di luminanza superiore al 50%. Una modifica di questo algoritmo è di invertire o spostare anche i valori di tonalità e saturazione.

Un algoritmo ancora più semplice per calcolare una luminanza contrastante è luminance>50% ? 0% : 100%. Anche questo può avere problemi estetici.

La linea di fondo qui è che non esiste una risposta giusta per invertire i colori del gradiente. Ma se hai un algoritmo per farlo, usa la tecnica della maschera di opacità di Joel insieme a una rilegatura e un IValueConverter che implementa il tuo algoritmo farà il trucco.

+1

+1: la tua risposta è esattamente ciò che volevo scrivere immediatamente dopo aver letto l'approccio "antigradiente" di Joel. Ottima introduzione ai problemi dello spazio colore! – quetzalcoatl

Problemi correlati