none
使用System.Windows.Controls.DataVisualization.Charting中遇到的问题,求解答.. RRS feed

  • 问题

  • RT,在使用该命名空间下Chart控件时遇到问题。使用PieSeries制作饼状图时能否将背景设为透明?

    xmlns:dc ="clr-namespace:System.Windows.Controls.DataVisualization.Charting;assembly=System.Windows.Controls.DataVisualization.Toolkit"
    xmlns:dv="clr-namespace:System.Windows.Controls.DataVisualization;assembly=System.Windows.Controls.DataVisualization.Toolkit"

    <Grid>
      <dc:Chart Background="Transparent">
        <dc:Chart.Series>
          <dc:PieSeries Background="Transparent" Title="Pie" IndependentValueBinding="{Binding Path=Key}" DependentValueBinding="{Binding Path=Value}">
          </dc:PieSeries>
        </dc:Chart.Series>
      </dc:Chart>
    </Grid>

    如上设置后,还是存在一块白色背底,如何能将其去掉呢?

    PS:这个控件库下是否有圆环图? 若无,能否请教如何实现?? 谢谢


    • 已编辑 Linner 2012年4月10日 12:12
    2012年4月10日 12:11

答案

  • 第一个问题: 背景色是由 可视树中 EdgePanel 中的Grid影响,我们要通过代码把这个颜色改掉:

    <Window x:Class="WpfApplication2.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:c="clr-namespace:System.Windows.Controls.DataVisualization.Charting;assembly=System.Windows.Controls.DataVisualization.Toolkit"
            xmlns:cp="clr-namespace:System.Windows.Controls.DataVisualization.Charting.Primitives;assembly=System.Windows.Controls.DataVisualization.Toolkit"
            Title="MainWindow" Height="350" Width="525">
      <Grid Background="Gray">
        <c:Chart x:Name="chart" Background="Transparent" Loaded="Chart_Loaded">
          <c:Chart.Series>
            <c:PieSeries Background="Transparent" Title="Pie" ItemsSource="{Binding Items}" IndependentValueBinding="{Binding Path=Key}" DependentValueBinding="{Binding Path=Value}">
              
            </c:PieSeries>
          </c:Chart.Series>
        </c:Chart>
      </Grid>
    </Window>
    

    C#:

      public partial class MainWindow : Window
      {
        public ObservableCollection<KeyValuePair<int, double>> Items { get; set; }
        public MainWindow()
        {
          InitializeComponent();
          Items = new ObservableCollection<KeyValuePair<int, double>>();
          Random random = new Random(DateTime.Now.Millisecond);
          for (int i = 1; i <= 5; i++)
          {
            Items.Add(new KeyValuePair<int, double>(i, random.NextDouble() * 100));
          }
          this.DataContext = this;
        }
    
        private void Chart_Loaded(object sender, RoutedEventArgs e)
        {
          EdgePanel edgePanel = GetVisualChild<EdgePanel>(chart);
          Grid grid = GetVisualChild<Grid>(edgePanel);
          grid.Background = Brushes.Transparent;
        }
    
        public static T GetVisualChild<T>(Visual parent) where T : Visual
        {
          T child = default(T);
          int numVisuals = VisualTreeHelper.GetChildrenCount(parent);
    
          for (int i = 0; i < numVisuals; i++)
          {
            Visual v = (Visual)VisualTreeHelper.GetChild(parent, i);
            child = v as T;
    
            if (child == null)
              child = GetVisualChild<T>(v);
            else
              break;
          }
          return child;
        }
      }

    对应傍边的Legend区域,也可以先通过可视树观察看到那个元素有背景,然后通过代码找到这个元素,设置他的背景为透明。VS2010在暂停调试模式下,提供可视树查看:


    Bob Bao [MSFT]
    MSDN Community Support | Feedback to us

    • 已标记为答案 Linner 2012年4月12日 1:18
    2012年4月10日 17:07
    版主
  • 第二个问题,你可以先看看我以前做过很多的自定义Chart的帖子和例子:

    然后,我们可以先从WPF Toolkit那边拿到源代码, 去学习他是怎么实现 PieSeries。

    然后,继承自PieSeries,后去实现自己的圆环Series。

    从Toolkit源代码 Toolkit-release\DataVisualization\Charting\Series\PieSeries.cs

    internal static void UpdatePieDataPointGeometry 方法中,我们可以看到,下面的一个循环是用来最终绘制扇面的:

              foreach (DependencyProperty dependencyProperty in new DependencyProperty[] { PieDataPoint.GeometryProperty, PieDataPoint.GeometrySelectionProperty, PieDataPoint.GeometryHighlightProperty })
              {
                // Creating the pie slice geometry object
                PathFigure pathFigure = new PathFigure { IsClosed = true };
                pathFigure.StartPoint = translatePoint;
                pathFigure.Segments.Add(new LineSegment { Point = adjustedOffsetRatioPoint });
                bool isLargeArc = (currentRatio - offsetRatio) > 0.5;
                pathFigure.Segments.Add(
                    new ArcSegment
                    {
                      Point = adjustedCurrentRatioPoint,
                      IsLargeArc = isLargeArc,
                      Size = new Size(sliceRadius, sliceRadius),
                      SweepDirection = SweepDirection.Clockwise
                    });
    
                PathGeometry pathGeometry = new PathGeometry();
                pathGeometry.Figures.Add(pathFigure);
                pieDataPoint.SetValue(dependencyProperty, pathGeometry);
              }

    我们要在这里重载这个方法并修改其代码,增加一个内圆来实现环形图。

              // Calculate the last clockwise point in the pie slice
              Point currentRatioPoint =
                  ConvertRatioOfRotationToPoint(currentRatio, sliceRadius, sliceRadius);
              Point currentInnerRatioPoint =
                  ConvertRatioOfRotationToPoint(currentRatio, innerSliceRadius, innerSliceRadius);
    
              // Adjust point using center of plot area as origin
              // instead of 0,0
              Point adjustedCurrentRatioPoint = currentRatioPoint.Translate(translatePoint);
              Point adjustedCurrentInnerRatioPoint = currentInnerRatioPoint.Translate(translatePoint);
    
              foreach (DependencyProperty dependencyProperty in new DependencyProperty[] { PieDataPoint.GeometryProperty, PieDataPoint.GeometrySelectionProperty, PieDataPoint.GeometryHighlightProperty })
              {
                // Creating the pie slice geometry object
                PathFigure pathFigure = new PathFigure { IsClosed = true };
                bool isLargeArc = (currentRatio - offsetRatio) > 0.5;
    
                pathFigure.StartPoint = adjustedCurrentInnerRatioPoint;
    
                pathFigure.Segments.Add(
                    new ArcSegment
                    {
                      Point = adjustedOffsetInnerRatioPoint,
                      IsLargeArc = isLargeArc,
                      Size = new Size(innerSliceRadius, innerSliceRadius),
                      SweepDirection = SweepDirection.Counterclockwise
                    });
    
                pathFigure.Segments.Add(new LineSegment { Point = adjustedOffsetRatioPoint });
    
                pathFigure.Segments.Add(
                    new ArcSegment
                    {
                      Point = adjustedCurrentRatioPoint,
                      IsLargeArc = isLargeArc,
                      Size = new Size(sliceRadius, sliceRadius),
                      SweepDirection = SweepDirection.Clockwise
                    });
    
                PathGeometry pathGeometry = new PathGeometry();
                pathGeometry.Figures.Add(pathFigure);
                pieDataPoint.SetValue(dependencyProperty, pathGeometry);
              }


    完整的例子: https://skydrive.live.com/#cid=51B2FDD068799D15&id=51B2FDD068799D15%21948


    Bob Bao [MSFT]
    MSDN Community Support | Feedback to us


    2012年4月10日 18:01
    版主

