2011-03-03 10 views
13

¿Cómo hago para crear una circular Border que pueda contener otros elementos de la interfaz de usuario?WPF Circular Border

Algo como esto: enter image description here

¿Hay alguna forma fácil de lograr un efecto similar?

Respuesta

5

esto funciona con un MultiValueConverter:

public class CircleMarginConverter : IMultiValueConverter 
{ 
    public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture) 
    { 
     var width = (double)values[0]; 
     var height = (double)values[1]; 
     var diagonal = Math.Sqrt(width * width + height * height); 
     var horzmargin = (diagonal - width)/2; 
     var vertmargin = (diagonal - height)/2; 
     return new Thickness(horzmargin,vertmargin,horzmargin,vertmargin); 
    } 

    public object[] ConvertBack(object value, Type[] targetTypes, object parameter, System.Globalization.CultureInfo culture) 
    { 
     throw new NotImplementedException(); 
    } 
} 

con siguiente Usercontrol:

<UserControl x:Class="CircleBorderTest.CircleBorder" 
      xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
      xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
      xmlns:local="clr-namespace:CircleBorderTest" 
      xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
      mc:Ignorable="d" 
      d:DesignHeight="300" d:DesignWidth="300"> 
    <UserControl.ContentTemplate> 
     <DataTemplate DataType="UserControl"> 
      <DataTemplate.Resources> 
       <local:CircleMarginConverter x:Key="CircleMarginConverter"/> 
      </DataTemplate.Resources> 
      <Grid VerticalAlignment="Center" HorizontalAlignment="Center"> 
       <ContentPresenter Content="{TemplateBinding Content}"> 
        <ContentPresenter.Margin> 
         <MultiBinding Converter="{StaticResource CircleMarginConverter}"> 
          <Binding Path="ActualWidth" RelativeSource="{RelativeSource Self}"/> 
          <Binding Path="ActualHeight" RelativeSource="{RelativeSource Self}"/> 
         </MultiBinding> 
        </ContentPresenter.Margin> 
       </ContentPresenter> 
       <Ellipse HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Stroke="Red" StrokeThickness="1px"/> 
      </Grid>    
     </DataTemplate> 
    </UserControl.ContentTemplate> 
</UserControl> 

y se usa de esta manera:

<Window x:Class="CircleBorderTest.MainWindow" 
     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
     xmlns:local="clr-namespace:CircleBorderTest" 
     Title="MainWindow" Height="350" Width="525"> 
    <local:CircleBorder> 
     yeah 
    </local:CircleBorder> 
</Window> 

Esto cambia el tamaño con el contenido. Realmente puede usar esto como un estilo en cualquier ContentControl que desee.

+1

Aunque lo hice de manera ligeramente diferente, trabajé en el mismo principio, así que estoy marcando esto como una respuesta. Para cualquier persona interesada, para un cuadro de texto con ancho = W y alto = H, una elipse delimitadora tendrá ancho = W * sqrt (2) y alto = H * sqrt (2) – NVM

+0

¡Eres un mago! ¡Gracias por esto! –

1

Puede dibujar un círculo en el fondo y compensar su contenido con relleno (su grosor se vinculará al tamaño del borde).

1

Creo que si tiene un borde con Width=Height=X, establecer el CornerRadius en X/2 debería dar el resultado correcto.

Luego, el relleno sería a lo largo de 0.3 X para evitar que los controles internos crucen el borde. Puede que quiera jugar un poco con ese último número, no tengo tiempo ahora para resolverlo.

4

Idealmente, podría usar un Ellipse para esto, pero desafortunadamente no puede contener contenido directamente.

siguiente conjetura podría ser la creación de una plantilla para su Border, pero Border no tiene una propiedad Template, por lo que está fuera, también ...

Por suerte, hay un trabajo de todo el año - se puede utilizar una ContentControl, con plantilla de esta manera:

 <Style TargetType="ContentControl"> 
      <Setter Property="Template"> 
       <Setter.Value> 
        <ControlTemplate TargetType="ContentControl"> 
         <Grid> 
          <Ellipse 
       Width="{TemplateBinding Width}" Height="{TemplateBinding Height}" Stroke="Red" StrokeThickness="3"> 
           <Ellipse.Effect> 
            <DropShadowEffect 
         BlurRadius="18" Direction="-20" ShadowDepth="12" /> 
           </Ellipse.Effect> 
          </Ellipse> 
          <ContentPresenter 
           HorizontalAlignment="Center" VerticalAlignment="Center" /> 
         </Grid> 
        </ControlTemplate> 
       </Setter.Value> 
      </Setter> 
     </Style> 

uso:

<ContentControl> 
     <Border BorderBrush="Black" BorderThickness="2" HorizontalAlignment="Center" VerticalAlignment="Center" 
        Height="120" Width="120"> 
      <TextBlock FontSize="24" Text="Some Text" /> 
     </Border> 
    </ContentControl> 
+0

no quiero tamaño codificado de elipse Debería expandirse como un borde. – NVM

+0

Aquí es donde TemplateBinding puede ayudar: ha actualizado la respuesta – kiwipom

+0

La elipse y el contenido se superpondrán. – NVM

34

manera fácil de hacer eso;

<Border x:Name="circularBorder" 
    CornerRadius="{Binding Path=ActualHeight, ElementName=circularBorder}" 
    Width="{Binding Path=ActualHeight, ElementName=circularBorder}"> 
</Border> 

Ahora usted tienen un borde circular en todo tipo de pantallas

+0

easist way entre las respuestas – jharr100

+0

Esto es muy bueno. No sabía que podrías unirte a ti mismo. ¡Gracias! – newman

0

Mi solución sería (pero, por supuesto, Frontera con radio de esquina es más simple):

<Border Margin="0,15,0,0" Height="75" Width="75"> 
    <Grid Width="{Binding Path=ActualWidth, RelativeSource={RelativeSource PreviousData}}" 
    Height="{Binding Path=ActualHeight, RelativeSource={RelativeSource PreviousData}}" > 
    <Ellipse Width="{Binding Path=Width, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=Border}}" 
     Height="{Binding Path=Height, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=Border}}" 
     Stroke="White" StrokeThickness="1"/> 
     <Border Width="{Binding Path=Width, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=Border}}" 
      Height="{Binding Path=Height, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=Border}}" 
      VerticalAlignment="Center" HorizontalAlignment="Center"> 
      <TextBlock HorizontalAlignment="Center" VerticalAlignment="Center" Margin="0,0,1,1"> 
       <StackPanel Orientation="Vertical" HorizontalAlignment="Center" > 
        <TextBlock Foreground="White" FontSize="18" FontFamily="{StaticResource RobotoFont}" 
          FontWeight="DemiBold" 
          HorizontalAlignment="Center" Text="0"/> 
        <TextBlock Foreground="White" FontSize="12" FontFamily="{StaticResource ResourceKey=RobotoFont}" FontStyle="Normal" 
           HorizontalAlignment="Center" Text="Selected"/> 
       </StackPanel> 
      </TextBlock> 
     </Border> 
    </Grid> 
</Border>