Monthly Archives: July 2014
WPF Charts (Part 1)
I was playing around with techniques and built a short chart demo. There are many tools out there to create charts. I prefer the good old WPF Toolkit solution on codeplex, which adds the namespace ‘System.Windows.Controls.DataVisualization.Chart’ and is supported by Microsoft. You can expect high compatibility at zero costs.
Do not confuse this one with the Extended WPF Toolkit, which is free software, but also offers a commercial solution.
We are going to create various WPF charts in the coming weeks. The programming pattern series will continue at some point afterwards. What topics I choose is always closely related to my personal interests at that time. I find it hard to motivate myself otherwise.
This is a very simple example today. I added two NumericUpDown controls to add some flavor. Well, in the WPF Toolkit they are not called NumericUpDown anymore. There are corresponding DoubleUpDown/ DecimalUpDown/IntegerUpDown controls.
The lower DoubleUpDown control in this demo is linked to the upper one. And in turn the upper one is bound to a DataContext object property. This demonstrates a chain of bindings. Hence three objects are linked together holding the same value.
You can uncomment the prepared block in the XAML code. This will influence the line color and the line thickness. This template has its limits. It does not change the color of related objects. Anyway, it is a good start.
The chart has two curves. You can influence one by using any of the two DoubleUpDown controls.
The used ObservableCollection to store the curve points could be a post on its own. Basically, it is a WPF collection, which notifies WPF when you add or remove items from/to the list. But how do you update a chart, which only changes a value of a single point? The four methods to invalidate the drawing area are somewhat not showing the expected results.
You can set the DataContext to null and then set it back to your source. This is not the fastest way. But practically speaking, changing one value does not happen very often and setting the DataContext is quick and easy. Usually you only add or remove points. If you are looking for animations, they are dealt with differently in WPF. You should have a look into System.Windows.Media.Storyboard for that. In this example I chose to simply remove and add the affected point.
You don’t have to re-insert the point at the right collection position. I just did it to easily find the same point again. A simple Chart.Add() would work as well.
WPF will most likely not show the point removal on the screen. Tell me if I am wrong. I haven’t seen any impact. I guess the Dispatcher thread is blocked while you are using it on the WPF event call. A signal, which may happen right after the event finishes, will trigger the queued removal and addition in one go.
<Window x:Class="Demo.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:tool="clr-namespace:Xceed.Wpf.Toolkit;assembly=Xceed.Wpf.Toolkit" xmlns:dv="clr-namespace:System.Windows.Controls.DataVisualization.Charting;assembly=System.Windows.Controls.DataVisualization.Toolkit" xmlns:local="clr-namespace:Demo" Title="MainWindow" Height="350" Width="525" Initialized="Window_Initialized"> <Grid> <DockPanel LastChildFill="True"> <tool:DoubleUpDown DockPanel.Dock="Top" Name="UpDown1" AllowSpin="True" Minimum="0" Maximum="100.5" Increment="0.5" ClipValueToMinMax="True" DefaultValue="0" Watermark="enter a value" MouseWheelActiveOnFocus="True" MouseWheelActiveTrigger="FocusedMouseOver" FormatString="N3" ShowButtonSpinner="True" TextAlignment="Center" Value="{Binding PriceOfDay3, Mode=OneWayToSource, FallbackValue=55.5 }" /> <tool:DoubleUpDown DockPanel.Dock="Top" Name="UpDown2" AllowSpin="True" Minimum="0" Maximum="100.5" Increment="0.5" ClipValueToMinMax="True" Value="{Binding Value, ElementName=UpDown1, Mode=TwoWay}" MouseWheelActiveOnFocus="True" MouseWheelActiveTrigger="FocusedMouseOver" FormatString="N3" ShowButtonSpinner="True" TextAlignment="Center"/> <dv:Chart Name="Chart1" Title="Test Chart" > <dv:LineSeries Title="Price" ItemsSource="{Binding Points, Delay=2500, IsAsync=False}" IndependentValueBinding="{Binding Day}" DependentValueBinding="{Binding Price}" > <dv:LineSeries.DependentRangeAxis> <dv:LinearAxis Orientation="Y" Title="Price" Minimum="50" Maximum="60" Interval="2" ShowGridLines="True"/> </dv:LineSeries.DependentRangeAxis> <!--<dv:LineSeries.Template> --><!-- change the line color to green and set the thickness --><!-- <ControlTemplate TargetType="dv:LineSeries"> <Canvas x:Name="PlotArea"> <Polyline x:Name="polyline" Points="{TemplateBinding Points}" Style="{TemplateBinding PolylineStyle}" Stroke="Green" StrokeThickness="4" /> </Canvas> </ControlTemplate> </dv:LineSeries.Template>--> </dv:LineSeries> <dv:LineSeries Title="Tax" ItemsSource="{Binding Points, Delay=2500, IsAsync=False}" IndependentValueBinding="{Binding Day}" DependentValueBinding="{Binding Tax}"> <dv:LineSeries.DependentRangeAxis> <dv:LinearAxis Orientation="Y" Title="Tax" Minimum="-10" Maximum="10" Interval="2.5"/> </dv:LineSeries.DependentRangeAxis> </dv:LineSeries> <dv:Chart.Axes> <dv:LinearAxis Orientation="X" Title="X-Axis" Interval="2" ShowGridLines="True"/> </dv:Chart.Axes> </dv:Chart> </DockPanel> </Grid> </Window>
using System; using System.Collections.ObjectModel; using System.Windows; using System.Windows.Controls.DataVisualization.Charting; namespace Demo { public partial class MainWindow : Window { public MainWindow() { InitializeComponent(); } public class DataPoint { public double Day { get; set; } public double Price { get; set; } public double Tax { get; set; } } // class public class ViewModel { private readonly Chart _Chart; public ObservableCollection<DataPoint> Points { get; private set; } public double PriceOfDay3 { get { lock (this) return Points[2].Price; } set { lock (this) { DataPoint p = Points[2]; p.Price = value; Points.Remove(p); Points.Insert(2, p); // same position //Points.Add(p); // append to the end } } } // public ViewModel(Chart xChart) { _Chart = xChart; Points = new ObservableCollection<DataPoint>(); Points.Add(new DataPoint() { Day = 1.0, Price = 55, Tax = 2.0 }); Points.Add(new DataPoint() { Day = 1.5, Price = 54, Tax = 1.0 }); Points.Add(new DataPoint() { Day = 2.0, Price = 58, Tax = -1.0 }); Points.Add(new DataPoint() { Day = 3.0, Price = 55.5, Tax = 0.0 }); Points.Add(new DataPoint() { Day = 4.0, Price = 53, Tax = -2.0 }); } // constructor } // class private void Window_Initialized(object sender, EventArgs e) { ViewModel lViewModel = new ViewModel(Chart1); DataContext = lViewModel; } // } // class } // namespace
Singleton Pattern
I did never really care about programming patterns. I had to come up with ideas when I needed them. And back in the Commodore 64 ages, when I wrote my first “Hello World” program in Basic, there was no book about patterns anyway.
When you only allow one object instance, that is called Singleton.
Have you ever come across Remoting? You send a request to a server. There is a choice between Singleton and SingleCall. It basically means that you:
- Always use the same object or
- create a new object for each request.
Let’s say you order 4 pints of beer using your tablet PC rather than calling the sexy, blond, and 18-year-old waitress. You obviously want 4 pints at once. Therefore the correct choice would be SingleCall; 4 distinct objects. The geeky waitress reacts. She responds via her high-tech cash register: “Who are you?”. She could ask that 10 times and unless you get upset, you would always give the same answer. Any good programmer realizes that this would only require one object instance – a Singleton.
There are several ways to do this. The conceptual idea is pretty easy. (Wikipedia has some more details.) In this post I am only giving you my favourite pattern, which should always work. You don’t need more unless you want to show off with some cheap stuff.
Example:
Remove the sealed keyword in case you need to make the class inheritable.
Notice the double-check if (_Instance == null) ...
The reason is:
- The first check avoids entering the lock in 99.9999% of the calls. You save precious processor time.
- The second check avoids an unlikely multithreading problem. A thread A could enter the lock and not finish before a thread B arrives. B has to wait in front of the lock. A exits the lock, now B enters the lock. Without the second check, B would now create a new instance. And this is, what we are trying to avoid.
using System; namespace Singleton { public sealed class JustOne { private static readonly object _Lock = new object(); private static JustOne _Instance = null; private JustOne() { } public static JustOne Instance { get { if (_Instance == null) { lock (_Lock) { if (_Instance == null) _Instance = new JustOne(); } } return _Instance; } } // public new string GetHashCode() { return base.GetHashCode().ToString(); } } // class class Program { static void Main(string[] args) { JustOne A = JustOne.Instance; JustOne B = JustOne.Instance; Console.WriteLine("HashCode of object A: " + A.GetHashCode()); Console.WriteLine("HashCode of object B: " + B.GetHashCode()); Console.ReadLine(); } // main } // class } // namespace
Facade Pattern
Don’t shoot the messenger!
This is something that you are doing all the time. We just name it now. The Facade Pattern is a structural programming design pattern. To explain it in a nutshell:
A class contains many references to objects, which are invisible to the client. The client has a reduced command set to keep things simple.
The class receives the simple command and takes care about the real complexity behind the facade, which is presented to the client. Think of a cash dispenser. All you have to know is a few buttons. The legal structure, the buildings, the accounting, the risk etc. … all is invisible to the client, who only cares about getting cash at this very moment.
namespace FacadePattern { internal class Burger { public void Prepare() { } public void WarmUp() { } public void Wrap() { } } // class internal class Fries { public void Fry() { } public void KeepWarm() { } } // class internal class Drink { public enum eDrink { Coke, SevenUp, Orange, Apple, Milk, Tea, Coffee } public bool IsSugarFree { set; get; } public bool IsHot { set; get; } public void Fill(eDrink xDrink) { } } // class internal class Extras { public void AddSalt() { } public void AddKetchup() { } public void AddMayo() { } public void AddNapkin() { } } // class public class MealFacade { private Burger _Burger = new Burger(); private Fries _Fries = new Fries(); private Drink _Drink = new Drink(); private Extras _Extras = new Extras(); public void MakeClientHappy() { _Drink.IsHot = false; _Drink.IsSugarFree = true; _Drink.Fill(Drink.eDrink.Coke); _Fries.Fry(); _Burger.Prepare(); _Burger.Wrap(); _Extras.AddKetchup(); _Extras.AddSalt(); _Extras.AddNapkin(); } // } // class class Program { static void Main(string[] args) { MealFacade lBurgerMeal = new MealFacade(); lBurgerMeal.MakeClientHappy(); } // main } // class } // namespace
Prototype Pattern
Sometimes the creation of new objects is time and resource intensive. You could create a thousand objects during the program initialization and park them on a queue. The object would then be ready when needed. And looking at the Garbage Collection process in more detail, you may notice that the Generation has probably changed by then. Your object requires less processor time the older it becomes.
But this is not the topic today. It just has a similar idea. We are talking about time and/or resource intensive object creation.
The Prototype Pattern is used for cloning objects. Cloning can be substantially faster than initializing objects from scratch. Let’s say object A did load a lot of data from a file. You don’t have to do the same for object B. Simply copy object A and amend some fields.
Here is the pattern:
public interface IChocolateBar { IChocolateBar Clone(); } // interface public class MintChocolateBar : IChocolateBar { public readonly int ObjectNumber; public MintChocolateBar(int xObjectNumber) { ObjectNumber = xObjectNumber; } public IChocolateBar Clone() { return MemberwiseClone() as MintChocolateBar; } } // class public class DarkChocolateBar : IChocolateBar { public readonly int ObjectNumber; public DarkChocolateBar(int xObjectNumber) { ObjectNumber = xObjectNumber; } public IChocolateBar Clone() { return MemberwiseClone() as DarkChocolateBar; } } // class public class CloneFactory { public IChocolateBar get(IChocolateBar xChocolateBar) { return xChocolateBar.Clone(); } } // class
The pattern is not really satisfying. Is there something better? C# offers the ICloneable interface.
public class Shortcut : ICloneable { public readonly int ObjectNumber; public Shortcut(int xObjectNumber) { ObjectNumber = xObjectNumber; } public object Clone() { return MemberwiseClone(); } } // class
The problem with this interface is the missing generic type. In fact the use is obsolete and Microsoft does not recommend it anymore. We therefore build our own implementation.
public class Shortcut2 { public readonly int ObjectNumber; public Shortcut2(int xObjectNumber) { ObjectNumber = xObjectNumber; } public Shortcut2 ShallowCopy() { return MemberwiseClone() as Shortcut2; } } // class
Using an interface like
interface IShallowCopy<T> { T IShallowCopy(); } // interface public class Shortcut3<T> : IShallowCopy<T> { public readonly int ObjectNumber; public Shortcut3(int xObjectNumber) { ObjectNumber = xObjectNumber; } public T ShallowCopy() { return MemberwiseClone() as T; } } // class
is nonsense. You cannot compile and instantiate this.
What else could we do? A static clone method quickly leads us back to a factory similar type. Hence we end up with something that we were having at the very beginning today. Just keep your solutions generic and you should be fine with this pattern.
MemberwiseClone()
We were using MemberwiseClone() to keep the example source code simple. The following is important to know:
MemberwiseClone() is a shallow copy. If a field of the copied object is a reference type, the reference is copied but the referred object is not; therefore, the original object and its clone refer to the same object.
To avoid the same references in the clone, you have to write your own Deep Copy or Lazy Copy. Your clone method must clone the object and objects inside the object.
A practical example:
Stock exchange orders need to be sent with a minimal delay. The fight for nanoseconds is tremendous. Companies even shorten the physical server cables to the exchanges in order to increase speed. One foot in length equals roughly one nanosecond these days.
The object creation for orders takes too long in the proprietary business. It is meaningful to generate orders before any decision is made. The next order sits in a queue of clones. When the machine decides to trade, then the order is taken from that queue and a few fields are populated/overridden. These are eg. trade size and price. There is no memory allocation at this late stage. As said, each nanosecond counts.
Full source code
Notice that
Console.WriteLine("ObjectNumber = " + lMintClone.ObjectNumber);
prints the same number as the original object. There are two objects at two locations in the RAM. Therefore the HashCode is different. Still the field content is the same.
using System; namespace PrototypePattern { public interface IChocolateBar { IChocolateBar Clone(); } // interface public class MintChocolateBar : IChocolateBar { public readonly int ObjectNumber; public MintChocolateBar(int xObjectNumber) { ObjectNumber = xObjectNumber; } public IChocolateBar Clone() { return MemberwiseClone() as MintChocolateBar; } } // class public class DarkChocolateBar : IChocolateBar { public readonly int ObjectNumber; public DarkChocolateBar(int xObjectNumber) { ObjectNumber = xObjectNumber; } public IChocolateBar Clone() { return MemberwiseClone() as DarkChocolateBar; } } // class public class CloneFactory { public IChocolateBar get(IChocolateBar xChocolateBar) { return xChocolateBar.Clone(); } } // class // IClonable is non-generic public class Shortcut : ICloneable { public readonly int ObjectNumber; public Shortcut(int xObjectNumber) { ObjectNumber = xObjectNumber; } public object Clone() { return MemberwiseClone(); } } // class public class Shortcut2 { public readonly int ObjectNumber; public Shortcut2(int xObjectNumber) { ObjectNumber = xObjectNumber; } public Shortcut2 ShallowCopy() { return MemberwiseClone() as Shortcut2; } } // class class Program { static void Main(string[] args) { CloneFactory lCloneFactory = new CloneFactory(); MintChocolateBar lMint = new MintChocolateBar(1); MintChocolateBar lMintClone = lCloneFactory.get(lMint) as MintChocolateBar; Console.WriteLine("Original object: "); Console.WriteLine("HashCode = " + lMint.GetHashCode()); Console.WriteLine("ObjectNumber = " + lMint.ObjectNumber); Console.WriteLine(); Console.WriteLine("Clone: "); Console.WriteLine("HashCode = " + lMintClone.GetHashCode()); Console.WriteLine("ObjectNumber = " + lMintClone.ObjectNumber); // !!! Console.WriteLine(); Console.WriteLine("Are the objects the same? " + (lMint == lMintClone)); DarkChocolateBar lDark = new DarkChocolateBar(2); DarkChocolateBar lDarkClone = lCloneFactory.get(lDark) as DarkChocolateBar; Console.WriteLine(); Console.WriteLine(); Console.WriteLine(); Console.WriteLine("Dark chocolate: "); Console.WriteLine("Are the objects the same? " + (lMint == lMintClone)); // old school Shortcut lShort = new Shortcut(3); Shortcut lShortClone = lShort.Clone() as Shortcut; Console.WriteLine(); Console.WriteLine("ICloneable: "); Console.WriteLine("Are the objects the same? " + (lShort == lShortClone)); Console.ReadLine(); } // } // class } // namespace
example output:
Original object:
HashCode = 62125865
ObjectNumber = 1Clone:
HashCode = 44200505
ObjectNumber = 1Are the objects the same? False
Dark chocolate:
Are the objects the same? FalseICloneable:
Are the objects the same? False