2008-11-27 20 views

Respuesta

47

Éstos son los aspectos más destacados de esta thread mencionados por Jobi

  • Ninguno de los decoradores (es decir Frontera) o paneles de diseño (es decir StackPanel) vienen con este comportamiento fuera de la -caja.
  • ClipToBounds es para el diseño. ClipToBounds no evita que un elemento se dibuje fuera de sus límites; solo evita que los diseños de los niños se "derramen". Además ClipToBounds = True no es necesario para la mayoría de los elementos porque sus implementaciones no permiten que el diseño de su contenido se derrame de todos modos. La excepción más notable es Canvas.
  • Finalmente, Border considera que las esquinas redondeadas son dibujos dentro de los límites de su diseño.

Aquí es una implementación de una clase que hereda de Frontera e implementa el funcionamiento correcto:

 /// <Remarks> 
    ///  As a side effect ClippingBorder will surpress any databinding or animation of 
    ///   its childs UIElement.Clip property until the child is removed from ClippingBorder 
    /// </Remarks> 
    public class ClippingBorder : Border { 
     protected override void OnRender(DrawingContext dc) { 
      OnApplyChildClip();    
      base.OnRender(dc); 
     } 

     public override UIElement Child 
     { 
      get 
      { 
       return base.Child; 
      } 
      set 
      { 
       if (this.Child != value) 
       { 
        if(this.Child != null) 
        { 
         // Restore original clipping 
         this.Child.SetValue(UIElement.ClipProperty, _oldClip); 
        } 

        if(value != null) 
        { 
         _oldClip = value.ReadLocalValue(UIElement.ClipProperty); 
        } 
        else 
        { 
         // If we dont set it to null we could leak a Geometry object 
         _oldClip = null; 
        } 

        base.Child = value; 
       } 
      } 
     } 

     protected virtual void OnApplyChildClip() 
     { 
      UIElement child = this.Child; 
      if(child != null) 
      { 
       _clipRect.RadiusX = _clipRect.RadiusY = Math.Max(0.0, this.CornerRadius.TopLeft - (this.BorderThickness.Left * 0.5)); 
       _clipRect.Rect = new Rect(Child.RenderSize); 
       child.Clip = _clipRect; 
      } 
     } 

     private RectangleGeometry _clipRect = new RectangleGeometry(); 
     private object _oldClip; 
    } 
+0

Esta solución usa un convertidor en lugar de crear una nueva clase: http://stackoverflow.com/questions/5649875/how-to-make-the-border-trim-the-child-elements Nota: tuve que anidar en el borde objetos para retener mi borde de color (el fondo funciona bien sin anidar) –

+0

¿Podría explicar la lógica en su código? Parece que no puedo entender el propósito de '_oldClip' y por qué está eligiendo' RadiusX' y 'RadiusY' para que sean' this.CornerRadius.TopLeft - (this.BorderThickness.Left * 0.5) '. –

0

Haga la rejilla más pequeña o el borde más grande. De modo que el elemento de borde contiene completamente la cuadrícula.

Como alternativa, vea si puede hacer que el fondo de la cuadrícula sea transparente, para que no se note el "salido".

Actualización: Vaya, no noté que esta era una pregunta de WPF. No estoy familiarizado con eso. Este fue un consejo general de HTML/CSS. Tal vez ayude ...

+0

Pero tienes razón en que es una respuesta lógica, y también funciona en muchas situaciones en WPF. –

7

Así que me encontré con esta solución, a continuación, seguido en enlace del foro de MSDN que Jobi siempre y pasó 20 minutos escribiendo mi propio control ClippingBorder.

Luego me di cuenta de que el tipo de propiedad CornerRadius no es un doble, sino System.Windows.CornerRaduis que acepta 4 dobles, uno para cada esquina.

así que voy a enumerar otra solución alternativa ahora, que lo más probable es satisfacer las necesidades de la mayoría de personas que van a tropezar con este post en el futuro ...

Digamos que usted tiene XAML que se parece esto:

<Border CornerRadius="10"> 
    <Grid> 
     ... your UI ... 
    </Grid> 
</Border> 

y el problema es que el fondo del elemento de cuadrícula sangra a través y muestra más allá de las esquinas redondeadas. Asegúrese de que su <Grid> tenga fondo transparente en lugar de asignar el mismo pincel a la propiedad "Fondo" del elemento <Border>. No más sangrado más allá de las esquinas y sin necesidad de un montón de código CustomControl.

