2011-01-29 13 views
13

Necesito crear un gradiente de varias etapas a lo largo de una trayectoria circular, como se demuestra en la siguiente imagen:Creación Gradiente del cepillo a lo largo de una trayectoria circular

Wheel Gradient

¿Alguien tiene alguna idea sobre cómo esto podría ser logrado en XAML en lugar de código? ¿Sería posible utilizar los pinceles de degradado existentes o compilarlos de alguna manera para lograr este efecto?

+0

¿Por qué las opciones de color? No es coherente con ninguna asignación de tono y color que haya visto antes, y las sinestesias [tienden a percibir esto de manera bastante diferente] (http://rhythmiclight.com/archives/ideas/colorscales.html) de todos modos. Tampoco parece coincidir exactamente con [Color Piano Project] (http://colorpiano.com/). –

+0

Las elecciones de color son arbitrarias y se eligen solo por motivos estéticos. No hay correlación con el lanzamiento. – Charlie

Respuesta

15

Puede obtener un efecto radial cruzado utilizando una transformación no afín, como una transformación de perspectiva. Solía ​​las ideas en este artículo de Charles Petzold:

para crear una región XAML de sólo anular con un gradiente transversal radial. Aquí está el marcado:

<Canvas x:Name="LayoutRoot"> 
    <Canvas.Resources> 
     <x:Array x:Key="sampleData" Type="sys:Object"> 
      <x:Array Type="sys:Object"> 
       <sys:Double>0</sys:Double> 
       <LinearGradientBrush StartPoint="0,0" EndPoint="1,0"> 
        <GradientStop Color="Red" Offset="0"/> 
        <GradientStop Color="Yellow" Offset="0.5"/> 
        <GradientStop Color="Blue" Offset="1"/> 
       </LinearGradientBrush> 
      </x:Array> 
      <x:Array Type="sys:Object"> 
       <sys:Double>90</sys:Double> 
       <LinearGradientBrush StartPoint="0,0" EndPoint="1,0"> 
        <GradientStop Color="Blue" Offset="0"/> 
        <GradientStop Color="Green" Offset="0.5"/> 
        <GradientStop Color="Red" Offset="1"/> 
       </LinearGradientBrush> 
      </x:Array> 
      <x:Array Type="sys:Object"> 
       <sys:Double>180</sys:Double> 
       <LinearGradientBrush StartPoint="0,0" EndPoint="1,0"> 
        <GradientStop Color="Red" Offset="0"/> 
        <GradientStop Color="Yellow" Offset="0.5"/> 
        <GradientStop Color="Blue" Offset="1"/> 
       </LinearGradientBrush> 
      </x:Array> 
      <x:Array Type="sys:Object"> 
       <sys:Double>270</sys:Double> 
       <LinearGradientBrush StartPoint="0,0" EndPoint="1,0"> 
        <GradientStop Color="Blue" Offset="0"/> 
        <GradientStop Color="Green" Offset="0.5"/> 
        <GradientStop Color="Red" Offset="1"/> 
       </LinearGradientBrush> 
      </x:Array> 
     </x:Array> 
    </Canvas.Resources> 
    <ItemsControl ItemsSource="{StaticResource sampleData}"> 
     <ItemsControl.OpacityMask> 
      <RadialGradientBrush> 
       <GradientStop Color="Transparent" Offset="0.95"/> 
       <GradientStop Color="White" Offset="0.949"/> 
       <GradientStop Color="White" Offset="0.501"/> 
       <GradientStop Color="Transparent" Offset="0.5"/> 
      </RadialGradientBrush> 
     </ItemsControl.OpacityMask> 
     <ItemsControl.Template> 
      <ControlTemplate TargetType="ItemsControl"> 
       <ItemsPresenter/> 
      </ControlTemplate> 
     </ItemsControl.Template> 
     <ItemsControl.ItemsPanel> 
      <ItemsPanelTemplate> 
       <Canvas/> 
      </ItemsPanelTemplate> 
     </ItemsControl.ItemsPanel> 
     <ItemsControl.ItemTemplate> 
      <DataTemplate> 
       <Canvas Width="1" Height="1"> 
        <Canvas.RenderTransform> 
         <RotateTransform Angle="{Binding [0]}" CenterX="124" CenterY="124"/> 
        </Canvas.RenderTransform> 
        <Viewport3D Width="250" Height="250"> 
         <ModelVisual3D> 
          <ModelVisual3D.Content> 
           <Model3DGroup> 
            <GeometryModel3D> 
             <GeometryModel3D.Geometry> 
              <MeshGeometry3D Positions="0 0 0, 0 1 0, 1 0 0, 1 1 0" TextureCoordinates="0 1, 0 0, 1 1, 1 0" TriangleIndices="0 2 1, 2 3 1"/> 
             </GeometryModel3D.Geometry> 
             <GeometryModel3D.Material> 
              <DiffuseMaterial Brush="{Binding [1]}"/> 
             </GeometryModel3D.Material> 
             <GeometryModel3D.Transform> 
              <MatrixTransform3D Matrix="0.002,0,0,0,-0.499,-0.498,0,-0.998,0,0,1,0,0.499,0.5,0,1"/> 
             </GeometryModel3D.Transform> 
            </GeometryModel3D> 
            <AmbientLight Color="White" /> 
           </Model3DGroup> 
          </ModelVisual3D.Content> 
         </ModelVisual3D> 
         <Viewport3D.Camera> 
          <OrthographicCamera Position="0.5 0.5 1" LookDirection="0 0 -1" UpDirection="0 1 0" Width="1"/> 
         </Viewport3D.Camera> 
        </Viewport3D> 
       </Canvas> 
      </DataTemplate> 
     </ItemsControl.ItemTemplate> 
    </ItemsControl> 
</Canvas> 

y aquí es el resultado visual:

enter image description here

El efecto utiliza una colección fuente de datos con los artículos que tienen dos propiedades, un ángulo y un cepillo. Dibuja cuatro cuadrantes (arriba, derecha, abajo e izquierda) usando un pincel diferente para cada cuadrante. Luego todo se recorta en la región anular con una máscara de opacidad.

+0

Esto se ve muy bien para mí, pero ¿cómo se ve la clase Tuple? Simplemente agregando algunas propiedades y mi margen arroja errores como la clase "Tuple" no admite contenido directo, etc. – Charlie

+0

Terminé configurando las Tuplas en el código en lugar de en el marcado (todavía tengo curiosidad por saber cómo se ve esa clase), y esto parece ser justo lo que necesito. Gracias por una solución realmente inteligente, Rick. :) – Charlie

