126 votes

Comment créer un conteneur WPF à coins arrondis ?

Nous sommes en train de créer une application XBAP dans laquelle nous avons besoin d'avoir des coins arrondis à différents endroits dans une seule page et nous aimerions avoir un conteneur WPF Rounded Corner pour y placer un tas d'autres éléments. Quelqu'un a-t-il des suggestions ou des exemples de code sur la meilleure façon de réaliser ceci ? Soit avec des styles sur un ou en créant un contrôle personnalisé ?

286voto

kobusb Points 1917

Vous n'avez pas besoin d'un contrôle personnalisé, il suffit de placer votre conteneur dans un élément de bordure :

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

Vous pouvez remplacer le <Grid/> avec l'un des conteneurs de mise en page...

57voto

cplotts Points 7630

Je sais que ce n'est pas une réponse à la question initiale ... mais vous voulez souvent découper le contenu intérieur de la bordure à coins arrondis que vous venez de créer.

Chris Cavanagh est venu avec une excellent moyen pour faire cela.

J'ai essayé plusieurs approches différentes à ce sujet... et je pense que celle-ci est géniale.

Voici le xaml ci-dessous :

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

18voto

cplotts Points 7630

J'ai dû le faire moi-même, alors j'ai pensé poster une autre réponse ici.

Voici une autre façon de créer une bordure d'angle arrondi et clipsez son contenu interne . C'est le moyen le plus simple d'utiliser la propriété Clip. C'est bien si vous voulez éviter un VisualBrush.

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

Le code du convertisseur :

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

2voto

BSalita Points 933

Mise en œuvre en code VB.Net de la solution de contrôle des frontières de kobusb. Je l'ai utilisé pour remplir une ListBox de contrôles de boutons. Les contrôles de boutons sont créés à partir d'extensions MEF. Chaque extension utilise l'attribut ExportMetaData du MEF pour une description de l'extension. Les extensions sont des objets graphiques VisiFire. L'utilisateur appuie sur un bouton, sélectionné dans la liste de boutons, pour exécuter le graphique souhaité.

        ' 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

1voto

Daniel Points 416

Si vous essayez de placer un bouton dans une bordure en forme de rectangle arrondi, vous devriez consulter le document suivant L'exemple de msdn . Je l'ai trouvé en cherchant sur Google des images du problème (au lieu du texte). Leur rectangle extérieur encombrant est (heureusement) facile à enlever.

Notez que vous devrez redéfinir le comportement du bouton (puisque vous avez modifié le ControlTemplate). En d'autres termes, vous devrez définir le comportement du bouton lorsqu'il est cliqué en utilisant une balise Trigger (Property="IsPressed" Value="true") dans la balise ControlTemplate.Triggers. J'espère que cela fera gagner à quelqu'un d'autre le temps que j'ai perdu :)

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X