Monday, November 14, 2011

NLog Network Target

Recently at work, I'd been tasked with utilizing NLog's targeting system to dump data into our system.  NLog itself has been working really well for us, but the downside is that the documentation leaves a lot to be desired.  Furthermore, examples and samples are extremely limited.

So, how in the world do we utilize this?

My first thought was to tear everything open in .NET Reflector (ILSpy, since I can't find a free copy of .NET Reflector anymore) and then work to understand how it works.

The targets we were most interested in were the Network and Memory targets -- such that we could grab data that was being logged and then further process it.  Why not have our complex-event processing system also process logs as well?  A self-logging system.  Hell, why not?  Also, doing what your boss asks is generally a good way to stay employed.

The Network Target


So, the network target.  It handles several different variations of address -- UDP, TCP, variations of IP4/6.

The standard attack pattern for this is actually pretty much the same as any other TCP/UDP application.  Manage your clients (if necessary) and then process the data.


The only difference is that handling the data is different.  The chart above shows the general jist.

  1. When reading from the socket, convert your incoming data to a string.
  2. Ensure that it is decoded properly -- by default, your message will be in UTF8.
  3. Store message in a buffer.
  4. Scan for end of line characters and process as necessary.
It's pretty simple.  A very simple handler would look like the following:

  string incomingMessage = UTF8Encoding.ASCII.GetString(incomingSocketBuffer, 0, incomingLength);
  incomingStringBuffer.Append(incomingMessage);
  //Process and analyze for "\r\n"

Not bad, eh?  The above code assumes that incomingSocketBuffer is what was received from the Socket's Receive method, and the incomingLength is the length of what was received.  incomingStringBuffer is a StringBuilder that I use to store up the data.

Of course, there are much better ways of handling this, but this is the most simplistic and hopefully it demystifies NLog's Network target.

Friday, September 23, 2011

Heisenbugs! Schrödinbugs! Multi-Threading Programming, Quantum Mechanics, and You!

My team leader has a saying for strange bugs popping up -- Heisenbugs.  Your code is correct.  Everything should be fine.  However, for some reason...  BOOM!  Exception.  You lose some hair.  I think a more appropriate name is Schrödinbugs, though.  They appear to be correct and if you step through them, they'll work.  However, the second you stop observing them, they always seem to have the potential for a different result.  Ahhh...  unpredictability!

This is frustrating, but I've noticed one of the biggest problems generally stems from multi-threading.  Most developers aren't tuned to developing multi-threaded applications.  Even when they are, it's just another thing to watch out for when developing code.

So, you may be writing an application in WPF.  Say, it subscribes to an asynchronous TCP socket at the application level.  You have a callback on a user control.  Is there a potential problem?

YES.

Any time you have another resource that can act of its own accord and interface with another thread (events to the user interface, for example), you have a chance of having a Schrödinbug!  For example, at work I had a strange issue -- a control would hit the end of its life-cycle.  Disposed and all was well, right?  Well, not quite.  I had a DispatcherTimer that was syncing up some things for that control.  I stopped it in Dispose -- so the timer shouldn't be called, right?

Wrong.

The timer did stop -- but it had already entered its callback on the event thread.  The thread then swapped back to handle the Dispose that I had called.  It finished the Dispose, then went back to the event callback to finish.  Surprise surprise!  The control had been disposed and threw an exception.  So, how do we get around this?

I've developed a fairly simple pattern...  using a lock and the basic Disposable pattern.  I'm attaching the basic skeleton on how to implement this in your code:


    public class MyClass : IDisposable
    {  
        private object _lock = new object();
 
        #region IDisposable Pattern
 
        private Boolean _disposed = false;
 
        private void OnEventCallback(object sender, EventArgs e)
        {
            lock(_lock)
            {
                if( _disposed)
                    return;
 
                // Handle callback here
            }
        }
 
        /// <summary>
        /// When called, throws an ObjectDisposedException if the object has been disposed.
        /// </summary>
        protected virtual void CheckDisposed()
        {
            if (_disposed)
            {
                throw new ObjectDisposedException(this.GetType().Name);
            }
        }
 
        /// <summary>
        /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
        /// </summary>
        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }
 
        /// <summary>
        /// Core dispose methods
        /// </summary>
        /// <param name="disposing">True if called from IDisposable::Dispose</param>
        protected virtual void Dispose(bool disposing)
        {
            lock (_lock)
            {
                if (disposing && !_disposed)
                {
                    // Clean up managed resources here
                }
 
                _disposed = true;
            }
        }
 
        /// <summary>
        /// Releases unmanaged resources and performs other cleanup operations before the
        /// <see cref="MyClass"/> is reclaimed by garbage collection.
        /// </summary>
        ~MyClass()
        {
            Dispose(false);
        }
 
        #endregion
    }