+0

Ojalá hubiera una clase estándar como el contenedor de la herramienta 'Tuple' solo para organizar datos de muestra sin tener que definir clases. Puede usar una x: matriz de x: matrices o sus propias estructuras de datos. Actualizaré el ejemplo para usar el método anterior. –

0

Eche un vistazo a Shazzam Puede escribir un pixelder que represente este degradado.

Creo que a la larga esto será más fácil que combinar degradados lineales. Otra opción es simplemente dibujar un mapa de bits y usarlo.

+0

Gracias por la sugerencia, pero un sombreador de píxeles parece excesivo para este escenario. ¿Por qué escribir C/HLSL cuando podía simplemente escribir algún código C# para lograr esto más directamente? Pero mi verdadero objetivo era ver si se podía hacer en XAML. – Charlie

+0

Como puede ver (la respuesta de Rick Sladkey) se puede hacer sin embargo, creo que su solución (transformaciones 3D) será mucho más lenta y el código para el pixelder sería mucho más compacto. –

1

En GDI +/Winforms puede utilizar la PathGradientBrush para hacer esto:

http://www.bobpowell.net/pgb.htm

http://msdn.microsoft.com/en-us/library/system.drawing.drawing2d.pathgradientbrush.aspx

Desafortunadamente, no hay soporte para un PathGradientBrush en WPF pero algunas personas han pedido aquí :

http://dotnet.uservoice.com/forums/40583-wpf-feature-suggestions/suggestions/480949-add-a-pathgradientbrush-like-in-winforms-

(valdría la pena Castin g su voto también!)

Debido a la falta de soporte no puede hacerlo directamente en XAML, sin embargo, podría utilizar el código GDI + para crear una imagen y luego usar la imagen en su XAML. Esto podría brindarle un mejor rendimiento que usar una transformación no afín.

+0

Pruebe [GradientPath de Charles Petzold] (http://www.charlespetzold.com/blog/2009/02/Graphical-Paths-with-Gradient-Colors.html). – xmedeko

Cuestiones relacionadas