如何创建 WPF 圆角容器?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/120851/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-08 19:38:17  来源:igfitidea点击:

How do I create a WPF Rounded Corner container?

wpfrounded-corners

提问by FarrEver

We are creating an XBAP application that we need to have rounded corners in various locations in a single page and we would like to have a WPF Rounded Corner container to place a bunch of other elements within. Does anyone have some suggestions or sample code on how we can best accomplish this? Either with styles on a or with creating a custom control?

我们正在创建一个 XBAP 应用程序,我们需要在单个页面的各个位置都有圆角,我们希望有一个 WPF 圆角容器来放置一堆其他元素。有没有人对我们如何最好地实现这一目标有一些建议或示例代码?是使用样式还是创建自定义控件?

回答by kobusb

You don't need a custom control, just put your container in a border element:

您不需要自定义控件,只需将容器放在边框元素中:

<Border BorderBrush="#FF000000" BorderThickness="1" CornerRadius="8">
   <Grid/>
</Border>

You can replace the <Grid/>with any of the layout containers...

您可以<Grid/>用任何布局容器替换...

回答by cplotts

I know that this isn't an answer to the initial question ... but you often want to clip the inner content of that rounded corner border you just created.

我知道这不是最初问题的答案……但是您经常想剪辑刚刚创建的圆角边框的内部内容。

Chris Cavanagh has come up with an excellent wayto do just this.

Chris Cavanagh 想出了一个很好的方法来做到这一点。

I have tried a couple different approaches to this ... and I think this one rocks.

我尝试了几种不同的方法来解决这个问题……我认为这个方法很摇滚。

Here is the xaml below:

这是下面的xaml:

<Page
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Background="Black"
>
    <!-- Rounded yellow border -->
    <Border
        HorizontalAlignment="Center"
        VerticalAlignment="Center"
        BorderBrush="Yellow"
        BorderThickness="3"
        CornerRadius="10"
        Padding="2"
    >
        <Grid>
            <!-- Rounded mask (stretches to fill Grid) -->
            <Border
                Name="mask"
                Background="White"
                CornerRadius="7"
            />

            <!-- Main content container -->
            <StackPanel>
                <!-- Use a VisualBrush of 'mask' as the opacity mask -->
                <StackPanel.OpacityMask>
                    <VisualBrush Visual="{Binding ElementName=mask}"/>
                </StackPanel.OpacityMask>

                <!-- Any content -->
                <Image Source="http://chriscavanagh.files.wordpress.com/2006/12/chriss-blog-banner.jpg"/>
                <Rectangle
                    Height="50"
                    Fill="Red"/>
                <Rectangle
                    Height="50"
                    Fill="White"/>
                <Rectangle
                    Height="50"
                    Fill="Blue"/>
            </StackPanel>
        </Grid>
    </Border>
</Page>

回答by cplotts

I just had to do this myself, so I thought I would post another answer here.

我只需要自己做这个,所以我想我会在这里发布另一个答案。

Here is another way to create a rounded corner border and clip its inner content. This is the straightforward way by using the Clip property. It's nice if you want to avoid a VisualBrush.

这是创建圆角边框并剪辑其内部内容的另一种方法。这是使用 Clip 属性的直接方法。如果您想避免使用 VisualBrush,这很好。

The xaml:

xml:

<Border
    Width="200"
    Height="25"
    CornerRadius="11"
    Background="#FF919194"
>
    <Border.Clip>
        <RectangleGeometry
            RadiusX="{Binding CornerRadius.TopLeft, RelativeSource={RelativeSource AncestorType={x:Type Border}}}"
            RadiusY="{Binding RadiusX, RelativeSource={RelativeSource Self}}"
        >
            <RectangleGeometry.Rect>
                <MultiBinding
                    Converter="{StaticResource widthAndHeightToRectConverter}"
                >
                    <Binding
                        Path="ActualWidth"
                        RelativeSource="{RelativeSource AncestorType={x:Type Border}}"
                    />
                    <Binding
                        Path="ActualHeight"
                        RelativeSource="{RelativeSource AncestorType={x:Type Border}}"
                    />
                </MultiBinding>
            </RectangleGeometry.Rect>
        </RectangleGeometry>
    </Border.Clip>

    <Rectangle
        Width="100"
        Height="100"
        Fill="Blue"
        HorizontalAlignment="Left"
        VerticalAlignment="Center"
    />
</Border>

The code for the converter:

转换器的代码:

