¿Cómo creo un contenedor WPF de esquinas redondeadas?
-
02-07-2019 - |
Pregunta
Estamos creando una aplicación XBAP que necesitamos tener esquinas redondeadas en varias ubicaciones en una sola página y nos gustaría tener un contenedor WPF de esquinas redondeadas para colocar muchos otros elementos dentro.¿Alguien tiene algunas sugerencias o código de muestra sobre cómo podemos lograr esto mejor?¿Ya sea con estilos en a o creando un control personalizado?
Solución
No necesitas un control personalizado, simplemente coloca tu contenedor en un elemento de borde:
<Border BorderBrush="#FF000000" BorderThickness="1" CornerRadius="8">
<Grid/>
</Border>
Puedes reemplazar el <Grid/>
con cualquiera de los contenedores de diseño...
Otros consejos
Sé que esta no es una respuesta a la pregunta inicial...pero a menudo querrás recortar el contenido interno de ese borde de esquina redondeada que acabas de crear.
Chris Cavanagh ha ideado una excelente manera para hacer precisamente esto.
He probado un par de enfoques diferentes para esto...y creo que este es genial.
Aquí está el siguiente 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>
Tenía que hacerlo yo mismo, así que pensé en publicar otra respuesta aquí.
Aquí hay otra forma de crear un borde de esquina redondeada. y recortar su contenido interno.Esta es la forma más sencilla de utilizar la propiedad Clip.Es bueno si quieres evitar VisualBrush.
El 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>
El código para el convertidor:
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();
}
}
Implementación basada en código VB.Net de la solución de control de fronteras de kobusb.Lo usé para completar un ListBox de controles de botones.Los controles de botón se crean a partir de extensiones MEF.Cada extensión utiliza el atributo ExportMetaData de MEF para una descripción de la extensión.Las extensiones son objetos de gráficos VisiFire.El usuario presiona un botón, seleccionado de la lista de botones, para ejecutar el gráfico deseado.
' 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
Si estás intentando poner un botón en un borde de rectángulo redondeado, deberías consultar ejemplo de msdn.Encontré esto buscando en Google imágenes del problema (en lugar de texto).Su voluminoso rectángulo exterior es (afortunadamente) fácil de quitar.
Tenga en cuenta que tendrá que redefinir el comportamiento del botón (ya que cambió ControlTemplate).Es decir, deberá definir el comportamiento del botón cuando se haga clic usando una etiqueta Trigger (Property="IsPressed" Value="true") en la etiqueta ControlTemplate.Triggers.Espero que esto le ahorre a alguien más el tiempo que perdí :)