0

我想创建一个自定义控件以显示饼图。我有一个 PieSlice 类(我从 WinRT 工具包项目中获得):

public class PieSlice : Path
{
    #region StartAngle
    public static readonly DependencyProperty StartAngleProperty =
        DependencyProperty.Register(
            "StartAngle",
            typeof(double),
            typeof(PieSlice),
            new PropertyMetadata(
                0d,
                new PropertyChangedCallback(OnStartAngleChanged)));

    public double StartAngle
    {
        get { return (double)GetValue(StartAngleProperty); }
        set { SetValue(StartAngleProperty, value); }
    }

    private static void OnStartAngleChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
    {
        var target = (PieSlice)sender;
        var oldStartAngle = (double)e.OldValue;
        var newStartAngle = (double)e.NewValue;
        target.OnStartAngleChanged(oldStartAngle, newStartAngle);
    }

    private void OnStartAngleChanged(double oldStartAngle, double newStartAngle)
    {
        UpdatePath();
    }
    #endregion

    #region EndAngle
    public static readonly DependencyProperty EndAngleProperty =
        DependencyProperty.Register(
            "EndAngle",
            typeof(double),
            typeof(PieSlice),
            new PropertyMetadata(
                0d,
                new PropertyChangedCallback(OnEndAngleChanged)));

    public double EndAngle
    {
        get { return (double)GetValue(EndAngleProperty); }
        set { SetValue(EndAngleProperty, value); }
    }

    private static void OnEndAngleChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
    {
        var target = (PieSlice)sender;
        var oldEndAngle = (double)e.OldValue;
        var newEndAngle = (double)e.NewValue;
        target.OnEndAngleChanged(oldEndAngle, newEndAngle);
    }

    private void OnEndAngleChanged(double oldEndAngle, double newEndAngle)
    {
        UpdatePath();
    }
    #endregion

    #region Radius
    public static readonly DependencyProperty RadiusProperty =
        DependencyProperty.Register(
            "Radius",
            typeof(double),
            typeof(PieSlice),
            new PropertyMetadata(
                0d,
                new PropertyChangedCallback(OnRadiusChanged)));

    public double Radius
    {
        get { return (double)GetValue(RadiusProperty); }
        set { SetValue(RadiusProperty, value); }
    }

    private static void OnRadiusChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
    {
        var target = (PieSlice)sender;
        var oldRadius = (double)e.OldValue;
        var newRadius = (double)e.NewValue;
        target.OnRadiusChanged(oldRadius, newRadius);
    }

    private void OnRadiusChanged(double oldRadius, double newRadius)
    {
        this.Width = this.Height = 2 * Radius;
        UpdatePath();
    }
    #endregion

    private void UpdatePath()
    {
        var pathGeometry = new PathGeometry();
        var pathFigure = new PathFigure();
        pathFigure.StartPoint = new Point(Radius, Radius);
        pathFigure.IsClosed = true;

        // Starting Point
        var lineSegment = 
            new LineSegment 
            {
                Point = new Point(
                    Radius + Math.Sin(StartAngle * Math.PI / 180) * Radius,
                    Radius - Math.Cos(StartAngle * Math.PI / 180) * Radius)
            };

        // Arc
        var arcSegment = new ArcSegment();
        arcSegment.IsLargeArc = (EndAngle - StartAngle) >= 180.0;
        arcSegment.Point =
            new Point(
                    Radius + Math.Sin(EndAngle * Math.PI / 180) * Radius,
                    Radius - Math.Cos(EndAngle * Math.PI / 180) * Radius);
        arcSegment.Size = new Size(Radius, Radius);
        arcSegment.SweepDirection = SweepDirection.Clockwise;
        pathFigure.Segments.Add(lineSegment);
        pathFigure.Segments.Add(arcSegment);
        pathGeometry.Figures.Add(pathFigure);
        this.Data = pathGeometry;
        this.InvalidateArrange();
    }
}

现在我正在尝试创建一个可以包含多个饼图的控件

public class Pie : Control
{
    #region Items Source
    public static readonly DependencyProperty ItemsSourceProperty =
        DependencyProperty.Register(
            "ItemsSource",
            typeof(IEnumerable),
            typeof(Pie),
            new PropertyMetadata(
                null,
                new PropertyChangedCallback(OnItemsSourceChanged)));

    public IEnumerable ItemsSource
    {
        get { return (IEnumerable)GetValue(ItemsSourceProperty); }
        set { SetValue(ItemsSourceProperty, value); }
    }

    private static void OnItemsSourceChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
    {
        var target = (Pie)sender;
        var oldItemsSource = (IEnumerable)e.OldValue;
        var newItemsSource = (IEnumerable)e.NewValue;
        target.OnItemsSourceChanged(oldItemsSource, newItemsSource);
    }

    private void OnItemsSourceChanged(IEnumerable oldItemsSource, IEnumerable newItemsSource)
    {
        UpdatePieSlices();
    }
    #endregion

    public Pie()
    {
        this.DefaultStyleKey = typeof(Pie);
    }

    private void UpdatePieSlices()
    {
        double startAngle = 0;
        foreach (KeyValuePair<string, double> item in ItemsSource)
        {
            PieSlice slice = new PieSlice() 
            { 
                Fill = new SolidColorBrush(Colors.Red), 
                Radius = 100, StartAngle = startAngle, 
                EndAngle = (item.Value / 100.0) * 360 
            };
            startAngle = (item.Value / 100.0) * 360;
        }
    }
}

ItemsSource 是KeyValuePair<string, int>代表切片名称和百分比的集合。我想显示切片,但我不知道如何...

编辑 :

我已经尝试过了,但它不起作用

<Style TargetType="control:Pie">
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="control:Pie">
                    <Border
                        Background="{TemplateBinding Background}"
                        BorderBrush="{TemplateBinding BorderBrush}"
                        BorderThickness="{TemplateBinding BorderThickness}">

                        <ItemsControl
                            AutomationProperties.AutomationId="ItemGridView"
                            AutomationProperties.Name="Grouped Items"
                            ItemsSource="{Binding Path=ItemsSource}">

                            <ItemsControl.ItemTemplate>
                                <DataTemplate>
                                    <ContentControl Content="{Binding}"/>
                                </DataTemplate>
                            </ItemsControl.ItemTemplate>
                            <ItemsControl.ItemsPanel>
                                <ItemsPanelTemplate>
                                    <Grid></Grid>
                                </ItemsPanelTemplate>
                            </ItemsControl.ItemsPanel>
                        </ItemsControl>
                    </Border>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
4

1 回答 1

1

显示是控件默认外观的区域,在 XAML 中定义。

我可能要做的是让控件公开一个DependencyProperty表示切片的对象集合。每个对象都将包含足够的信息来正确显示它对应的切片,您的控件代码必须在ItemsSource更改时计算这些信息。

然后在 XAML 中,将其绑定到ItemsControl具有DataTemplate将切片描述对象绑定到实际PieSlice对象的 a 以及ItemsPanelTemplate可能只是 aGrid或 aCanvas以允许段彼此堆积的一个。

你正在做的是创建实际的PieSlice对象,这没关系,但它们必须以不同的方式显示 - 你可以将它们的集合绑定到用作它的ItemsControl,绑定到 each 。ContentControlItemTemplateContentPieSlice

<DataTemplate><ContentControl Content="{Binding}" /></DataTemplate>

在这里,有关为 WPF 和 Silverlight 创建自定义控件的信息将为您提供很好的帮助,因为 WinRT 中的基本思想和大部分技术是相同的。

于 2012-06-18T14:59:48.967 回答