public class WidthAndHeightToRectConverter : IMultiValueConverter
{
    public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
    {
        double width = (double)values[0];
        double height = (double)values[1];
        return new Rect(0, 0, width, height);
    }
    public object[] ConvertBack(object value, Type[] targetTypes, object parameter, System.Globalization.CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}

回答by BSalita

VB.Net code based implementation of kobusb's Border control solution. I used it to populate a ListBox of Button controls. The Button controls are created from MEF extensions. Each extension uses MEF's ExportMetaData attribute for a Description of the extension. The extensions are VisiFire charting objects. The user pushes a button, selected from the list of buttons, to execute the desired chart.

基于 VB.Net 代码的 kobusb 边境控制解决方案的实现。我用它来填充 Button 控件的 ListBox。Button 控件是从 MEF 扩展创建的。每个扩展使用 MEF 的 ExportMetaData 属性作为扩展的描述。扩展是 VisiFire 图表对象。用户按下从按钮列表中选择的按钮来执行所需的图表。

        ' Create a ListBox of Buttons, one button for each MEF charting component. 
    For Each c As Lazy(Of ICharts, IDictionary(Of String, Object)) In ext.ChartDescriptions
        Dim brdr As New Border
        brdr.BorderBrush = Brushes.Black
        brdr.BorderThickness = New Thickness(2, 2, 2, 2)
        brdr.CornerRadius = New CornerRadius(8, 8, 8, 8)
        Dim btn As New Button
        AddHandler btn.Click, AddressOf GenericButtonClick
        brdr.Child = btn
        brdr.Background = btn.Background
        btn.Margin = brdr.BorderThickness
        btn.Width = ChartsLBx.ActualWidth - 22
        btn.BorderThickness = New Thickness(0, 0, 0, 0)
        btn.Height = 22
        btn.Content = c.Metadata("Description")
        btn.Tag = c
        btn.ToolTip = "Push button to see " & c.Metadata("Description").ToString & " chart"
        Dim lbi As New ListBoxItem
        lbi.Content = brdr
        ChartsLBx.Items.Add(lbi)
    Next

Public Event Click As RoutedEventHandler

Private Sub GenericButtonClick(sender As Object, e As RoutedEventArgs)
    Dim btn As Button = DirectCast(sender, Button)
    Dim c As Lazy(Of ICharts, IDictionary(Of String, Object)) = DirectCast(btn.Tag, Lazy(Of ICharts, IDictionary(Of String, Object)))
    Dim w As Window = DirectCast(c.Value, Window)
    Dim cc As ICharts = DirectCast(c.Value, ICharts)
    c.Value.CreateChart()
    w.Show()
End Sub

<System.ComponentModel.Composition.Export(GetType(ICharts))> _
<System.ComponentModel.Composition.ExportMetadata("Description", "Data vs. Time")> _
Public Class DataTimeChart
    Implements ICharts

    Public Sub CreateChart() Implements ICharts.CreateChart
    End Sub
End Class

Public Interface ICharts
    Sub CreateChart()
End Interface

Public Class Extensibility
    Public Sub New()
        Dim catalog As New AggregateCatalog()

        catalog.Catalogs.Add(New AssemblyCatalog(GetType(Extensibility).Assembly))

        'Create the CompositionContainer with the parts in the catalog
        ChartContainer = New CompositionContainer(catalog)

        Try
            ChartContainer.ComposeParts(Me)
        Catch ex As Exception
            Console.WriteLine(ex.ToString)
        End Try
    End Sub

    ' must use Lazy otherwise instantiation of Window will hold open app. Otherwise must specify Shutdown Mode of "Shutdown on Main Window".
    <ImportMany()> _
    Public Property ChartDescriptions As IEnumerable(Of Lazy(Of ICharts, IDictionary(Of String, Object)))

End Class

回答by Daniel

If you're trying to put a button in a rounded-rectangle border, you should check out msdn's example. I found this by googling for images of the problem (instead of text). Their bulky outer rectangle is (thankfully) easy to remove.

如果您尝试将按钮放在圆角矩形边框中,则应查看msdn 的示例。我通过谷歌搜索问题的图像(而不是文本)发现了这一点。它们庞大的外部矩形(谢天谢地)很容易移除。

Note that you will have to redefine the button's behavior (since you've changed the ControlTemplate). That is, you will need to define the button's behavior when clicked using a Trigger tag (Property="IsPressed" Value="true") in the ControlTemplate.Triggers tag. Hope this saves someone else the time I lost :)

请注意,您必须重新定义按钮的行为(因为您已经更改了 ControlTemplate)。也就是说,您需要使用 ControlTemplate.Triggers 标记中的 Trigger 标记(Property="IsPressed" Value="true")定义单击时按钮的行为。希望这可以节省其他人我失去的时间:)