2011-04-13 19 views
15

Tengo Border con la propiedad CornerRadius establecida en 10. Dentro de esa Border, hay una StackPanel. El panel contiene dos Border s con fondos azules y rojos, respectivamente.¿Cómo hacer que el borde recorte los elementos secundarios?

Las esquinas izquierda y superior derecha superior del borde azul y la parte inferior izquierda e inferior derecha de la frontera rojo se pega fuera de los bordes curvos de la primera frontera. Deseo hacer que los bordes azul y rojo se recorten en el borde principal. ¿Es eso posible?

Por cierto, sé que si configuro el mismo valor para la propiedad CornerRadius de los bordes azul y rojo, seguirá la curva de la primera. No quiero eso, quiero recortar. ¡Gracias!

<Border 
    Width="200" 
    Height="200" 
    BorderThickness="1" 
    BorderBrush="Black" 
    CornerRadius="10"> 
    <StackPanel> 
     <Border Height="100" Background="Blue" /> 
     <Border Height="100" Background="Red" /> 
    </StackPanel> 
</Border> 
+0

Podría publicar un código que ilustra el problema? –

Respuesta

18

Usted puede escribir un convertidor para la propiedad de clip. El convertidor debería implementar IMultiValueConverter y ligarse al tamaño real y al radio de la esquina, por ejemplo.

public class BorderClipConverter : IMultiValueConverter 
{ 
    public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture) 
    { 
     if (values.Length == 3 && values[0] is double && values[1] is double && values[2] is CornerRadius) 
     { 
      var width = (double)values[0]; 
      var height = (double)values[1]; 

      if (width < Double.Epsilon || height < Double.Epsilon) 
      { 
       return Geometry.Empty; 
      } 

      var radius = (CornerRadius)values[2]; 

      // Actually we need more complex geometry, when CornerRadius has different values. 
      // But let me not to take this into account, and simplify example for a common value. 
      var clip = new RectangleGeometry(new Rect(0, 0, width, height), radius.TopLeft, radius.TopLeft); 
      clip.Freeze(); 

      return clip; 
     } 

     return DependencyProperty.UnsetValue; 
    } 

    public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture) 
    { 
     throw new NotSupportedException(); 
    } 
} 

Uso:

<Border CornerRadius="10"> 
    <Border.Clip> 
     <MultiBinding Converter="{StaticResource BorderClipConverter}"> 
      <Binding Path="ActualWidth" 
         RelativeSource="{RelativeSource Self}"/> 
      <Binding Path="ActualHeight" 
         RelativeSource="{RelativeSource Self}"/> 
      <Binding Path="CornerRadius" 
         RelativeSource="{RelativeSource Self}"/> 
     </MultiBinding> 
    </Border.Clip> 
</Border> 
+0

mejor ejemplo @MaratKhasanov 's que he sido capaz de encontrar! –

+0

pensé en hacer algo como esto, pero me preguntaba si hay una manera estaban convenientemente XAML de hacerlo. voy a probar esto. mi pregunta al respecto: http: // stackoverflow.com/questions/24158147/wpf-clipping-a-border –

+0

Esto podría hacerse con un convertidor regular (es decir, no un convertidor multivalente) y luego vinculante consigo mismo. Haría el encuadernado mucho más bonito (es decir, mucho más fácil de usar repetidamente) y empujaría la lógica de agarrar el ancho/alto/radio en el convertidor. – claudekennilol

1

ClipToBounds es la propiedad que podría ayudar en este caso.

Editar: Después de algunas pruebas, me di cuenta de que ClipToBounds sólo se preocupa por los límites reales (es decir, el área rectangular utiliza el control), por lo que el contenido todavía sobresale en las esquinas ...

Esto parece sugerir que sencilla de recorte para la frontera no es posible. Puede establecer la propiedad Clip en un rectángulo redondeado, aunque esto no es muy conveniente porque creo que no se puede limitar su tamaño.

Sus opciones parecen estar utilizando un OpacityMask junto con un VisualBrush o volver a crear un recorte cada vez que cambian las propiedades relevantes mediante el uso de un MultiValueConverter MultiBinding & ...

+0

Clip to bounds no funcionará aquí, me temo. – Boris

+0

Dime algo que no sé ... –

+0

OpacticyMask sólo se exceptúa el tipo de geometría, por lo que sería todavía necesita algún convertidor como en cuestión –

6

También hay una solución XAML sólo a su problema mediante el uso de la propiedad OpacityMask. El truco es crear un Grid dentro del borde exterior y establecer OpacityMask de la cuadrícula a otro elemento que actúa como una máscara de recorte.

<Border Width="200" Height="200" 
     BorderThickness="1" BorderBrush="Black" 
     CornerRadius="10"> 
    <Grid> 
     <Grid.OpacityMask> 
      <VisualBrush Visual="{Binding ElementName=clipMask}" Stretch="None" /> 
     </Grid.OpacityMask> 
     <Border x:Name="clipMask" Background="White" CornerRadius="10" /> 
     <StackPanel Background="White"> 
      <Border Height="100" Background="Blue" /> 
      <Border Height="100" Background="Red" /> 
     </StackPanel> 
    </Grid> 
</Border> 

En el fragmento anterior I utilizó un Border como máscara de recorte, pero también puede ser otro elemento, siempre y cuando su color de relleno no es transparente. Tenga en cuenta también que el clipMask Border también tiene el mismo CornerRadius.

Inspirado por: http://www.codeproject.com/Articles/225076/Creating-Inner-Shadows-for-WPF-and-Silverlight

Cuestiones relacionadas