2008-11-27 7 views

Répondre

47

Voici les faits saillants de cette thread mentionnés par Jobi

  • Aucun des décorateurs (c.-à-frontière) ou des panneaux de mise en page (c.-à-StackPanel) viennent avec ce comportement hors du -boîte.
  • ClipToBounds est pour la disposition. ClipToBounds n'empêche pas un élément de dessiner en dehors de ses limites; cela empêche simplement les présentations des enfants de «déborder». De plus, ClipToBounds = True n'est pas nécessaire pour la plupart des éléments, car leurs implémentations ne permettent pas à la mise en page de leur contenu de se répandre de toute façon. L'exception la plus notable est Canvas. Enfin, Border considère les coins arrondis comme des dessins dans les limites de sa mise en page.

Voici une implémentation d'une classe qui hérite de la frontière et met en œuvre la fonctionnalité appropriée:

 /// <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

Cette solution utilise ici un convertisseur au lieu de faire une nouvelle classe: http://stackoverflow.com/questions/5649875/how-to-make-the-border-trim-the-child-elements Note: je devais nicher la frontière objets pour conserver ma bordure colorée (l'arrière-plan fonctionne bien sans imbrication) –

+0

Pourriez-vous expliquer la logique dans votre code? Je n'arrive pas à comprendre le but de '_oldClip' et pourquoi vous choisissez le' RadiusX' & 'RadiusY' pour être' this.CornerRadius.TopLeft - (this.BorderThickness.Left * 0.5) '. –

0

Redimensionnez la grille ou agrandissez-la. Alors que l'élément frontière contient complètement la grille.

Vous pouvez également voir si vous pouvez rendre l'arrière-plan de la grille transparent, de sorte que le "dépassement" ne soit pas perceptible.

Mise à jour: Oups, n'a pas remarqué que c'était une question WPF. Je ne suis pas familier avec ça. C'était un conseil général HTML/CSS. Peut-être qu'il aide ...

+0

Mais vous avez raison que c'est une réponse logique, et cela fonctionne aussi dans de nombreuses situations dans WPF. –

7

Je viens de tomber sur cette solution, puis suivie dans le lien forum msdn que Jobi fourni et a passé 20 minutes en écrivant mon propre contrôle ClippingBorder.

Puis j'ai réalisé que le type de propriété CornerRadius n'est pas un double, mais System.Windows.CornerRaduis qui accepte 4 doubles, un pour chaque coin.

Je vais énumérer une autre solution de rechange maintenant, qui le plus probablement satisfaire aux exigences de la plupart des gens qui tombent par hasard sur ce poste à l'avenir ...

Disons que vous avez XAML qui ressemble à cela:

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

Et le problème est que l'arrière-plan de l'élément Grid saigne à travers et montre passé les coins arrondis. Assurez-vous que votre <Grid> a un arrière-plan transparent au lieu d'affecter le même pinceau à la propriété "Arrière-plan" de l'élément <Border>. Plus besoin de tout le code CustomControl. Il est vrai qu'en théorie, la zone client a toujours le potentiel de dépasser le coin du coin, mais vous contrôlez ce contenu afin que vous, en tant que développeur, puissiez avoir assez de rembourrage, ou assurez-vous que la forme du le contrôle à côté du bord est approprié (dans mon cas, mes boutons sont ronds, donc s'adaptent très bien dans le coin sans aucun problème).

6

Comme Micah mentionné ClipToBounds ne fonctionnera pas avec Border.ConerRadius.

Il existe UIElement.Clip propriété, dont Border hérités.

Si vous connaissez la taille exacte de la frontière, alors voici la solution:

<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 la taille est inconnue ou dynamique puis Converter pour Border.Clip peut être utilisé. Voir la solution here.

34

XAML pur:

<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> 

Mise à jour: trouvé une meilleure façon d'obtenir le même résultat. Vous pouvez également remplacer Bordure avec tout autre élément maintenant.

<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

Pour supprimer les artefacts derrière les coins arrondis dans le premier exemple (que vous pouvez voir lorsque vous agrandissez cela avec l'outil Snoop par exemple), vous devez également lier BorderThickness (de la même manière) et définir BorderBrush sur Blanc. Cela coupera la frontière de la frontière. –

+0

Le premier exemple est plus général car il peut être transparent (la forme d'écrêtage ne doit pas être visible, avec son arrière-plan). –

1

En utilisant la solution de @ Andrew Mikhailov, vous pouvez définir une classe simple, ce qui rend la définition d'un VisualBrush pour chaque élément affecté manuellement inutile:

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); 
    } 
} 

Pour tester cela, il suffit compilez les deux échantillons suivants:

<!-- 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> 
Questions connexes