Notice the lock around the two most important parts -- I wanted to make sure that I have critical sections on the _disposed, such that I can break out as necessary.  Notice, if it enters the thread for the callback, we're fine.  If it disposes on the other thread, we can still break out before the code hits something disposed.  Essentially, we're making textbook critical sections and managing them appropriately.

Nothing unusual or entirely special -- just adapted to be mindful of another thread.

Wednesday, September 7, 2011

Control Lifecycle Gotcha's in Silverlight

I've come acrosss some more "fun" in Silverlight.  One of the most irritating (and not very well documented) pieces involves the tear-down and destruction of your controls.  Creation of controls is pretty simple, with a few caveats.

Control Creation


When a control or page is created in Silverlight, if the child controls are not visible, they are not "created."  Rather, they are created when they become visible.  For instance, if you have a Container control of some kind (Grid, etc) that is Collapsed, all of the child controls will not be created until it becomes visible.  Given how the rendering/layout engine works in WPF and Silverlight, this kind of makes sense -- only worry about what is visible.

Control Teardown and Destruction


The Unloading event occurs in a different order.


This is the most irritating part for me, as a developer.  Primarily because it doesn't make a whole lot of sense to me and is rather different compared to other frameworks.

Let's start with what we would think should happen, normally.  Supposing you had controls each in a hierarchy of:

A is the parent of B, which is the parent of C.

You would think C gets Unloaded first, then B, then A.

It's the exact opposite.

A is Unloaded, then B, then C.

If you have something, for instance, at point B that needs to be taken care of before C, you'll have some very frustrating issues ahead of you.  For example, C may consume resources that are created in B (such as a service).  Suppose the control is closed, B will attempt to clean up its resources before C does (assuming you've built your controls cleanly).  So, if C is still trying to access the resource created at the scope of B...  C will blow up with all kinds of exceptions.

Finalizers are called upon Application exit.

Not much to be said here -- whereas WPF and WinForms call finalizers generally as soon as the references disappear, Silverlight nukes them upon Application exit.  So, if you want to free up resources, you need to do that beforehand.

In Closing

In short, writing Silverlight is a bit more complicated and doesn't handle things quite as easily as other frameworks we're used to.  However, knowing the afore mentioned, you should be able to make your code cleaner and more efficient.

Tuesday, September 6, 2011

'x' was already registered by 'y' in Silverlight and WPF

So, I've had the extreme pleasure of working with a lot of Silverlight recently -- and my code in WPF had never been tested with multiple controls (stupid me).  When I did, I got all kinds of errors about properties not being set correctly, and eventually, after commenting out enough, I received the error

"'X' was already registered by 'Y.'"

So looking deeper, I notice it always happens on the second element.  Weird.  Looking further, I notice that my DependencyProperty pattern is basically declared at a private-instance level, i.e.:
DependencyProperty TitleProperty = DependencyProperty.Register("Title"typeof(string), typeof(SomeControl), new PropertyMetadata(string.Empty));
In Silverlight, this isn't a big deal.  In WPF, it's a deal-breaker.  It appears that Silverlight can automatically handle instance-level dependency properties (or more likely, translating bad code into them).  In WPF, it's not as forgiving and needs to be prefaced by:
public static readonly 
i.e.,
public static readonly DependencyProperty TitleProperty = DependencyProperty.Register("Title"typeof(string), typeof(SomeControl), new PropertyMetadata(string.Empty));

With that, everything works again and my Silverlight code doesn't break either.

Interesting difference between WPF and Silverlight, for sure.

Tuesday, August 23, 2011

Thank you Bing Maps!

After enough crying from developers, Bing Maps has apparently *finally* released a WPF control.

I had my solution *nearly* working -- with a few bugs I was going to ask Microsoft about in relation to accessing via quad-keys and getting a tile based on latitude/longitude via their web services.  Go to the blog and ten minutes prior to me arriving, they announced the official Bing Maps control for WPF.

Rejoice, friends!  Go get it!

http://www.bing.com/community/site_blogs/b/maps/archive/2011/08/23/announcing-the-bing-maps-wpf-control.aspx

Friday, August 19, 2011

I Want the World - A Thought Exercise in Building Map Controls for WPF and Silverlight

My latest task has been to build a Map control for our API at work, which has proven to be quite challenging.  Given that the Silverlight Toolkit is open source, it's easy to take the code, recompile it, adjust it so that it works for WPF, and then run with the customizations.

However, no developer has a good implementation of an open source map control that spans both Silverlight and WPF at the moment, which is a pain at the moment.

I've come up with the following plan to build something based off of Bing Maps:


  1. Use Bing Maps for Silverlight, but abstract all control/controls (except for the DeepZoom map tiles) out.
  2. Implement the map tiles via the WPF Bing Maps bindings.
  3. All layers on top will have to be built separately.
So, my first task has been to extract a lot of the functionality out of what has been given at Bing Maps (http://msdn.microsoft.com/en-us/library/bb259689.aspx).  Bing Maps works in a very interesting way.  At each "zoom level," the map's true size in pixel's increases.  At the base level (1 -- highest out), it is 512 x 512. For each level after that, the dimensions are multiplied by 2 (zoom level 2 = 1024 x 1024; zoom level 3 = 2048 x 2048; etc).  The highest zoom makes the map EXCESSIVELY large.  Mind you, only a few tiles in that space have been loaded though.

So, we need to make sure all "layers" on top of the map are done independently of the natural API of the Bing Maps control provided in Silverlight.  As such, I've built a wrapper to handle converting latitude/longitude to the pixel-based coordinate system that Bing Maps likes to use.  When the view is changed, the map will then update all controls as it moves.

If I can get my architect's permission, I'll likely be taking some of this code (only for the WPF version) and dropping it into CodePlex and/or MSDN, given that nobody has written a *decent* WPF Bing Maps control that's open.  I know there are quite a few on CodePlex, but the issue is that they're either shoddy implementations (too many layers of code/disorganization, poor code, running the AJAX version through a web browser control), or they're outdated and will stop working as the end of 2011, due to lack of support for the old Virtual Earth API.  Rather than any of these indirect implementations, I'll hopefully be posting a true WPF-based solution that relies on the Bing Maps web services with native WPF controls.

Wednesday, July 20, 2011

Silverlight and WPF Measurement Pain

One of the more irritating things I've been dealing with in Silverlight and WPF is that sizing and automatic content placement is a pain.  Don't get me wrong -- I love the new rendering engine and how it works to update the layout, but it can be a pain to "think in terms of WPF or Silverlight."  Especially when the two don't exactly have the same methods of working.

I made a decision fairly early on to build a static Utilities class, which holds all of my ugly code where I have to use the very, very, very fun

#if SILVERLIGHT            

#else

#endif

constructs, which gets me to the point of this post.

It's difficult to determine the size of a control -- especially the size it wants to be.  Ideally, yes, the DesiredSize will have that exact size.  Unfortunately, the DesiredSize is somewhat misleading -- it's the DesiredSize of the space it's confined to.  In addition, it works totally different between Silverlight and WPF.

I was primarily concerned with sizing things before they are rendered (they have no parent).  This is drastically different from figuring out a size once they are in the layout tree and the control itself has a parent.

In any case, I'm only going to cover the basics.  The most simple way to determine the size something wants to take up is to do artificially measure the element and then check the desired size.  Assuming I have a TextBlock named Frank, the following code would determine the size Frank really wants:

Frank.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity));
Frank.Height = Frank.DesiredSize.Height;
Frank.Width = Frank.DesiredSize.Width;

