如何为WPF工具包图表添加样式

5

在这里输入图片描述

我正在使用WPF应用程序中的WPF Toolkit Chart,其中包含PieChart。

我想将PieChart图片默认的白色背景更改为透明背景。

如何使用样式实现这一点?

2个回答

20
WPF旨在通过XAML而非代码来允许您为控件设置样式。通过样式,使饼图中的绘图区域和图例透明也是可能的。不幸的是,无法使用属性控制绘图区域周围的边框,而必须修改整个控件模板。最终,使用样式可能与编写修改可视树的代码一样繁琐,但至少对我来说,它仍然感觉更加简洁。
<chartingToolkit:Chart>
  <chartingToolkit:Chart.PlotAreaStyle>
    <Style TargetType="Grid">
      <Setter Property="Background" Value="Transparent"/>
    </Style>
  </chartingToolkit:Chart.PlotAreaStyle>

  <chartingToolkit:Chart.LegendStyle>
    <Style TargetType="visualizationToolkit:Legend">
      <Setter Property="Margin" Value="15,0"/>
      <Setter Property="VerticalAlignment" Value="Center"/>
      <Setter Property="BorderBrush" Value="Transparent"/>
      <Setter Property="Background" Value="Transparent"/>
    </Style>
  </chartingToolkit:Chart.LegendStyle>

  <chartingToolkit:Chart.Style>
    <Style TargetType="chartingToolkit:Chart">
      <Setter Property="Template">
        <Setter.Value>
          <ControlTemplate TargetType="chartingToolkit:Chart">
            <Border Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Padding="{TemplateBinding Padding}">
              <Grid>
                <Grid.RowDefinitions>
                  <RowDefinition Height="Auto" />
                  <RowDefinition Height="*" />
                </Grid.RowDefinitions>

                <visualizationToolkit:Title Content="{TemplateBinding Title}" Style="{TemplateBinding TitleStyle}" />

                <!-- Use a nested Grid to avoid possible clipping behavior resulting from ColumnSpan+Width=Auto -->
                <Grid Grid.Row="1" Margin="0,15,0,15">
                  <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="*" />
                    <ColumnDefinition Width="Auto" />
                  </Grid.ColumnDefinitions>

                  <visualizationToolkit:Legend x:Name="Legend" Title="{TemplateBinding LegendTitle}" Style="{TemplateBinding LegendStyle}" Grid.Column="1" />
                  <chartingprimitives:EdgePanel x:Name="ChartArea" Style="{TemplateBinding ChartAreaStyle}">
                    <Grid Canvas.ZIndex="-1" Style="{TemplateBinding PlotAreaStyle}" />
                    <!--<Border Canvas.ZIndex="10" BorderBrush="#FF919191" BorderThickness="1" />-->
                  </chartingprimitives:EdgePanel>
                </Grid>
              </Grid>
            </Border>
          </ControlTemplate>
        </Setter.Value>
      </Setter>
    </Style>
  </chartingToolkit:Chart.Style>

  <chartingToolkit:PieSeries ... />
</chartingToolkit:Chart>

PlotAreaStyleLegendStyle被修改为透明。通过修改图表的ControlTemplate并注释掉有问题的Border元素来移除图表区域周围的边框。


嗨,马丁,你的例子非常有用。如果我想把饼图改成甜甜圈,或者改变饼图的3D阴影,有没有文档可以知道哪些属性控制它们?谢谢。 - Yafim Simanovsky
1
@YafimSimanovsky:距离我提供这个答案已经七年了,我恐怕不知道如何回答你的问题了。然而,如果我想修改一个现有的 WPF 控件,我会查看控件模板,并查看是否可以在不必从头开始重写控件的情况下实现所需的内容,就像七年前一样。不要指望找到有关如何做到这一点的文档。如果控件设计人员提供了一种修改三维阴影的方法,他们会添加一个属性来实现,而不是记录如何自己修改控件模板。 - Martin Liversage

4

如果您查看可视树,您会发现必须更改网格和边框的背景属性才能将背景更改为透明色(如下图中突出显示的元素)。

enter image description here

为此,您可以在Loaded事件中更改颜色。首先,您必须找到名称为ChartAreaEdgePanel,然后必须更改网格和边框的颜色。如果您还想将Legend的背景设置为透明,则必须找到Legend元素并设置适当的属性。

<DVC:Chart Canvas.Top="80" Canvas.Left="10" Name="mcChart" 
   Width="400" Height="250"
   Background="Orange"
   Loaded="mcChart_Loaded">            
    <DVC:Chart.Series>
        <DVC:PieSeries Title="Experience" 
            ItemsSource="{StaticResource FruitCollection}"
            IndependentValueBinding="{Binding Path=Name}"
            DependentValueBinding="{Binding Path=Share}">                
        </DVC:PieSeries>
    </DVC:Chart.Series>           
</DVC:Chart>

后置代码:

private void mcChart_Loaded(object sender, RoutedEventArgs e)
{
    EdgePanel ep = VisualHelper.FindChild<EdgePanel>(sender as Chart, "ChartArea");
    if (ep != null)
    {
        var grid = ep.Children.OfType<Grid>().FirstOrDefault();
        if (grid != null)
        {
            grid.Background = new SolidColorBrush(Colors.Transparent);
        }

        var border = ep.Children.OfType<Border>().FirstOrDefault();
        if (border != null)
        {
            border.BorderBrush = new SolidColorBrush(Colors.Transparent);
        }
    }

    Legend legend = VisualHelper.FindChild<Legend>(sender as Chart, "Legend");
    if (legend != null)
    {
        legend.Background = new SolidColorBrush(Colors.Transparent);
        legend.BorderBrush = new SolidColorBrush(Colors.Transparent);               
    }
}

这是一个帮助类,用于在此情况下查找子元素EdgePanel的:

class VisualHelper
{
    public static T FindChild<T>(DependencyObject parent, string childName) where T : DependencyObject
    {
        if (parent == null) return null;

        T foundChild = null;

        int childrenCount = VisualTreeHelper.GetChildrenCount(parent);
        for (int i = 0; i < childrenCount; i++)
        {
            var child = VisualTreeHelper.GetChild(parent, i);
            T childType = child as T;
            if (childType == null)
            {
                foundChild = FindChild<T>(child, childName);
                if (foundChild != null) break;
            }
            else if (!string.IsNullOrEmpty(childName))
            {
                var frameworkElement = child as FrameworkElement;
                if (frameworkElement != null && frameworkElement.Name == childName)
                {
                    foundChild = (T)child;
                    break;
                }
            }
            else
            {
                foundChild = (T)child;
                break;
            }
        }
        return foundChild;
    }
}

但是正确答案、错误答案和未参加的框背景没有改变。 - Avinash Singh
@AvinashSingh 再次检查我的答案 :) 我更改了 Loaded 事件处理程序的代码,将 Legend 的背景属性设置为透明。 - kmatyaszek

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接