全部回复

  • 第一个问题: 背景色是由 可视树中 EdgePanel 中的Grid影响,我们要通过代码把这个颜色改掉:

    <Window x:Class="WpfApplication2.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:c="clr-namespace:System.Windows.Controls.DataVisualization.Charting;assembly=System.Windows.Controls.DataVisualization.Toolkit"
            xmlns:cp="clr-namespace:System.Windows.Controls.DataVisualization.Charting.Primitives;assembly=System.Windows.Controls.DataVisualization.Toolkit"
            Title="MainWindow" Height="350" Width="525">
      <Grid Background="Gray">
        <c:Chart x:Name="chart" Background="Transparent" Loaded="Chart_Loaded">
          <c:Chart.Series>
            <c:PieSeries Background="Transparent" Title="Pie" ItemsSource="{Binding Items}" IndependentValueBinding="{Binding Path=Key}" DependentValueBinding="{Binding Path=Value}">
              
            </c:PieSeries>
          </c:Chart.Series>
        </c:Chart>
      </Grid>
    </Window>
    

    C#:

      public partial class MainWindow : Window
      {
        public ObservableCollection<KeyValuePair<int, double>> Items { get; set; }
        public MainWindow()
        {
          InitializeComponent();
          Items = new ObservableCollection<KeyValuePair<int, double>>();
          Random random = new Random(DateTime.Now.Millisecond);
          for (int i = 1; i <= 5; i++)
          {
            Items.Add(new KeyValuePair<int, double>(i, random.NextDouble() * 100));
          }
          this.DataContext = this;
        }
    
        private void Chart_Loaded(object sender, RoutedEventArgs e)
        {
          EdgePanel edgePanel = GetVisualChild<EdgePanel>(chart);
          Grid grid = GetVisualChild<Grid>(edgePanel);
          grid.Background = Brushes.Transparent;
        }
    
        public static T GetVisualChild<T>(Visual parent) where T : Visual
        {
          T child = default(T);
          int numVisuals = VisualTreeHelper.GetChildrenCount(parent);
    
          for (int i = 0; i < numVisuals; i++)
          {
            Visual v = (Visual)VisualTreeHelper.GetChild(parent, i);
            child = v as T;
    
            if (child == null)
              child = GetVisualChild<T>(v);
            else
              break;
          }
          return child;
        }
      }

    对应傍边的Legend区域,也可以先通过可视树观察看到那个元素有背景,然后通过代码找到这个元素,设置他的背景为透明。VS2010在暂停调试模式下,提供可视树查看:


    Bob Bao [MSFT]
    MSDN Community Support | Feedback to us

    • 已标记为答案 Linner 2012年4月12日 1:18
    2012年4月10日 17:07
    版主
  • 第二个问题,你可以先看看我以前做过很多的自定义Chart的帖子和例子:

    然后,我们可以先从WPF Toolkit那边拿到源代码, 去学习他是怎么实现 PieSeries。

    然后,继承自PieSeries,后去实现自己的圆环Series。

    从Toolkit源代码 Toolkit-release\DataVisualization\Charting\Series\PieSeries.cs

    internal static void UpdatePieDataPointGeometry 方法中,我们可以看到,下面的一个循环是用来最终绘制扇面的:

              foreach (DependencyProperty dependencyProperty in new DependencyProperty[] { PieDataPoint.GeometryProperty, PieDataPoint.GeometrySelectionProperty, PieDataPoint.GeometryHighlightProperty })
              {
                // Creating the pie slice geometry object
                PathFigure pathFigure = new PathFigure { IsClosed = true };
                pathFigure.StartPoint = translatePoint;
                pathFigure.Segments.Add(new LineSegment { Point = adjustedOffsetRatioPoint });
                bool isLargeArc = (currentRatio - offsetRatio) > 0.5;
                pathFigure.Segments.Add(
                    new ArcSegment
                    {
                      Point = adjustedCurrentRatioPoint,
                      IsLargeArc = isLargeArc,
                      Size = new Size(sliceRadius, sliceRadius),
                      SweepDirection = SweepDirection.Clockwise
                    });
    
                PathGeometry pathGeometry = new PathGeometry();
                pathGeometry.Figures.Add(pathFigure);
                pieDataPoint.SetValue(dependencyProperty, pathGeometry);
              }

    我们要在这里重载这个方法并修改其代码,增加一个内圆来实现环形图。

              // Calculate the last clockwise point in the pie slice
              Point currentRatioPoint =
                  ConvertRatioOfRotationToPoint(currentRatio, sliceRadius, sliceRadius);
              Point currentInnerRatioPoint =
                  ConvertRatioOfRotationToPoint(currentRatio, innerSliceRadius, innerSliceRadius);
    
              // Adjust point using center of plot area as origin
              // instead of 0,0
              Point adjustedCurrentRatioPoint = currentRatioPoint.Translate(translatePoint);
              Point adjustedCurrentInnerRatioPoint = currentInnerRatioPoint.Translate(translatePoint);
    
              foreach (DependencyProperty dependencyProperty in new DependencyProperty[] { PieDataPoint.GeometryProperty, PieDataPoint.GeometrySelectionProperty, PieDataPoint.GeometryHighlightProperty })
              {
                // Creating the pie slice geometry object
                PathFigure pathFigure = new PathFigure { IsClosed = true };
                bool isLargeArc = (currentRatio - offsetRatio) > 0.5;
    
                pathFigure.StartPoint = adjustedCurrentInnerRatioPoint;
    
                pathFigure.Segments.Add(
                    new ArcSegment
                    {
                      Point = adjustedOffsetInnerRatioPoint,
                      IsLargeArc = isLargeArc,
                      Size = new Size(innerSliceRadius, innerSliceRadius),
                      SweepDirection = SweepDirection.Counterclockwise
                    });
    
                pathFigure.Segments.Add(new LineSegment { Point = adjustedOffsetRatioPoint });
    
                pathFigure.Segments.Add(
                    new ArcSegment
                    {
                      Point = adjustedCurrentRatioPoint,
                      IsLargeArc = isLargeArc,
                      Size = new Size(sliceRadius, sliceRadius),
                      SweepDirection = SweepDirection.Clockwise
                    });
    
                PathGeometry pathGeometry = new PathGeometry();
                pathGeometry.Figures.Add(pathFigure);
                pieDataPoint.SetValue(dependencyProperty, pathGeometry);
              }


    完整的例子: https://skydrive.live.com/#cid=51B2FDD068799D15&id=51B2FDD068799D15%21948


    Bob Bao [MSFT]
    MSDN Community Support | Feedback to us


    2012年4月10日 18:01
    版主
  • Bob Bao 你好,我试了你说的这种方法。发现在VS2010下成功,但是在VS2008下VisualTreeHelper.GetChildrenCount(chart)返回的值是0。也就是说该视觉数下没有子元素?请问是怎么回事?是因为两个版本的控件库内部实现有区别么?
    2012年4月11日 4:24
  • 注意,你一定要等到Chart内容都显示出来才可以,所以我是把代码写在了Loaded事件里面。

    WPF Toolkit只有for .Net 3.5的版本,在VS 2010中用的也是这个版本,所以是一样的。

    还有,我已经告诉你可以下载到源代码的,所以你尽可以修改源码中Chart控件的样式模板,把 EdgePanel 中的Grid的背景去掉就好了,就不需要代码了。

    既然你有在用VS2010开发,为何你要倒退到08环境,.Net4 针对WPF做了很多改进,我总体感觉 .Net 4做WPF比.Net 3.5好很多。


    Bob Bao [MSFT]
    MSDN Community Support | Feedback to us

    2012年4月11日 7:05
    版主
  • 非常感谢!

    2012年4月12日 1:18