簡體   English   中英

帶形狀的CustomControl

[英]CustomControl with shapes

我想創建一個自定義控件以顯示餅圖。 我有一個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>

顯示內容是XAML中定義的控件默認外觀的部分。

我可能要做的就是獲取暴露DependencyProperty的控件,該DependencyProperty是代表切片的對象的集合。 每個對象將包含足夠的信息以正確顯示其對應的切片,而ItemsSource更改時,控件的代碼將必須計算這些切片。

然后在XAML,結合,為一個ItemsControl具有DataTemplate結合所述切片描述對象實際PieSlice對象,以及一個ItemsPanelTemplate這可能只是一個GridCanvas ,以允許多個節段堆積在彼此周圍。

您正在執行的操作是創建實際的PieSlice對象,這沒關系,但是必須以不同的方式顯示它們-您可以將它們的集合綁定到使用ContentControl作為其ItemTemplateItemsControl ,並將Content綁定到每個PieSlice

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

有關為WPF和Silverlight創建自定義控件的信息將在這里為您提供很好的服務,因為基本思想和許多技術在WinRT中都是相同的。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM