programing

둥근 모서리 테두리의 내용물도 둥근 모서리로 만드는 방법은 무엇입니까?

showcode 2023. 5. 5. 10:02
반응형

둥근 모서리 테두리의 내용물도 둥근 모서리로 만드는 방법은 무엇입니까?

3x3 격자를 포함하는 둥근 모서리의 테두리 요소가 있습니다.그리드의 모서리가 테두리 밖으로 돌출되어 있습니다.어떻게 고칠 수 있을까요?ClipToBounds를 사용해봤지만 아무 것도 되지 않았습니다.도와주셔서 고마워요.

다음은 Jobi가 언급한 이 스레드의 하이라이트입니다.

  • 장식기(예: 테두리) 또는 레이아웃 패널(예: 스택 패널)은 이러한 동작을 즉시 제공하지 않습니다.
  • ClipToBounds는 레이아웃용입니다.ClipToBounds는 요소가 경계 밖으로 그려지는 것을 방지하지 않으며, 하위 레이아웃이 '흘리는' 것을 방지합니다.추가로 ClipToBounds=대부분의 요소에는 True가 필요하지 않습니다. 구현을 통해 콘텐츠 레이아웃이 유출되지 않기 때문입니다.가장 주목할 만한 예외는 캔버스입니다.
  • 마지막으로 테두리는 둥근 모서리를 배치 경계 내의 도면으로 간주합니다.

다음은 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;
    }

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

업데이트: 동일한 결과를 얻을 수 있는 더 나은 방법을 찾았습니다.이제 테두리를 다른 요소로 바꿀 수도 있습니다.

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

예

마이카가 언급했듯이ClipToBounds 않하음지와 함께 .Border.ConerRadius.

UI 요소가 있습니다.클립 속성, 다음 중 하나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사용할 수 있습니다.여기에서 솔루션을 확인하십시오.

그래서 저는 이 해결책을 우연히 발견했고, 조비가 제공한 msdn 포럼 링크를 따라가서 20분 동안 저만의 클리핑 보더 컨트롤을 작성했습니다.

그때 나는 CornerRadius 속성 유형이 이중이 아니라 System이라는 것을 깨달았습니다.창문들.각 코너마다 하나씩, 4개의 더블을 허용하는 코너라듀.

그래서 저는 지금 다른 대안을 열거할 것입니다. 그것은 미래에 이 게시물을 우연히 발견하게 될 대부분의 사람들의 요구 사항을 충족시킬 것입니다.

다음과 같은 XAML이 있다고 가정합니다.

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

그리고 문제는 그리드 요소의 배경이 피를 흘리며 둥근 모서리를 지나간다는 것입니다.다음 항목을 확인합니다.<Grid>에서는 "Background"의 "한 배경을 합니다.<Border>원소의더 이상 코너를 지나 출혈이 없고 사용자 지정 컨트롤 코드를 모두 사용할 필요가 없습니다.

이론적으로, 클라이언트 영역은 여전히 모서리의 가장자리를 지나 그릴 수 있는 잠재력이 있지만, 개발자로서 충분한 패딩을 가질 수 있도록 콘텐츠를 제어하거나 가장자리 옆에 있는 컨트롤의 모양이 적절한지 확인합니다(내 경우, 내 단추는 둥글고,구석에 아무 문제 없이 매우 잘 맞습니다.)

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

그리드를 더 작게 만들거나 테두리를 더 크게 만듭니다.경계 요소가 그리드를 완전히 포함하도록 합니다.

또는 그리드의 배경을 투명하게 만들어 "눈에 띄는" 부분이 눈에 띄지 않도록 할 수 있는지 확인합니다.

업데이트: 이런, 이것이 WPF 질문이라는 것을 알아차리지 못했습니다.저는 그것에 익숙하지 않습니다.이것은 일반적인 HTML/CSS 조언이었습니다.도움이 될지도...

사용자 지정 컨트롤을 사용하는 것을 좋아하지 않습니다.대신 동작을 만들었습니다.

using System.Linq;
using System.Windows;
using System.Windows.Interactivity;

/// <summary>
/// Base class for behaviors that could be used in style.
/// </summary>
/// <typeparam name="TComponent">Component type.</typeparam>
/// <typeparam name="TBehavior">Behavior type.</typeparam>
public class AttachableForStyleBehavior<TComponent, TBehavior> : Behavior<TComponent>
        where TComponent : System.Windows.DependencyObject
        where TBehavior : AttachableForStyleBehavior<TComponent, TBehavior>, new()
{
#pragma warning disable SA1401 // Field must be private.

    /// <summary>
    /// IsEnabledForStyle attached property.
    /// </summary>
    public static DependencyProperty IsEnabledForStyleProperty =
        DependencyProperty.RegisterAttached("IsEnabledForStyle", typeof(bool),
        typeof(AttachableForStyleBehavior<TComponent, TBehavior>), new FrameworkPropertyMetadata(false, OnIsEnabledForStyleChanged));

#pragma warning restore SA1401

    /// <summary>
    /// Sets IsEnabledForStyle value for element.
    /// </summary>
    public static void SetIsEnabledForStyle(UIElement element, bool value)
    {
        element.SetValue(IsEnabledForStyleProperty, value);
    }

    /// <summary>
    /// Gets IsEnabledForStyle value for element.
    /// </summary>
    public static bool GetIsEnabledForStyle(UIElement element)
    {
        return (bool)element.GetValue(IsEnabledForStyleProperty);
    }

    private static void OnIsEnabledForStyleChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        UIElement uie = d as UIElement;

        if (uie != null)
        {
            var behColl = Interaction.GetBehaviors(uie);
            var existingBehavior = behColl.FirstOrDefault(b => b.GetType() ==
                  typeof(TBehavior)) as TBehavior;

            if ((bool)e.NewValue == false && existingBehavior != null)
            {
                behColl.Remove(existingBehavior);
            }
            else if ((bool)e.NewValue == true && existingBehavior == null)
            {
                behColl.Add(new TBehavior());
            }
        }
    }
}

using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Media;

/// <summary>
/// Behavior that creates opacity mask brush.
/// </summary>
internal class OpacityMaskBehavior : AttachableForStyleBehavior<Border, OpacityMaskBehavior>
{
    protected override void OnAttached()
    {
        base.OnAttached();

        var border = new Border()
        {
            Background = Brushes.Black,
            SnapsToDevicePixels = true,
        };

        border.SetBinding(Border.CornerRadiusProperty, new Binding()
        {
            Mode = BindingMode.OneWay,
            Path = new PropertyPath("CornerRadius"),
            Source = AssociatedObject
        });

        border.SetBinding(FrameworkElement.HeightProperty, new Binding()
        {
            Mode = BindingMode.OneWay,
            Path = new PropertyPath("ActualHeight"),
            Source = AssociatedObject
        });

        border.SetBinding(FrameworkElement.WidthProperty, new Binding()
        {
            Mode = BindingMode.OneWay,
            Path = new PropertyPath("ActualWidth"),
            Source = AssociatedObject
        });

        AssociatedObject.OpacityMask = new VisualBrush(border);
    }

    protected override void OnDetaching()
    {
        base.OnDetaching();

        AssociatedObject.OpacityMask = null;
    }
}

<Style x:Key="BorderWithRoundCornersStyle" TargetType="{x:Type Border}">
    <Setter Property="CornerRadius" Value="50" />
    <Setter Property="behaviors:OpacityMaskBehavior.IsEnabledForStyle" Value="True" />
</Style>

언급URL : https://stackoverflow.com/questions/324641/how-to-make-the-contents-of-a-round-cornered-border-be-also-round-cornered

반응형