У меня есть элемент границы с закругленными углами, содержащими сетку 3x3. Уголки сетки торчат из границы. Как я могу это исправить? Я пробовал использовать ClipToBounds, но ничего не получал. Спасибо за вашу помощь.
Как сделать содержимое округлой границы также круглым?
Ответ 1
Вот основные моменты этой темы, упомянутой Jobi
- Ни один из декораторов (например, границы) или панелей компоновки (например, Stackpanel) не приходит с этим поведением из коробки.
- ClipToBounds предназначен для макета. ClipToBounds не препятствует рисованию элемента за пределами его границ; это просто мешает детским макетам "проливать". Кроме того, ClipToBounds = True не требуется для большинства элементов, потому что их реализация не позволяет их макет контента разливать в любом случае. Наиболее заметным исключением является Canvas.
- Наконец, Border рассматривает закругленные углы как чертежи внутри границ его макета.
Вот реализация класса, который наследует от Border и реализует правильную функциональность:
/// <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;
}
Ответ 2
Чистый XAML:
<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>
Update: Нашел лучший способ добиться того же результата. Вы также можете заменить Border на любой другой элемент.
<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>
Ответ 3
Итак, я просто наткнулся на это решение, а затем зашел в ссылку форума msdn, которую Jobi предоставил и потратил 20 минут на мой собственный элемент ClippingBorder.
Тогда я понял, что тип свойства CornerRadius не является двойным, а System.Windows.CornerRaduis, который принимает 4 удвоения, по одному для каждого угла.
Итак, я собираюсь перечислить еще одно альтернативное решение, которое, скорее всего, удовлетворит требования большинства людей, которые наткнутся на этот пост в будущем...
Скажем, у вас есть XAML, который выглядит так:
<Border CornerRadius="10">
<Grid>
... your UI ...
</Grid>
</Border>
И проблема в том, что фон для элемента Grid пропускает и просматривает закругленные углы. Убедитесь, что ваш <Grid>
имеет прозрачный фон вместо того, чтобы назначать одну и ту же кисть для свойства "Background" элемента <Border>
. Больше нет кровотечений за углами и нет необходимости в целую кучу кода CustomControl.
Правда, теоретически, клиентская область по-прежнему имеет потенциал прохода за край угла, но вы контролируете этот контент, чтобы вы, как разработчик, могли либо иметь достаточное дополнение, либо убедиться, что форма элемента управления рядом с краем уместно (в моем случае, мои кнопки круглые, поэтому очень удобно в углу без проблем).
Ответ 4
Как упоминал Мика ClipToBounds
не будет работать с Border.ConerRadius
.
Существует UIElement.Clip свойство, которое Border
наследования.
Если вы знаете точный размер границы, то вот решение:
<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>
Если размер неизвестен или динамичен, тогда можно использовать Converter
для Border.Clip
. См. Решение здесь.
Ответ 5
Используя решение @Andrew Mikhailov, вы можете определить простой класс, который делает ненужным определение VisualBrush
для каждого затронутого элемента вручную:
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);
}
}
Чтобы проверить это, просто скомпилируйте следующие два примера:
<!-- 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>
Ответ 6
Сделать сетку меньшей или увеличить границу. Чтобы элемент границы полностью содержал сетку.
Альтернативно, посмотрите, можно ли сделать фон сетки прозрачным, чтобы "торчащий" не был заметен.
Обновление: Ой, не заметил, что это вопрос WPF. Я не знаком с этим. Это был общий совет HTML/CSS. Может быть, это помогает...