Как создать контейнер с закругленными углами WPF? - PullRequest
103 голосов
/ 23 сентября 2008

Мы создаем приложение XBAP, в котором нам нужно иметь закругленные углы в разных местах на одной странице, и мы хотели бы иметь контейнер WPF с закругленными углами для размещения в нем группы других элементов. У кого-нибудь есть какие-либо предложения или примеры кода о том, как мы можем лучше всего это сделать? Или со стилями на или с созданием пользовательского элемента управления?

Ответы [ 5 ]

239 голосов
/ 23 сентября 2008

Вам не нужен пользовательский элемент управления, просто поместите свой контейнер в элемент границы:

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

Вы можете заменить <Grid/> любым из контейнеров макетов ...

49 голосов
/ 16 октября 2008

Я знаю, что это не ответ на первоначальный вопрос ... но вы часто хотите обрезать внутреннее содержание той границы закругленного угла, которую вы только что создали.

Крис Кавана придумал отличный способ сделать именно это.

Я испробовал несколько разных подходов к этому ... и я думаю, что это круто.

Вот 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>
13 голосов
/ 04 августа 2011

Мне просто нужно было сделать это самому, поэтому я решил опубликовать другой ответ здесь.

Вот еще один способ создать границу с закругленными углами и обрезать ее внутреннее содержимое . Это простой способ использования свойства Clip. Хорошо, если вы хотите избежать VisualBrush.

XAML:

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

Код для конвертера:

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();
    }
}
2 голосов
/ 22 августа 2012

Внедрение на основе кода VB.Net решения Kobusb Border Control Я использовал его для заполнения ListBox элементов управления Button. Элементы управления 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
1 голос
/ 06 мая 2010

Если вы пытаетесь поместить кнопку в рамку прямоугольника с закругленными углами, вам следует проверить пример msdn . Я нашел это, прибегая к помощи картинок проблемы (вместо текста). Их громоздкий внешний прямоугольник (к счастью) легко удалить.

Обратите внимание, что вам придется переопределить поведение кнопки (поскольку вы изменили шаблон ControlTemplate). То есть вам нужно определить поведение кнопки при нажатии, используя тег Trigger (Property = "IsPressed" Value = "true") в теге ControlTemplate.Triggers. Надеюсь, это сэкономит кому-то еще время, которое я потерял :)

...