2012-06-18 197 views
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> 

回答

1

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

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

然后在XAML,结合,为一个ItemsControl具有DataTemplate结合所述切片描述对象实际PieSlice对象,以及一个ItemsPanelTemplate这可能只是一个GridCanvas以允许多个节段堆积起来围绕每个其他。

你在做什么是创建实际PieSlice对象,这是好的,但他们以不同的方式显示 - 你可以将它们集合绑定到使用ContentControl作为其ItemTemplateItemsControl,结合Content每个PieSlice

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

有关创建WPF和Silverlight自定义控件会以及在这里为您服务,为基本思想和许多技术的信息,可以在WinRT中相同。

+0

你能提供更多的细节吗?我用xaml编辑了我的帖子,但它仍然不起作用 – Peekyou

+0

确定它现在可用!谢谢:) – Peekyou

+0

@Peekyou你能否用你的最终工作解决方案编辑你的问题?谢谢。 – 2012-10-04 16:21:18