Ich hab da noch eine Variante von mir. Dieser kann per Data Binding ein Radius, ein Winkel mitgegeben werden, als auch eine Information, ob die Elemente selbst auch im Kreis angeordnet werden sollen.
using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
namespace DotNetGui.Controls.CirclePanel
{
public class CirclePresentationPanel : Panel
{
#region Attributes
private Double _right;
private Double _left;
private Double _top;
private Double _bottom;
#endregion Attributes
#region Properties
public static readonly DependencyProperty RotateProperty = DependencyProperty.Register("Rotate", typeof(bool), typeof(CirclePresentationPanel), new FrameworkPropertyMetadata(false, FrameworkPropertyMetadataOptions.AffectsMeasure));
public bool Rotate
{
get { return (bool)GetValue(RotateProperty); }
set { SetValue(RotateProperty, value); }
}
public static readonly DependencyProperty AngleProperty = DependencyProperty.Register("Angle", typeof(Double), typeof(CirclePresentationPanel), new FrameworkPropertyMetadata(0d, FrameworkPropertyMetadataOptions.AffectsMeasure));
public Double Angle
{
get { return (Double)GetValue(AngleProperty); }
set { SetValue(AngleProperty, value); }
}
public static readonly DependencyProperty RadiusProperty = DependencyProperty.Register("Radius", typeof(Double), typeof(CirclePresentationPanel), new FrameworkPropertyMetadata(0d, FrameworkPropertyMetadataOptions.AffectsMeasure));
public Double Radius
{
get { return (Double)GetValue(RadiusProperty); }
set { SetValue(RadiusProperty, value); }
}
#endregion Properties
#region Overrides
protected override Size MeasureOverride(Size availableSize)
{
Double angleChild = this.Angle / this.Children.Count;
Double angle = this.Angle / (-2);
Double angleRadiant;
Point point1;
Point point2;
Point point3;
Point point4;
_top = this.Radius * -1;
_bottom = this.Radius * -1;
_left = 0;
_right = 0;
foreach (UIElement element in this.Children)
{
element.Measure(new Size(Double.PositiveInfinity, Double.PositiveInfinity));
angleRadiant = (-1 * angle + 90) * Math.PI / 180;
point1 = new Point(Math.Cos(angleRadiant) * (this.Radius + element.DesiredSize.Height) + element.DesiredSize.Width / 2 * Math.Sin(angleRadiant), (Math.Sin(angleRadiant) * (this.Radius + element.DesiredSize.Height) - element.DesiredSize.Width / 2 * Math.Cos(angleRadiant)) * -1);
point2 = new Point(Math.Cos(angleRadiant) * (this.Radius + element.DesiredSize.Height) - element.DesiredSize.Width / 2 * Math.Sin(angleRadiant), (Math.Sin(angleRadiant) * (this.Radius + element.DesiredSize.Height) + element.DesiredSize.Width / 2 * Math.Cos(angleRadiant)) * -1);
point3 = new Point(Math.Cos(angleRadiant) * this.Radius - element.DesiredSize.Width / 2 * Math.Sin(angleRadiant), (Math.Sin(angleRadiant) * this.Radius + element.DesiredSize.Width / 2 * Math.Cos(angleRadiant)) * -1);
point4 = new Point(Math.Cos(angleRadiant) * this.Radius + element.DesiredSize.Width / 2 + Math.Sin(angleRadiant), (Math.Sin(angleRadiant) * this.Radius - element.DesiredSize.Width / 2 * Math.Cos(angleRadiant)) * -1);
_top = Math.Min(Math.Min(Math.Min(Math.Min(_top, point1.Y), point2.Y), point3.Y), point4.Y);
_bottom = Math.Max(Math.Max(Math.Max(Math.Max(_bottom, point1.Y), point2.Y), point3.Y), point4.Y);
_left = Math.Min(Math.Min(Math.Min(Math.Min(_left, point1.X), point2.X), point3.X), point4.X);
_right = Math.Max(Math.Max(Math.Max(Math.Max(_right, point1.X), point2.X), point3.X), point4.X);
angle += angleChild;
}
return new Size(Math.Min(_right - _left, availableSize.Width), Math.Min(_bottom - _top, availableSize.Height));
}
protected override Size ArrangeOverride(Size finalSize)
{
Double angleRadiant;
Double angleChild = this.Angle / (this.Children.Count);
Double angle = this.Angle / -2;
foreach (UIElement element in this.Children)
{
angleRadiant = (angle - 90) * Math.PI / 180;
Rect rect = new Rect(new Point(0, 0), new Size(element.DesiredSize.Width, element.DesiredSize.Height));
element.Arrange(rect);
TransformGroup transformGroup = new TransformGroup();
if (this.Rotate)
transformGroup.Children.Add(new RotateTransform(angle, element.DesiredSize.Width / 2, element.DesiredSize.Height));
transformGroup.Children.Add(new TranslateTransform(Math.Cos(angleRadiant) * this.Radius - element.DesiredSize.Width / 2 - _left, Math.Sin(angleRadiant) * this.Radius - element.DesiredSize.Height - _top));
element.RenderTransform = transformGroup;
angle += angleChild;
}
return finalSize;
}
#endregion Overrides
}
}
Ein Demo-Fenster könnte so aussehen:
<Window x:Class="DotNetGui.Controls.CircelPanel.Demo.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:DotNetGui.Controls.CirclePanel;assembly=DotNetGui.Controls.CirclePanel"
Title="Circle Presentation Panel Demo" Height="544" Width="352">
<Window.Resources>
<Style TargetType="{x:Type Image}">
<Setter Property="Width" Value="75"/>
</Style>
<Style x:Key="TitleStyle" TargetType="{x:Type TextBlock}">
<Setter Property="Margin" Value="25"/>
<Setter Property="FontSize" Value="14"/>
<Setter Property="FontWeight" Value="Bold"/>
</Style>
</Window.Resources>
<StackPanel Orientation="Vertical">
<TextBlock Text="Circle Presentation Panel Demo" HorizontalAlignment="Center" Style="{StaticResource TitleStyle}"/>
<TextBlock Text="Radius (valid Range: 10 - 500)"/>
<Slider x:Name="RadiusSlider" Maximum="500" Minimum="10"/>
<TextBlock Text="Angle (valid Range: 0 - 360)"/>
<Slider x:Name="AngleSlider" Maximum="360" Minimum="0"/>
<TextBlock Text="Rotation"/>
<ComboBox x:Name="RotateBox">
<ComboBoxItem Content="True"/>
<ComboBoxItem Content="False" IsSelected="True"/>
</ComboBox>
<local:CirclePresentationPanel Radius="{Binding ElementName=RadiusSlider, Path=Value}" Angle="{Binding ElementName=AngleSlider,Path=Value}" Margin="20" Rotate="{Binding ElementName=RotateBox,Path=Text}">
<Image Source="Images/1.jpg"/>
<Image Source="Images/2.jpg"/>
<Image Source="Images/3.jpg"/>
<Image Source="Images/4.jpg"/>
<Image Source="Images/5.jpg"/>
<Image Source="Images/6.jpg"/>
</local:CirclePresentationPanel>
</StackPanel>
</Window>
Wie dies dann aussieht, ist im Anhang ersichtlich. Verbesserungsmöglichkeiten sind natürlich gegeben.