Wednesday, May 23, 2012

Changing the color of Area Chart Fill without C#

After looking over several websites, googling like crazy, and finding all sorts of complicated code I took notes of and still just didn't understand, I finally figured out how to "easily" change the color of the area chart fill.

Below is the basic, every day area chart - default blue color:


Below is the code I wrote to create the chart (the points are set in the code behind, I didn't want to mess up this code with the points set inline):

<UserControl
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:controls="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls"
    xmlns:controlsToolkit="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Toolkit"
    xmlns:chartingToolkit="clr-namespace:System.Windows.Controls.DataVisualization.Charting;assembly=System.Windows.Controls.DataVisualization.Toolkit"
    xmlns:chartingPrimitivesToolkit="clr-namespace:System.Windows.Controls.DataVisualization.Charting.Primitives;assembly=System.Windows.Controls.DataVisualization.Toolkit"
    xmlns:chartingPrimitives="clr-namespace:System.Windows.Controls.DataVisualization.Charting.Primitives;assembly=System.Windows.Controls.DataVisualization.Toolkit"
    xmlns:telerik="http://schemas.telerik.com/2008/xaml/presentation"
    xmlns:toolkit="http://schemas.microsoft.com/winfx/2006/xaml/presentation/toolkit"
    mc:Ignorable="d"
    x:Class="XAMLTestingScreens.AreaChartExample"
    Width="640" Height="480">

    <Grid x:Name="LayoutRoot" Background="White">
        <Canvas>
            <toolkit:Chart Title="Area Series Fill" x:Name="AreaSeriesFill" BorderBrush="Transparent" Width="640" Height="480">
                <toolkit:Chart.Axes>
                    <toolkit:LinearAxis x:Name="AxisOne" Foreground="Black"
                                        Title="Width" ShowGridLines="True"
                                        Orientation="X" Minimum="0" Maximum="40" Interval="5"/>
                    <toolkit:LinearAxis x:Name="AxisTwo" Foreground="Black" Title="Height"
                                        ShowGridLines="True" Orientation="Y" Minimum="0" Maximum="40" Interval="5"/>
                </toolkit:Chart.Axes>
               
                <toolkit:AreaSeries Title="Change Color" x:Name="changecolor" ItemsSource="{Binding}"
                                    IndependentValueBinding="{Binding Width}" DependentValueBinding="{Binding Height}"/>
            </toolkit:Chart>
        </Canvas>
    </Grid>
</UserControl>

I want to have the area below the plotted line (the fill) in red, and of course the corresponding Legend Item in the same color.

Here is the updated chart with the new color.


Below is the section of updated code:

<toolkit:AreaSeries Title="Change Color" x:Name="changecolor"
                                    ItemsSource="{Binding}"
                                    IndependentValueBinding="{Binding Width}"
                                    DependentValueBinding="{Binding Height}">
                    <toolkit:AreaSeries.DataPointStyle>
                        <Style TargetType="toolkit:DataPoint">
                            <Setter Property="Background" Value="Red" />
                        </Style>
                    </toolkit:AreaSeries.DataPointStyle>
                </toolkit:AreaSeries>

The highlighted area is the updated code.
All I did was add the DataPointStyle and set the background color. However, the area is not solid, and looks pink (not what I wanted) so I have to update the Opacity as well.



Below is the code for the brighter chart:

<toolkit:AreaSeries Title="Change Color" x:Name="changecolor"
                                    ItemsSource="{Binding}"
                                    IndependentValueBinding="{Binding Width}"
                                    DependentValueBinding="{Binding Height}" IsHitTestVisible="False">
                    <toolkit:AreaSeries.DataPointStyle>
                        <Style TargetType="toolkit:DataPoint">
                            <Setter Property="Background" Value="Red" />
                            <Setter Property="Opacity" Value="1.0" />
                        </Style>
                    </toolkit:AreaSeries.DataPointStyle>
                    <toolkit:AreaSeries.Style>
                        <Style TargetType="toolkit:AreaSeries">
                            <Setter Property="PathStyle">
                                <Setter.Value>
                                    <Style TargetType="Path">
                                        <Setter Property="Opacity" Value="1.0" />
                                    </Style>
                                </Setter.Value>
                            </Setter>
                        </Style>
                    </toolkit:AreaSeries.Style>
                </toolkit:AreaSeries>

The opacity is set using the AreaSeries.Style - pointing to a PathStyle. 

I was SO HAPPY to find a much easier way to change the colors, I really was not looking forward to coding upteen too many lines.

Hope this is helpful to someone else too.


PS: Below is the VERY basic code behind that I used to create the points for this graph:

using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Ink;
using System.Globalization;
using System.Threading;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Controls.DataVisualization.Charting;
using System.Windows.Controls.DataVisualization;
using System.ComponentModel;
using System.Windows.Shapes;

namespace XAMLTestingScreens
{
    public partial class AreaChartExample : UserControl
    {
        public AreaChartExample()
        {
            // Required to initialize variables
            InitializeComponent();
           
            this.LayoutRoot.DataContext = this;
           
            this.Loaded += new RoutedEventHandler(UC_Loaded);
           
           
        }
       
        void UC_Loaded (object sender, RoutedEventArgs e)
        {
       
            List<ColorChangePoints> colorchange = new List<ColorChangePoints>();
            colorchange.Add(new ColorChangePoints() {Width=0,Height=0});
            colorchange.Add(new ColorChangePoints() {Width=5,Height=10});
            colorchange.Add(new ColorChangePoints() {Width=10,Height=20});
            colorchange.Add(new ColorChangePoints() {Width=15,Height=15});
            colorchange.Add(new ColorChangePoints() {Width=20,Height=30});
            colorchange.Add(new ColorChangePoints() {Width=25,Height=15});
            colorchange.Add(new ColorChangePoints() {Width=30,Height=35});
            colorchange.Add(new ColorChangePoints() {Width=35,Height=10});
            colorchange.Add(new ColorChangePoints() {Width=40,Height=20});
           
            AreaSeries changecolor = AreaSeriesFill.Series[0] as AreaSeries;
           
            changecolor.IndependentValuePath = "Width";
            changecolor.DependentValuePath = "Height";
            changecolor.ItemsSource = colorchange;
        }
       
        public class ColorChangePoints
        {
            public double Width {get; set;}
            public double Height {get; set;}
        }
    }
}
Nothing special, but it's easier for me than hard coding it into the XAML

I've uploaded a copy of the project for you to play around with.

Thursday, May 10, 2012

Reversing a Silverlight Line Chart with XAML only

UPDATE:
I figured out the reversal, however the chart needed to plot downward and not left to right.

After trying to plot using the example below, the lines did not plot right. They were jagged and the graph did not plot any of the points in order.

One of my coworkers made the observation that the Silverlight charts always run left to right - for some reason it even happened when I "flipped" the chart in the way I previously tried (described below). However - the actual PLOTTING had remained the same. 

So, by going into the control template, I was able to translate the actual plotting area for the line to actually flow downward.

Went ahead and posted the explanation here.

*******************************


Wanted to reverse a Line Chart in Silverlight. All I could find were solutions using C#, and I am not the C-sharpest (I am more C-dull) so I decided to play around with the styles and options in the Linear Chart that is in the Silverlight 5 toolkit. (Have not tested it in Silverlight 4).

I looked at the code for the chart and couldn't figure out why it all had to be in C#, the elements themselves could use RenderTransform to change their orientation.

Started with the basic control, Layout Root. Added a Canvas for my new chart. I do include the entire list of xmlns definitions at the top. It helps me remember what to use, and kept getting frustrated with seeing a solution, but not what I needed to refer to so that it would WORK for me. I am still at the basic level when it comes to coding.



Make sure that you have the System.Windows.Controls.DataVisualization.Toolkit.dll in your References folder, or this won't work.







You can download the most current Silverlight Toolkit here.

Ok, from this point on - I am only showing the main code used in the actual line graph. That top part is LONG. Started with the basic line chart, and I did separate out the Axis Titles, this way if they need to be rotated I just rotate the TextBlock without affecting the entire axis.





Then added the LineSeries (these are notes for me, and I know I would forget this part too - so, have to make sure that I keep track of this chart item as well)




I didn't want to create the points for this entry in the code behind, so I used the answer to this post and just defined the points in the XAML for now. 

I also went ahead and finished defining the minimum and maximum for both of the axes - for the X-Axis, I gave an Interval of 2 so more lines would show.

Below is the finished code and a screenshot of the chart itself - right now it is the basic, default chart without any styling.





Since the code has become rather long (for me to keep copying and making it readable) I will just show the individual elements of the chart as I change them.

First, I reversed the actual Axis Labels on the Y axis - this has not changed the line as the preview shows. I added the RenderTransform Code to the elements - this is why I separated the Title of the Axis using <chartingToolkit:LinearAxis.Title> and a TextBlock. Since it automatically rotates with the axis, I can rotate it back to where it should be.

For the Labels, they will be upside down once you reverse the ScaleY of the axis, but by using the <chartingToolkit:LinearAxis.AxisLabelStyle> I can transform them back to the orientation they need to be.



Now, I just need to reverse the line on this chart - and it will display like I want it too - the zero at the top left hand corner and going DOWN as values change.

Reversing the LineSeries is SUPER easy - all I did was add
 <toolkit:LineSeries.RenderTransform>
<CompositeTransform ScaleY="-1" />
</toolkit:LineSeries.RenderTransform>

Now the line is reversed with the Y axis - and I have the chart the way I wanted it - the Y axis reversed with 0 on the top.




And there it is - a reversed chart where I didn't fry my brain on C# (it did fry a bit on the XAML since I had to play around with it and came up with a lot of deformed charts).

I've uploaded the file for you to play with/use.





Tuesday, May 8, 2012

Reusable Brushes (Resource Dictionaries)

One of the nice things in Silverlight/WPF is the way Resource Dictionaries can help create a standard set of application brushes - used in the design keeps all of the colors consistent and preserve the design when sent over to production and deployment.

Below is a screenshot of the starting Blend Screen - this is what you see when you create a new project. Most will be different depending on how you set up your screen, but this is just going over some of the basics, helps to explain the process (for me at least).

The "Projects" window in the upper left shows you what files are currently in your project, "Assets" and "Stages" are not used when creating a Resource Dictionary. The "Objects and Timeline" window below "Projects" displays the elements you have either created or imported into the file. Think of this file as a new Illustrator file, the LayoutRoot grid is the new page and the "Objects and Timeline" window shows you the objects based on what layer they are in the file.



Step 1. Create a new folder in the project files.
I create a new folder so I can easily find my resource dictionaries - and keep them all in one place. Sort of like collecting images for print projects in InDesign. Everything for the document is now in one place and can be referenced through the entire document (or project for Silverlight).





I right click on the project name (for this demo it is XAMLTestingScreens) which brings up a menu - Choose "Add New Folder". I name my folder "Resources" since it is easy for me to remember.

Right click on your new folder, the same options menu will be displayed, this time select "Add New Item." This will bring up a dialog window showing various file types you can add to your current project.

Select "Resource Dictionary" - I named mine "Brushes.xaml" so it is easy for me to reference later as I build more functionality and design into this project.

You will now see a new file named (ok, I will in this demo) "Brushes.xaml" - there is no C# codebehind, since there is no real functionality to this document. Think of it as a .css file you use to style the Silverlight controls and elements.




I used the same brush I made for the chrome brush notes, just so I don't have to remake anything for this - the XAML for our Resource Dictionary now looks like below.




 In order to reference this dictionary you have to make sure the file App.xaml includes the newly created Resource Dictionary (in this case Brushes.xaml) in it's listing of used style files.

For this small project the App.xaml file is located in the very top/first project named "XAMLTesting", it is usually located in your topmost project that is the name of the Silverlight file (nothing after the name such as XAMLTestingScreens).

Below is what we currently have in our App.xaml file for this mini project:
<Application
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    x:Class="XAMLTesting.App">
    <Application.Resources>
          <ResourceDictionary>
            <ResourceDictionary.MergedDictionaries>
                <ResourceDictionary Source="/Microsoft.Expression.Prototyping.SketchControls;component/ScrollViewerStyles.xaml"/>
                <ResourceDictionary Source="/XAMLTesting.Screens;component/SketchStyles.xaml"/>
                <ResourceDictionary Source="/XAMLTesting.Screens;component/Resources/Brushes.xaml"/>
            </ResourceDictionary.MergedDictionaries>
        </ResourceDictionary>
    </Application.Resources>
</Application>

It lists all of the resource dictionaries that the application is supposed to use - the SketchStyles and ScrollViewerStyles are default when you create a Silverlight Sketchflow project (which this is).

This line should automatically be placed in your App.xaml file - and you will see a tab at the top of your page saying "App.xaml*" - the star means the file has not been saved yet - save your file and then rebuild the project. After you rebuild - you will be able to see the new file in the"Resources" Tab/Window on the right hand side.


Go back to the properties panel - click on the white box next to the "Fill" color selector. You will get a dropdown box - choose "Local Resources" for a selection of brush styles available to you in the application. Choose the "MyChrome" brush (this name is the x:Key value in the resource dictionary file.)



After you have selected this option, your shape will now have the newly chosen brush from your resource dictionary. You can now use this brush on any of your application controls or pages without having to recreate it - saving both coding time and number of lines in the file.

 


 Above, you can see the XAML created by Blend to link the rectangle to this brush - it is now a "StaticResource" letting the application know it is a predefined resource and what key to use when referencing this brush style/definition.

You now have a rectangle (or any shape) with this brush as the fill.