How do I go about creating a circular Border
that can hold other UI elements?
Something like this:
Is there some开发者_运维问答 easy way of achieving a similar effect?
easy way to do that;
<Border x:Name="circularBorder"
CornerRadius="{Binding Path=ActualHeight, ElementName=circularBorder}"
Width="{Binding Path=ActualHeight, ElementName=circularBorder}">
</Border>
Now you have a circular border in all type of screens
This works with a 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();
}
}
with following 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>
and is used like this:
<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>
This resizes with the content. You can actually use this as a style on any ContentControl
you like.
Ideally you could just use an Ellipse
for this, but unfortunately it cannot hold content directly.
Next guess might be to create a template for your Border
, but Border
does not have a Template
property, so that's out, too...
Luckily, there is a work-round - you can use a ContentControl
, templated like this:
<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>
usage:
<ContentControl>
<Border BorderBrush="Black" BorderThickness="2" HorizontalAlignment="Center" VerticalAlignment="Center"
Height="120" Width="120">
<TextBlock FontSize="24" Text="Some Text" />
</Border>
</ContentControl>
I think if you have a border with Width=Height=X
, then setting the CornerRadius
to X/2 should give the right result.
Then the padding would be along 0.3 X to keep internal controls from crossing the edge. Might want play some with that last number, don't have time now to work it out.
You could draw circle on the background and offset its content with padding (it's thickness would be bound to size of the border).
My solution would be (but of course, Border with corner radius is simpler ):
<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>
精彩评论