Ah, a crafty trick (and it works in both Silverlight and WPF without a hitch; if Frank didn't have a parent, the code would be different between the two platforms).  We make the control believe it has unlimited space, and then we can use DesiredSize.  Play with it a little bit -- set a breakpoint on DesiredSize before and after this call and see the difference.

For more information about how the Layout system works (which is an excellent read for understanding how WPF/Silverlight work), check out this MSDN article: http://msdn.microsoft.com/en-us/library/ms745058.aspx

Thursday, July 14, 2011

The XAML Message From Hell: "Error HRESULT E_FAIL has been returned from a call to a COM component."

The most irritating thing in XAML-based projects (Silverlight, WPF) is the infamous "Error HRESULT E_FAIL has been returned from a call to a COM component."

Why Microsoft didn't decide to catch it and give a more appropriate exception escapes me.  However, some things I've learned about this:

Your XAML is failing to load!


Now, your XAML may actually be correct, is the funny thing -- but maybe your project is missing the references.  For example, I'm using the Silverlight Toolkit and setting styles at runtime on the fly, allowing for potential theming.  I kept getting this error, even though my other projects which use the same code are building fine -- so why is my latest project failing to build?

I missed a reference that was used in the other project.  When it came to load the XAML style, it was likely getting hung up on the missing reference and saying, "OK, I see you want to use System.Windows.Controls.Layout.Toolkit...  but what in the world is that?"

To rectify this issue, it was necessary to add references all over again.

So, my troubleshooting advice is:

  1. Make sure the XAML is correct.  When writing cross-platform (i.e. Silverlight and WPF), some of the controls/targets behave differently or have different properties.  Visual Studio generally points this out as a build error.
  2. Make sure that you are referencing all dependent assemblies.  Due to Silverlight's dependencies, if I write a library on top of Silverlight Toolkit, which then gets used in an application, that application needs to have the references to Silverlight Toolkit.  
Good luck and when in doubt -- get an extra set of eyes!

Wednesday, July 13, 2011

Embedding (Silverlight) Content in SharePoint Webparts

I'm going to start this off by saying that I am, by no means, a SharePoint expert.  Developing for SharePoint is painful, but also rewarding.  When it works, you feel an immense amount of pride that your solution worked after all of your labor.  However, there's the immeasurable pain and headaches that come from attempting to write it.

That being said, I did find a very clever way of embedding a piece of content (in my case, a Silverlight xap -- but this could be anything, a JPEG, PNG, MP3, etc) into a SharePoint webpart.  Given my background of making everything work on multiple platforms, I wanted to have the simplest possible way of doing this, without having to continually go back and forth with new code.  Given I'm also trying to write a platform of tools and controls, this enables me to make a standardized package where we're not going to have conflicts with different versions of a chunk of content in the layouts folder with different assemblies/features installed.

The jist of this is that we're going to have ASP.NET share the content through a compiled DLL.  Seems complicated?  Not as much as you'd think.  It's a relatively simple process:
  1. Add content to your project.
  2. Add information about the resource to your assembly.
  3. Utilize the resource.
First things first -- make sure you have a SharePoint project setup in Visual Studio 2010.  I imagine this will probably work in prior versions of Visual Studio, but I haven't tested it.

1. Add content to your project.

Originally, I wanted to do things the "right" way for embedding my content -- I wanted to add each file into the mapped Layouts folder that Visual Studio 2010 gracefully provides.  However, a minor issue arose from this -- my content is changing dynamically, and I needed to add it as a linked item (like the way I've done with Silverlight and WPF controls).  Since the file is linked and not actually in the folder, Visual Studio doesn't have it in the directory and thus, it is not built.  You could potentially make a script to copy it back/forth after the content is built (in my case, it's a Silverlight xap), but then you have issues with checking it out, etc.

Instead, we want to link it, since that's much, much, much easier.  It prevents a lot of issues that could also result with conflicting and different features, in the event of any major issues with deployment.

So, I created a folder in my project called "Resources" where I would link this in.  In this example, I have a Silverlight application called "HelloWorld.xap" and will be linking in the existing xap from the Release directory.  Make sure that this is included as an "Embedded Resource" from the "Build Actions."

Gotta love our Hello World applications!

Now, that we have that done, we can get to the slightly uglier part.

2. Add information about the resource to your assembly.

In the SharePoint project, we need to open up AssemblyInfo.cs under Properties and edit it very minorly.  We want to add in the new resource we have.  I had to add in a reference to System.Web, and you likely will too.

At the bottom of the file, you will need to add one entry per resource, as follows:


[assembly: System.Web.UI.WebResource("EmbeddedSPContent.Resources.HelloWorld.xap""application/x-silverlight-2")]

The first parameter of System.Web.UI.WebResource is the name of the file and its location in the project.  Notice that to notate paths/directories, we need to use periods instead of slashes.

The second parameter of System.Web.UI.WebResource is the mime-type.  What do you want the DLL to tell the browser that the file is?  In my case, I want it to be recognized as a Silverlight application.  This could potentially be a PNG, MP3, and so forth.

Still hanging on there?  Cool, because we're almost done.


3. Utilize the resource.

Ah, yes -- the most important part.  We have to actually use it now.  But that's simple.  I'm going to build a pretty standard WebPart and override RenderContents.


I added the following code to render it (a very quick/dirty Silverlight HTML mockup):


            string resourceUrl = Page.ClientScript.GetWebResourceUrl(GetType(), "EmbeddedSPContent.Resources.HelloWorld.xap");
 
            string control = @"
            <div id=""silverlightControlHost"">
                <object data=""data:application/x-silverlight-2,"" type=""application/x-silverlight-2"" width=""400px"" height=""400px"">
                    <param name=""source"" value=""{MY_URL}"" />
                    <param name=""minRuntimeVersion"" value=""4.0.50826"" />
 
                    <a href=""http://go.microsoft.com/fwlink/?LinkID=149156&amp;v=4.0.50826.0"" style=""text-decoration:none"">
                        <img src=""http://go.microsoft.com/fwlink/?LinkId=108181"" alt=""Get Microsoft Silverlight"" style=""border-style:none"" />
                    </a>
                </object>
            </div>";
 
            control = control.Replace("{MY_URL}", resourceUrl);
 
            writer.Write(control);


and voila, it works!

I know what you're thinking -- that's a sexy web part.

I'm including a sample on MSDN for others to use, so this will hopefully make it easier to follow what was done:

http://code.msdn.microsoft.com/Embedding-Resources-for-d61b251d

Please note that in order to get this working, I had to deploy it as a Farm Solution, rather than a Sandboxed Solution.

Tuesday, July 12, 2011

SplineSeries for the Silverlight Toolkit

While the Silverlight Toolkit has made some amazing strides in improving, it still lacks some functionality compared to other toolkit offerings.  In particular, Silverlight Toolkit's charts lack splines, or smoothed lines.  The idea here is that we don't want the graph to appears as though a line is moving from point to point directly -- that it moves parabolically, or softer.

A typical line series.

Now, this is all fun and games, but can we get something where transitions are more smooth?  Yes, we can.

A  spline series.

Notice, the spline series changes are more gradual and curved.  Are they an entirely accurate representation of the in-between?  No, not always -- but they're not meant to be (necessarily).

The Spline Series is literally a copy/paste of the LineSeries, with a few changes.  Note that this is located under the Charting/Series folder of the DataVisualization.Toolkit project.  Essentially, what we want to do is change the Polyline to a Path.  The idea here is that a Polyline doesn't draw Beziers.  Below is my (large) code,

SplineSeries.cs:

// (c) Copyright Microsoft Corporation.
// This source is subject to the Microsoft Public License (Ms-PL).
// Please see http://go.microsoft.com/fwlink/?LinkID=131993 for details.
// All other rights reserved.
 
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Windows.Media;
using System.Windows.Shapes;
 
#if !DEFINITION_SERIES_COMPATIBILITY_MODE
 
namespace System.Windows.Controls.DataVisualization.Charting
{
    /// <summary>
    /// Represents a control that contains a data series to be rendered in X/Y 
    /// line format.
    /// </summary>
    /// <QualityBand>Preview</QualityBand>
    [StyleTypedProperty(Property = DataPointStyleName, StyleTargetType = typeof(LineDataPoint))]
    [StyleTypedProperty(Property = "LegendItemStyle", StyleTargetType = typeof(LegendItem))]
    [StyleTypedProperty(Property = "PathStyle", StyleTargetType = typeof(Path))]
    [TemplatePart(Name = DataPointSeries.PlotAreaName, Type = typeof(Canvas))]
    [SuppressMessage("Microsoft.Maintainability""CA1501:AvoidExcessiveInheritance", Justification = "Depth of hierarchy is necessary to avoid code duplication.")]
    public partial class SplineSeries : LineAreaBaseSeries<LineDataPoint>
    {
        #region public PointCollection Points
        /// <summary>
        /// Gets the collection of points that make up the spline.
        /// </summary>
        public PointCollection Points
        {
            get { return GetValue(PointsProperty) as PointCollection; }
            private set { SetValue(PointsProperty, value); }
        }
 
        /// <summary>
        /// Identifies the Points dependency property.
        /// </summary>
        public static readonly DependencyProperty PointsProperty =
            DependencyProperty.Register(
                "Points",
                typeof(PointCollection),
                typeof(SplineSeries),
                null);
        #endregion public PointCollection Points
 
        #region public PathGeometry SplinePoints
        /// <summary>
        /// Gets the collection of points that make up the line.
        /// </summary>
        public PathGeometry SplinePoints
        {
            get { return GetValue(SplinePointsProperty) as PathGeometry; }
            private set { SetValue(SplinePointsProperty, value); }
        }
 
        /// <summary>
        /// Identifies the SplinePoints dependency property.
        /// </summary>
        public static readonly DependencyProperty SplinePointsProperty =
            DependencyProperty.Register(
                "SplinePoints",
                typeof(PathGeometry),
                typeof(SplineSeries),
                null);
        #endregion public PathGeometry SplinePoints
 
        #region public double SplineTension
 
        /// <summary>
        /// Gets or sets the tension in the beziers that make up the spline.
        /// </summary>
        /// <remarks>
        /// The greater the tension, the more straight/linear the spline will look.
        /// Less tension creates a more curvy spline.
        /// </remarks>
        public double SplineTension
        {
            get { return (double) GetValue(SplineTensionProperty); }
            set { SetValue(SplineTensionProperty, value); }
        }
 
        /// <summary>
        /// Identifies the SplineTension dependency property.
        /// </summary>
        public static readonly DependencyProperty SplineTensionProperty =
            DependencyProperty.Register(
                "SplineTension",
                typeof(double),
                typeof(SplineSeries),
                new PropertyMetadata(2.5));
        #endregion public double SplineTension
 
        #region public Style PathStyle
        /// <summary>
        /// Gets or sets the style of the Path object that follows the data 
        /// points.
        /// </summary>
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming""CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Path", Justification = "Matches System.Windows.Shapes.Path.")]
        public Style PathStyle
        {
            get { return GetValue(PathStyleProperty) as Style; }
            set { SetValue(PathStyleProperty, value); }
        }
 
        /// <summary>
        /// Identifies the PathStyle dependency property.
        /// </summary>
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming""CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Path", Justification = "Matches System.Windows.Shapes.Path.")]
        public static readonly DependencyProperty PathStyleProperty =
            DependencyProperty.Register(
                "PathStyle",
                typeof(Style),
                typeof(SplineSeries),
                null);
        #endregion public Style PathStyle
 
#if !SILVERLIGHT
        /// <summary>
        /// Initializes the static members of the LineSeries class.
        /// </summary>
        [SuppressMessage("Microsoft.Performance""CA1810:InitializeReferenceTypeStaticFieldsInline", Justification = "Dependency properties are initialized in-line.")]
        static SplineSeries()
        {
            DefaultStyleKeyProperty.OverrideMetadata(typeof(SplineSeries), new FrameworkPropertyMetadata(typeof(SplineSeries)));
        }
 
#endif
        /// <summary>
        /// Initializes a new instance of the LineSeries class.
        /// </summary>
        public SplineSeries()
        {
#if SILVERLIGHT
            this.DefaultStyleKey = typeof(SplineSeries);
#endif
        }
 
        /// <summary>
        /// Acquire a horizontal linear axis and a vertical linear axis.
        /// </summary>
        /// <param name="firstDataPoint">The first data point.</param>
        protected override void GetAxes(DataPoint firstDataPoint)
        {
            GetAxes(
                firstDataPoint,
                (axis) => axis.Orientation == AxisOrientation.X,
                () =>
                {
                    IAxis axis = CreateRangeAxisFromData(firstDataPoint.IndependentValue);
                    if (axis == null)
                    {
                        axis = new CategoryAxis();
                    }
                    axis.Orientation = AxisOrientation.X;
                    return axis;
                },
                (axis) => axis.Orientation == AxisOrientation.Y && axis is IRangeAxis,
                () =>
                {
                    DisplayAxis axis = (DisplayAxis)CreateRangeAxisFromData(firstDataPoint.DependentValue);
                    if (axis == null)
                    {
                        throw new InvalidOperationException(Properties.Resources.DataPointSeriesWithAxes_NoSuitableAxisAvailableForPlottingDependentValue);
                    }
                    axis.ShowGridLines = true;
                    axis.Orientation = AxisOrientation.Y;
                    return axis;
                });
        }
 
        /// <summary>
        /// Updates the Series shape object from a collection of Points.
        /// </summary>
        /// <param name="points">Collection of Points.</param>
        protected override void UpdateShapeFromPoints(IEnumerable<Point> points)
        {
            if (points.Any())
            {
                PointCollection pointCollection = new PointCollection();
                foreach (Point point in points)
                {
                    pointCollection.Add(point);
                }
 
                //At least two points are necessary to generate a proper spline
                if (pointCollection.Count >= 2)
                {
                    PathGeometry geometry = new PathGeometry();
                    PathFigure figure = new PathFigure();
 
                    PointCollection bezierPoints = GetBezierPoints(pointCollection);
 
                    figure.StartPoint = bezierPoints[0];
                    for (int i = 1; i < bezierPoints.Count; i += 3)
                    {
                        figure.Segments.Add(new BezierSegment()
                            {
                                Point1 = bezierPoints[i],
                                Point2 = bezierPoints[i + 1],
                                Point3 = bezierPoints[i + 2]
                            });
                    }
 
                    geometry.Figures.Add(figure);
                    SplinePoints = geometry;
                }
                else
                {
                    SplinePoints = null;
                }
 
                Points = pointCollection;
            }
            else
            {
                Points = null;
                SplinePoints = null;
            }
        }
 
        #region Bezier Curve Building
 
        /*
         * Formulas and code pulled from Kerem Kat's MapBezier example:
         * http://www.codeproject.com/KB/silverlight/MapBezier.aspx
         */ 
 
        private PointCollection GetBezierPoints(PointCollection pts)
        {
            PointCollection ret = new PointCollection();
 
            for (int i = 0; i < pts.Count; i++)
            {
                // for first point append as is.
                if (i == 0)
                {
                    ret.Add(pts[0]);
                    continue;
                }
 
                // for each point except first and last get B1, B2. next point. 
                // Last point do not have a next point.
                ret.Add(GetB1(pts, i - 1, SplineTension));
                ret.Add(GetB2(pts, i - 1, SplineTension));
                ret.Add(pts[i]);
            }
 
            return ret;
        }
 
        private Point GetB1(PointCollection pts, int i, double a)
        {
            Point  derivedPoint = GetDerivative(pts, i, a);
            return new Point(pts[i].X + derivedPoint.X / 3, pts[i].Y + derivedPoint.Y / 3);
        }
 
        private Point GetB2(PointCollection pts, int i, double a)
        {
            Point derivedPoint = GetDerivative(pts, i+1, a);
            return new Point(pts[i + 1].X - derivedPoint.X / 3, pts[i + 1].Y - derivedPoint.Y / 3);
        }
 
        private Point GetDerivative(PointCollection pts, int i, double a)
        {
            if (pts.Count < 2)
                throw new ArgumentOutOfRangeException("pts""Data must contain at least two points.");
  
            if (i == 0)
            {
                // First point.
                return new Point((pts[1].X - pts[0].X) / a, (pts[1].Y - pts[0].Y) / a);
            }
            if (i == pts.Count - 1)
            {
                // Last point.
                return new Point((pts[i].X - pts[i - 1].X) / a, (pts[i].Y - pts[i - 1].Y) / a);
            }
  
            return new Point((pts[i + 1].X - pts[i - 1].X) / a, (pts[i + 1].Y - pts[i - 1].Y) / a);
        }
        #endregion
    }
}
 
#endif


Note that I borrowed my Spline/Bezier code from Kerem Kat's example: http://www.codeproject.com/KB/silverlight/MapBezier.aspx

Essentially what it does, is takes prior points to adjust such that they curve into the next.  The UpdateShapeFromPoints method was changed from the standard LineSeries and uses all of the helper methods that were added to calculate a Bezier curve.

We're pretty much almost done, except for one more minor touch.  We need to have the default style included, such that it complies with how Silverlight Toolkit handles it's control templating.  We add the following chunk of code to Themes\generic.xaml of the same project:


    <!--  charting:SplineSeries  -->
    <Style TargetType="charting:SplineSeries">
        <Setter Property="IsTabStop" Value="False" />
        <Setter Property="PathStyle">
            <Setter.Value>
                <Style TargetType="Path">
                    <Setter Property="StrokeThickness" Value="2" />
                    <Setter Property="StrokeMiterLimit" Value="1" />
                </Style>
            </Setter.Value>
        </Setter>
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="charting:SplineSeries">
                    <Canvas x:Name="PlotArea">
                        <Path Data="{TemplateBinding SplinePoints}" Stroke="{TemplateBinding Background}" Style="{TemplateBinding PathStyle}"/>
                        <Polyline Points="{TemplateBinding Points}" />
                    </Canvas>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>

Now, just recompile the Toolkit and you should be good to go!

I've included a "patch" with these files and their updates -- they should be capable of being pasted over their old versions (the Themes\generic.xaml just has the SplineSeries.xaml pasted into it -- I would strongly recommend you doing this with your own source):

https://docs.google.com/viewer?a=v&pid=explorer&chrome=true&srcid=0B9hGvs6yJgfJNzA4YmE1OTctNzNmYy00MzMzLWJhNDQtNTc0M2FlNTA3NzFm&hl=en_US

Tuesday, June 28, 2011

SilverlightToolkit Development/Building Guidance

If you're like me and want to alter some of Silverlight Toolkit's behavior (or add more functionality to it), chances are your builds will not work perfectly and you'll be in a constant state of mismatched assemblies.

I've noticed that Silverlight Toolkit has some major issues with the entire build process -- only loading different components and making references to other DLL's (which get deleted if you perform a clean build), not other projects.  The second those are removed from the Binaries directory, the entire system goes to hell and back, eventually grabbing references to your DLL's in the Silverlight Toolkit install directory (somewhere in your root drive under Program Files, etc).  What a pain!  Then you'd have to go back and rebuild the references and re-specify their location.  There has to be a better way, right?

Kind of.

What I ended up doing, and I highly recommend this for anyone working with Silverlight Toolkit on a regular basis -- is to build a new solution, rather than use the existing ones.  Don't worry about including their Design or Testing projects, unless they're important to you.  Then follow this process:

1. Build a new solution and include all relevant projects.
As stated before, place everything that you actually care about building.  In my case, I was only concerned about the actual controls - not the testing or design.  Since I'm already heavily involved with using the controls, I'll know if they're broken in test or design scenarios.
2. (Optional) Rename all projects to their full assembly name, rather than a shorthand version.
When viewing their projects, you'll notice things like Controls.Data or System.Controls, which are all very misleading.  Everything falls under System.Windows.*.  For sake of clarity, I found myself renaming them, so when I would eventually add references back to other projects, I could see the full name of the project/assembly built.
3. Change build path in each project, for all build-types, to a single directory.
You'd be surprised how many different places the assemblies for Silverlight Toolkit get built to.  Each project seems to be written by someone else, with their own styles/paths for where assemblies that are built get stored.  I simplified everything and made everything build to the Binaries folder -- always. 
 4. Referenced assemblies from other SDKs should be placed in a special folder under the build path.
This is a pattern we have at work -- if you build something that requires a reference to an SDK other than our own, you drop the assembly in a References project and store everything in source control for the entire team to use.  You won't have to install the toolkits for other team members at this point, since they'll be in a standard location.  For Design and Testing projects, SilverlightToolkit uses other SDKs, so this is vital for those of you wishing to build these.
5. Remove all references to SilverlightToolkit projects and re-add them as a reference to the projects in your solution.
As stated before, the references all get built to different places, which can cause for some crazy issues when you perform a clean.  They then default back to your SilverlightToolkit install.  It's horribly complicated.  Referencing your projects will create appropriate dependencies that cause everything to build correctly and together.  You can imagine what will happen to System.Windows.Controls.DataVisualizations when it tries to reference System.Windows.Controls and the assemblies are built at different times with different dependencies.  If you can't, imagine shear sacrilege.  And pain.  And suffering.
If you follow these guidelines, you should have a much more stable/clean build of SilverlightToolkit, which will make future developments and enhancements easier to bake in (such as targeting a WPF platform for Charting).  Unfortunately SilverlightToolkit also no longer accepts user contributions, due to licensing issues, and Microsoft is the sole development team.  This makes getting features added a little (read: very) difficult.

Good luck and happy building!

Monday, June 27, 2011

VisualTreeHelper - Your New Best Friend

Ever noticed that WPF and Silverlight don't like to play nicely with their implementations of the same controls?  Often, this is because they are derived differently.  They both ultimately derive from DependencyObject, however the

In any case, the VisualTreeHelper is your best friend when it comes to navigating the structure of your controls.  Essentially, it allows you to navigate down from a parent element, locating children.  You can be a little recursive and then use the VisualTreeHelper on the child controls and dig deeper and deeper.

I've written a little helper that I've injected into the base class of all controls I'm writing for Silverlight and WPF.

/// <summary>
/// Navigates the control tree to find a child of a specific type.
/// </summary>
/// <param name="element">The parent element to search under.</param>
/// <param name="type">The type to search for.</param>
/// <returns>The first child of the specified type on success or null on failure.</returns>
protected object GetChildOfType(FrameworkElement element, Type type)
{
    int count = VisualTreeHelper.GetChildrenCount(element);
 
    for (int i = 0; i < count; i++)
    {
        FrameworkElement child = (FrameworkElement)VisualTreeHelper.GetChild(element, i);
 
        if (child != null)
        {
            if (child.GetType() == type)
                return child;
 
            object deeperChild = GetChildOfType(child, type);
 
            if (deeperChild != null)
                return deeperChild;
        }
    }
 
    return null;
}


Enjoy!