Monday, September 22, 2014

Helix 3D Toolkit - Well Viewer Part 1

The last few years I've been working in the oil industry, programming small custom engineering applications.  One common requirement is to have a 3D plot of the well trajectory.  My first crack at this several years ago was rather crude, basically using a 3D to 2D orthographic transformation.  In fact the first rendition of it was done in an Excel VSTO application and plotted using an Excel chart. After migrating the application to WPF I plotted it using the SciChart chart package.  Though not beautiful, this worked and did enough to get us by while we worked on more technical aspects of our program.


3D well profile plotted with SciChart
I was aware of WPF's native 3D capability, but I never could find the time to dig into it to make a new 3D well survey plot to draw this graph.  I stumbled on Helix 3D Toolkit on NuGet, several months ago and just recently I found the time to dive in and replace our 3D plot with a more attractive and functional tool.

Helix wraps the core WPF 3D functionality, to provide an extra level of sweetness and ease of use.  It recently moved to GitHub and appears to be a project with growing activity.  Documentation is nearly non-existent, however the source code has a great suite of sample applications.  Code samples are worth thousands of words :)

I decided to have a preview well plot and then allow the user to open up a new window which would contain a larger version of the plot and expose more controls to manipulate the 3D view-port.

3D well profile preview plotted with Helix 3D Toolkit

Window giving a larger view-port and more user controls

One of the nice things about the toolkit is that the controls provide a huge amount of functionality.  For example I was able to databind to a collection of 3D points representing my tube path.  The Helix3DViewport class provided panning, zooming, rotation, copy image clipboard etc.  Honestly, after reading through several of the code samples creating this plot was very simple.


It's not all sunshine and roses, I did run into one issue.  For my preview plot I keep one instance of the view instantiated and when a user clicks on a new well, a new WellSurveyPlotViewModel is created and the data context of the preview view is updated.  When the user clicked the Open Well Viewer button a window service creates a new window passing off the WellSurveyPlotViewModel as its data context.  I could not get the view to zoom extents with the new camera information.  After reading the source code I arrived at the idea of using an attached property to reset the camera and call for a re-zoom.  The following two lines, in an attached property hooked into a ReZoom boolean property in the preview view model solved the issue.

  viewport.Camera = viewport.DefaultCamera;
  viewport.ZoomExtents();

Overall this toolkit is great, using the MVVM pattern I was able to recreate our 3D plot using Helix in a weekend of several short coding sessions.

Saturday, September 20, 2014

PRISM & WPF Resource Dictionaries

The web is a great spot to get information, getting something useful out of the information can be another matter. At work, I've been spending a large amount of time working on a PRISM based modular WPF application. One of the things on my to-do list has been to figure out how to "correctly" structure resource dictionaries in a modular application.

The longer I work with WPF, the more I value the concept of blend-ability. One of the issues I found with several of the approaches to managing resource dictionaries is that they are compiled at run time, and at design time they aren't available. It's quite annoying to never know what anything is going to look like until the application runs.

After digging around on the net, I realized there was some contradicting advice. For example, one camp believes in cramming every thing into one dictionary, in the name of performance. The other camp believes in using a new resource dictionary for every style. I decided to go with organization over performance, knowing that if performance was an issue things can be restructured.

By piecing together blog posts, MSDN articles, and stackoverflow questions I arrived at a system that is working well.

Resources structure:
  • I found this blog post which outlines a folder structure for resource files, and goes by the style per resource dictionary rule.  After adding a new resource dictionary file into the folder structure, a reference to that file is added to the a merged dictionary referred to as the ResourceLibrary.  The ResourceLibrary is then referenced by all the project modules.  
  • In each PRISM module, a local resource dictionary could be merge into that modules App.xaml file for further specific module styling.
Design Time Blendability: 
  • This SO post contains the key to a very simple solution to allow resources to be visible in Blend and VS at design time. Leave the App.xaml in each PRISM module. If you've already deleted it, add one back into the project. In the App.xaml, use a merged dictionary and a Pack Uri to reference the resource dictionary in your shared infrastructure project.
 <Application x:Class="KNE.Athena.ProjectModule.App"  
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"  
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">  
   <Application.Resources>  
     <ResourceDictionary>  
       <ResourceDictionary.MergedDictionaries>  
         <ResourceDictionary Source= "pack://application:,,,/KNE.Athena.Infrastructure;component/ResourceDictionaries/ResourceLibrary.xaml"/>  
       </ResourceDictionary.MergedDictionaries>  
       <Style TargetType="{x:Type Rectangle}"/>  
     </ResourceDictionary>  
   </Application.Resources>  
 </Application>  

Note the interesting line inside the merged dictionary  <Style TargetType="{x:Type Rectangle}"/> 
I can't actually say for certain that it is necessary anymore, as I seem to have gotten this to work with out it, however it is there to fix a Microsoft bug...

Other Notes - BasedOn Styles need merged dictionary, and performance concerns:

After reorganizing my styles into the structure described in section one,  I was surprised to find that styles that made use of the BasedOn property where not correctly inheriting the styles.  The answer for this was occurring was of course on stackoverflow. When the base style and derived style are not defined in the same .xaml file, one must first merge in the style from the other resource dictionary.   Below you can see my AddButton is based on Button, and at the top of the file I merge in the button style.

 <ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"  
           xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">  
   <ResourceDictionary.MergedDictionaries>  
     <ResourceDictionary Source="../BaseControlStyles/ButtonStyle.xaml"/>  
   </ResourceDictionary.MergedDictionaries>  
   <Style x:Key="AddButtonStyle" BasedOn="{StaticResource {x:Type Button}}" TargetType="{x:Type Button}">  
     <Setter Property="Content" Value="+" />  
     <Setter Property="Width" Value="25"/>  
     <Setter Property="Height" Value="25"/>  
     <Setter Property="ToolTip" Value="Add Item"/>  
   </Style>  
 </ResourceDictionary>  

Last, be aware that performance issues could arise.  Apperently in WPF, each time a control references a resource dictionary, a new instance of the resource dictionary is created. Repeatedly parsing many lines of xaml can have a negative performance impact.  This is another thing that I'm not sure if Microsoft has addressed, this blog post is several years old.  The fix outlined in this blog post is simple, but I have not yet found a need to implement it in my application.

Friday, September 19, 2014

Web API 2 Attribute Routing - Error 500

I ran into a 500 Error last week while working on a project that uses Web API 2 for a REST like web service.  Looking up upon looking up error 500, I found that it was returned when there is more than one possible route for a request.  I went and looked at my convention based route definition which looked fine.  Then I paid a visit to the controller, where I found that I had two route attributes on my put and post methods that where defined as empty strings.  Whoops!

 [Route("")]  

Lesson learned :) In Web API 2, if you mix route attributes with convention based routing, the route attribute takes precedent over the convention based route.  If a route attribute is not present, the default convention based route will be used. The route can't be duplicated!


Sunday, September 14, 2014

WPF DataGrid or ListView does not follow underlying ICollectionView selection

If you've ever used a selector derived control and ICollectionView with the IsSynchronizedWithCurrentItem property set to true, you may have noticed that the UI can get out of sync with the actual selected item.  This seems to be a bug in the underlying implementation of the selector class.

I ran into this bug recently and on Tim Valentine's blog coderelief.net was glad to find this solution.  It involves using an attached property to keep the UI and ICollectionView synced.