in

Software FX Community

Discuss and find help for all Software FX products.

WPF Blog

June 2009 - Posts

  • Chart FX for WPF Compatibility with VS2010 Beta 1

    If you are using Visual Studio 2010 Beta 1 and Chart FX for WPF to create your WPF applications you have probably found that you have no design time experience, i.e. if you click on the chart at design time you will not get our wizard.

    VS2010Beta1

    Unfortunately Beta 1 does not pickup the Design time assemblies we ship for Visual Studio 2008 because they reference older versions of the Microsoft.Windows.Design.* assemblies. We expect this will be fixed on future Visual Studio builds so that we can ship multiple design time dlls and each Visual Studio will load the appropriate version.

    In the meantime we have been building VS2010 compatible assemblies although they are not shipped with our installer, if you are using VS2010 and want to use our design time functionality you must do this

    • Install our most recent hotfix
    • Send an email to support at softwarefx dot com to request the VS2010 design time assemblies
    • If you have a Design subdirectory underneath the folder where ChartFX was installed, rename this folder and copy all files to its parent directory
    • Overwrite ChartFX.WPF.Design.dll and ChartFX.WPF.Design.VisualStudio.dll with the VS2010 compatible assemblies (keep a backup copy if you think you might want to switch back to VS 2008)

    If you are starting a new project you will not get our component in the toolbox or in the WPF tab in the Choose Items dialog, but you can browse for the ChartFX.WPF.dll assembly.

    Note that VisualStudio 2010 Beta 1 seems to ignore the ToolboxBrowsable attribute so it will suggest a bunch of classes that you will not need in your toolbox, make sure you uncheck all classes but Chart.

    JuanC

  • Showing vertical titles

    Chart FX for WPF uses the title class in several places including Chart.Titles, Axis.Title, LegendBox.Titles and CustomGridLine.Title; in most of these scenarios there are cases where the title needs to be drawn vertically. For example the following XAML generates a chart with 4 titles each docked in a different position

          <cfx:Chart.Titles>
            <cfx:Title DockPanel.Dock="Top">Top</cfx:Title>
            <cfx:Title DockPanel.Dock="Left">Left</cfx:Title>
            <cfx:Title DockPanel.Dock="Right">Right</cfx:Title>
            <cfx:Title DockPanel.Dock="Bottom">Bottom</cfx:Title>
          </cfx:Chart.Titles>
    

    Which results in a chart like this

    VerticalTitles1

    Note that we rotate the titles on the right side 90 degrees clockwise while the title on the left side is rotated 90 degrees counterclockwise. You can control this using the RotateVerticalMode property, in the following picture we will set the left title RotateVerticalMode to None which might be suitable for short titles, you can also force a specific rotation by using Clockwise or CounterClockwise. We are using Counterclockwise for the right title.

    VerticalTitles2

    Can we use this feature to draw vertical titles where the letters are not rotated? I am glad you asked, setting the RotateVerticalMode to None is useful if we “borrow” delay’s code for a vertical text block, in this case our XAML would set the title’s content to be an instance of VerticalTextBlock which derives from control

          <cfx:Chart.Titles>
            <cfx:Title DockPanel.Dock="Left" RotateVerticalMode="None">
              <local:VerticalTextBlock Text="SALES"/>
            </cfx:Title>
          </cfx:Chart.Titles>
    

    Which results in the following chart

    VerticalTitles3

    Note that the Title.Content is of type object so you can also provide any visuals, e.g. a StackPanel with an icon and some text, a button, etc.

    There are some scenarios though where Chart FX might reuse your title in more than one place, an axis for example could potentially be reused in multiple panes, in this case you will want to use the visuals in the Title.ContentTemplate property.

    JuanC

    Posted Jun 18 2009, 10:31 AM by JuanC with no comments
    Filed under:
  • Creating an Expression Dark Chart Style

    Styling a WPF application so that it looks similar to Expression Blend seems to be a common scenario, you can even download a couple of open-source projects from Codeplex called “WPF Futures” and “WPF Themes” that include Expression Dark as one of several styles you can use in your WPF applications.

    If you use one of these projects, all the common controls will be automatically styled (ListBox, Label, Slider, etc.) but it will not affect how your charts look, so you will get something like this

    ExpressionDark1

    The first thing we can do to make our chart look integrated with the application is to change the brushes used for all the elements (bars, background, titles, point labels, etc.), in order to do this we will add to our app.xaml a style targeting all charts as follows

    xmlns:cfx="http://schemas.softwarefx.com/chartfx/wpf/80"
    xmlns:cfxMotifs=http://schemas.softwarefx.com/chartfx/wpf/80/motifs
    <Style x:Key="{x:Type cfx:Chart}" TargetType="{x:Type cfx:Chart}">
      <Setter Property="Template" Value="{x:Static cfxMotifs:Simple.ChartTemplate}"/>
      <Setter Property="Palette" Value="{StaticResource PaletteExpressionDark}"/>
    </Style>

    The first setter will switch the chart template from the default (Glass) to a simpler template (Simple), this removes the reflection at the bottom as well as the 3D-like floor. The second setter to change the chart’s palette references a resource in our app.xaml that will hold the palette and will look like this

    <cfx:Palette x:Key="PaletteExpressionDark">
      <cfx:Palette.SeriesFill>
        <Brush>#5372B0</Brush>
        <Brush>#FFEC35</Brush>
        …
    </cfx:Palette.SeriesFill> <cfx:Palette.SeriesStroke> <Brush>#324468</Brush> <Brush>#897E1C</Brush> …
    </cfx:Palette.SeriesStroke> <cfx:Palette.SeriesForegroundInside> <Brush>#FF385516</Brush> <Brush>#FF575113</Brush> … </cfx:Palette.SeriesForegroundInside> <cfx:Palette.Foreground>#FFFFFFFF</cfx:Palette.Foreground> <cfx:Palette.Background>#FF333333</cfx:Palette.Background> <cfx:Palette.Border></cfx:Palette.Border> <cfx:Palette.PointLabelForeground>#FFFFFFFF</cfx:Palette.PointLabelForeground> <cfx:Palette.PointLabelForegroundInside>
    #FFFFFFFF
    </cfx:Palette.PointLabelForegroundInside> <cfx:Palette.Axis>#BDBDBD</cfx:Palette.Axis> <cfx:Palette.AxisGridLines>#FF8B8B8B</cfx:Palette.AxisGridLines>

    <cfx:Palette.PlotArea>#40595959</cfx:Palette.PlotArea> <cfx:Palette.MainArea>Transparent</cfx:Palette.MainArea> <cfx:Palette.Title>#DFDFDF</cfx:Palette.Title> <cfx:Palette.LegendForeground>#DFDFDF</cfx:Palette.LegendForeground> <cfx:Palette.DataViewBackground>#40595959</cfx:Palette.DataViewBackground>
    <cfx:Palette.ToolTipForeground>#EEEEEE</cfx:Palette.ToolTipForeground> <cfx:Palette.View3DAmbientLight>#808080</cfx:Palette.View3DAmbientLight> <cfx:Palette.ThumbStroke>#FFD1D1D1</cfx:Palette.ThumbStroke> <cfx:Palette.SelectionFill>#8C00AEFF</cfx:Palette.SelectionFill> </cfx:Palette>

    Note that this palette has been trimmed so there are several entries missing, you can check the attached XAML for a complete palette, I wanted to highlight the following

    • You can supply as many brushes as desired for the chart series, if there are more series we will loop through this list
    • You can optionally supply brushes used for the borders of the markers, if you don’t we will use a lightly darker version of the series brushes
    • SeriesForegroundInside will be used when we know the point label is drawn inside the marker while the single PointLabelForeground will be used when the point is drawn on the plot area.
    • If you want, you can instead provide a single PointLabelForegroundInside and remove the SeriesForegroundInside
    • There are additional entries for the DataView, Legend, ToolTip, Titles and 3D

    ExpressionDark2

    The combination of a simpler style and using the same colors/gradients makes a big change but there are still several things we can improve, note that the border has not changed, when we designed Chart FX for WPF we wanted to be able to separate the styling of the different chart elements so changing the chart template did not result in the border being changed. This also means that in your chart you can modify the border appearance without worrying about the other elements in the chart.

    <cfx:ControlTemplateBorder x:Key="BorderDark">
      <cfx:ControlTemplateBorder.Template>
        <ControlTemplate TargetType="{x:Type cfx:ChartBorder}">
          <ControlTemplate.Resources>
            <Thickness x:Key="cfxBorderThickness">1</Thickness>
            <Style x:Key="cfxInternalBorderStyle" TargetType="{x:Type ContentControl}">
              <Setter Property="Template">
                <Setter.Value>
                  <ControlTemplate TargetType="{x:Type ContentControl}">
                    <Border CornerRadius="2"
    BorderBrush="{Binding Path=Palette.AlternateBorder}"
    RelativeSource={RelativeSource TemplatedParent},
    Background="{TemplateBinding Background}" BorderThickness="1"> <ContentPresenter Margin="{TemplateBinding Padding}"/> </Border> </ControlTemplate> </Setter.Value> </Setter> </Style> <CornerRadius x:Key="cfxCornerRadius">2</CornerRadius> </ControlTemplate.Resources> <Border cfx:Chart.PanelName="BorderChild"
    BorderBrush="{TemplateBinding BorderBrush}"
    Background="{TemplateBinding Background}" CornerRadius="2"
    BorderThickness="{TemplateBinding BorderThickness}" /> </ControlTemplate> </cfx:ControlTemplateBorder.Template> </cfx:ControlTemplateBorder>
    <Style x:Key="{x:Type cfx:Chart}" TargetType="{x:Type cfx:Chart}">
      <Setter Property="Template" Value="{x:Static cfxMotifs:Simple.ChartTemplate}"/>
      <Setter Property="Palette" Value="{StaticResource PaletteExpressionDark}"/>
      <Setter Property="Border" Value="{StaticResource BorderDark}"/>
    </Style>
    

    We are now setting the Border property using a ControlTemplateBorder class, if you ignore the resources for a moment it is just a single Border with some template bindings but the PanelName=”BorderChild” is very important, we will find the element with this value for the Chart.PanelName attached property and we will add inside of it the other visuals that generate the chart.

    • If we find a resource named cfxBorderThickness it will be used as a default border thickness unless you set the Chart.BorderThickness property
    • The cfxInternalBorderStyle will be used for the borders of the legend box and dataview
    • If the element marked as “BorderChild” has some roundness you must set the cfxCornerRadius appropriately

    Additionally you will notice that we have a default scrollbar style that does not match with the one used in the listbox, for this we will have to modify another property called MergeResources that expects a ResourceDictionary (we did not use a built-in WPF feature that does this because it causes memory leaks)

      <ResourceDictionary x:Key="ResourcesDark">
        <Style x:Key="ThumbStyle" TargetType="{x:Type Thumb}" BasedOn="{x:Null}">
          <Setter Property="Template">
            <Setter.Value>…</Setter.Value>
          </Setter>
        </Style>
        <Style x:Key="ScrollRepeatButtonStyle" TargetType="{x:Type RepeatButton}">
          <Setter Property="Template">
            <Setter.Value></Setter.Value>
          </Setter>
        </Style>
        <Style TargetType="{x:Type ScrollBar}">
          <Setter Property="Template">
            <Setter.Value>…</Setter.Value>
          </Setter>
        </Style>
      </ResourceDictionary>
      <Style x:Key="{x:Type cfx:Chart}" TargetType="{x:Type cfx:Chart}">
        <Setter Property="Template" Value="{x:Static cfxMotifs:Simple.ChartTemplate}"/>
        <Setter Property="Palette" Value="{StaticResource PaletteExpressionDark}"/>
        <Setter Property="Border" Value="{StaticResource BorderDark}"/>
        <Setter Property="MergeResources" Value="{StaticResource ResourcesDark}"/>
      </Style>
    

    Again we removed most of the xaml but this is just a copy of how a scrollbar is styled for expression dark. We are now getting really close as you can see in the following pictures

    ExpressionDark3 ExpressionDark4

    Depending on your application you can actually stop the styling here but there is still some of the glass showing on the markers, if you decide you want simpler visuals you can add the following

    <ResourceDictionary x:Key="GalleryDark">
      <DataTemplate x:Key="Bar">
        <DataTemplate.Resources>
          <sys:Double x:Key="cfxDefStrokeThickness">1</sys:Double>
          <DataTemplate x:Key="cfxLastStack">…</DataTemplate>
          <DataTemplate x:Key="cfxMiddleStack">…</DataTemplate>
          <DataTemplate x:Key="cfxFirstStack">…</DataTemplate>
    </DataTemplate.Resources> <
    Border x:Name="bar" CornerRadius="2,2,0,0"
    Width="{Binding Path=Width}" Height="{Binding Path=Height}"
    Background="{Binding Path=Fill}" BorderBrush="{Binding Path=Stroke}"
    BorderThickness="{Binding Path=StrokeThickness}"
    Opacity="{Binding Path=Opacity}"
    RenderTransform="{Binding Path=Transform}" /> <DataTemplate.Triggers>…</DataTemplate.Triggers> </DataTemplate> <DataTemplate x:Key="Line"> <DataTemplate.Resources> <sys:Double x:Key="cfxDefStrokeThickness">3</sys:Double> <sys:Double x:Key="cfxDefMarkerSize">10</sys:Double> <sys:String x:Key="pointsCategory">lineShadow</sys:String> </DataTemplate.Resources> <Canvas Opacity="{Binding Path=Opacity}"> <Polyline Visibility="{Binding Path=EffectsVisibility}" x:Name="lineShadow"
    Points="{Binding Path=Points}"
    Canvas.Top="{Binding Path=StrokeThickness,
    Converter={StaticResource multiplyConverter},
    ConverterParameter=1.50}"
    Stroke="#FF000000" StrokeThickness="{Binding Path=StrokeThickness}"
    StrokeDashArray="{Binding Path=StrokeDashArray}" Opacity="0.2"> <Polyline.BitmapEffect> <BlurBitmapEffect Radius="2"/> </Polyline.BitmapEffect> </Polyline> <Polyline Points="{Binding Path=Points}" x:Name="points"
    Stroke="{Binding Path=Stroke}"
    StrokeThickness="{Binding Path=StrokeThickness}"
    StrokeDashArray="{Binding Path=StrokeDashArray}" /> </Canvas> <DataTemplate.Triggers>…</DataTemplate.Triggers> </DataTemplate> </ResourceDictionary>
    <Style x:Key="{x:Type cfx:Chart}" TargetType="{x:Type cfx:Chart}">
      <Setter Property="Template" Value="{x:Static cfxMotifs:Simple.ChartTemplate}"/>
      <Setter Property="Palette" Value="{StaticResource PaletteExpressionDark}"/>
      <Setter Property="Border" Value="{StaticResource BorderDark}"/>
      <Setter Property="MergeResources" Value="{StaticResource ResourcesDark}"/>
      <Setter Property="GalleryTemplates" Value="{StaticResource GalleryDark}"/>
      <Setter Property="MarkerTemplates" Value="{x:Static cfx:MarkerTemplates.Simple}"/>
    </Style>

    The GalleryTemplates property expects a ResourceDictionary where you supply styles for all our galleries, note the following key points

    • If we do not find a template for a particular gallery we will use the template from the Simple style. This gives you a simple but not too basic style for most galleries, in this case we are only customizing bar and line
    • Each style can provide defaults, for example the line will have a thickness of 3 and the markers will be size 10 if you do not modify the appropriate properties.
    • Bars allow you to specify an alternate template for the first, middle and last stacks, this allows you to have a rounded top without having all intermediate segments rounded
    • You can bind visibility of “effects” to a property called EffectsVisibility (shown here for the shadow of the line), this will be controlled by Chart.UseEffects
    • You can also provide a ResourceDictionary that controls how the line markers look, we are using a built-in dictionary that generates simpler markers.

    This is what our final style looks like

    ExpressionDark5 ExpressionDark6
    ExpressionDark7

    Chart FX for WPF includes the following built-in styles

    • In our core ChartFX.WPF assembly we support Glass, Simple and Basic
    • In the ChartFX.WPF.Motifs assembly we include Edge, Spotlight, Floating and Blinds
    • In the ChartFX.WPF.Motifs.HandDrawn assembly we include HandDrawn

    You can quickly switch styles in your app with a single line of code, if you add a reference to the extra 2 assemblies you will  be able to browse through our styles in the ChartFX.WPF.Motifs namespace, remember that you are assigning a Style property so you have to then select the Style property (e.g. ChartFX.WPF.Motifs.Simple.Style)

    ExpressionDarkStyles

    We are considering adding Expression Dark to ChartFX.WPF.Motifs as well as other popular application styles, your feedback will let us know which styles we should focus on, but we wanted to show that is possible to completely control your charts appearance to make it integrated in your application.

    JuanC

    The following APIs were not harmed during the production of this post

    Palette: Gives you control over all brushes and colors used in the chart. 
    Border: Allows you to change the chart border independently from the chart template.
    GalleryTemplates and MarkerTemplates. Control how markers (bar, line, area, etc.) look
    MergeResources: Additional resources such as scrollbar. 
    UseEffects: Hide shadows, reflections from the chart visuals.

    Posted Jun 15 2009, 10:54 AM by JuanC with no comments
    Filed under: ,
Copyright 2008 Software FX, Inc.