Es cierto que, en teoría, el área del cliente todavía tiene el potencial de atravesar el borde de la esquina, pero usted controla ese contenido para que usted, como desarrollador, tenga suficiente relleno o para asegurarse de que la forma del el control al lado del borde es apropiado (en mi caso, mis botones son redondos, por lo que se ajustan muy bien en la esquina sin ningún problema).

6

Como mencionó Micah ClipToBounds no funcionará con Border.ConerRadius.

Hay UIElement.Clip propiedad, que Border herencias.

Si conoce el tamaño exacto de la frontera, entonces aquí es la solución:

<Border Background="Blue" CornerRadius="3" Height="100" Width="100"> 
     <Border.Clip> 
     <RectangleGeometry RadiusX="3" RadiusY="3" Rect="0,0,100,100"/> 
     </Border.Clip> 
     <Grid Background="Green"/> 
</Border> 

Si el tamaño no es conocido o dinámico continuación Converter para Border.Clip se puede utilizar. Vea la solución here.

34

XAML puro:

<Border CornerRadius="30" Background="Green"> 
    <Border.OpacityMask> 
     <VisualBrush> 
      <VisualBrush.Visual> 
       <Border 
        Background="Black" 
        SnapsToDevicePixels="True" 
        CornerRadius="{Binding CornerRadius, RelativeSource={RelativeSource AncestorType=Border}}" 
        Width="{Binding ActualWidth, RelativeSource={RelativeSource AncestorType=Border}}" 
        Height="{Binding ActualHeight, RelativeSource={RelativeSource AncestorType=Border}}" 
        /> 
      </VisualBrush.Visual> 
     </VisualBrush> 
    </Border.OpacityMask> 
    <TextBlock Text="asdas das d asd a sd a sda" /> 
</Border> 

Actualización: encontrado una mejor manera de conseguir el mismo resultado. También puede reemplazar Border con cualquier otro elemento ahora.

<Grid> 
    <Grid.OpacityMask> 
     <VisualBrush Visual="{Binding ElementName=Border1}" /> 
    </Grid.OpacityMask> 
    <Border x:Name="Border1" CornerRadius="30" Background="Green" /> 
    <TextBlock Text="asdas das d asd a sd a sda" /> 
</Grid> 

Example

+1

Para deshacerse de los artefactos que se encuentran detrás de las esquinas redondeadas en el primer ejemplo (que se puede ver cuando se amplía con la herramienta Snoop, por ejemplo) también debe vincular BorderThickness (de la misma manera) y establecer BorderBrush en Blanco. Esto cortará el borde de la frontera. –

+0

El primer ejemplo es más general porque puede ser transparente (la forma de recorte no tiene que ser visible, con su fondo). –

1

Utilizando la solución de @ Andrew Mikhailov, se puede definir una clase simple, lo que hace que la definición de un VisualBrush para cada elemento afectado innecesaria manualmente:

public class ClippedBorder : Border 
{ 
    public ClippedBorder() : base() 
    { 
     var e = new Border() 
     { 
      Background = Brushes.Black, 
      SnapsToDevicePixels = true, 
     }; 
     e.SetBinding(Border.CornerRadiusProperty, new Binding() 
     { 
      Mode = BindingMode.OneWay, 
      Path = new PropertyPath("CornerRadius"), 
      Source = this 
     }); 
     e.SetBinding(Border.HeightProperty, new Binding() 
     { 
      Mode = BindingMode.OneWay, 
      Path = new PropertyPath("ActualHeight"), 
      Source = this 
     }); 
     e.SetBinding(Border.WidthProperty, new Binding() 
     { 
      Mode = BindingMode.OneWay, 
      Path = new PropertyPath("ActualWidth"), 
      Source = this 
     }); 

     OpacityMask = new VisualBrush(e); 
    } 
} 

Para probar esto, simplemente compilar las dos muestras siguientes:

<!-- You should see a blue rectangle with rounded corners/no red! --> 
<Controls:ClippedBorder 
    Background="Red" 
    CornerRadius="10" 
    Height="425" 
    HorizontalAlignment="Center" 
    VerticalAlignment="Center" 
    Width="425"> 
    <Border Background="Blue"> 
    </Border> 
</Controls:ClippedBorder> 

<!-- You should see a blue rectangle with NO rounded corners/still no red! --> 
<Border 
    Background="Red" 
    CornerRadius="10" 
    Height="425" 
    HorizontalAlignment="Center" 
    VerticalAlignment="Center" 
    Width="425"> 
    <Border Background="Blue"> 
    </Border> 
</Border> 
Cuestiones relacionadas