Displaying and editing Child Object properties in a Property Grid

If you have a complex member property (a class that isn’t a .NET system type) and you want to display and edit through PropertyGrid, follow these steps:

  1. Derive from base class System.ComponentModel.ExpandableObjectConverter
  2. Add TypeConverter(typeof(yourClass)) attribute on this class
  3. Optionally Add Description(“your description”) attribute as well.  Common descriptions include “Expand to see options” as your property value will not be editable without expanding drop down
  4. Override ToString for better display of your object ‘state’ in the property grid
  5. IMPORTANT: provide a default constructor – otherwise it excepts quietly and you are not sure why

Optionally…Override  the 4  base class methods for conversion / serialization to string

public override object ConvertTo(ITypeDescriptorContext context,
CultureInfo culture,
object value,
System.Type destinationType)
{
if (destinationType == typeof(System.String) && value is StatusCommand)
{

//Convert / Serialize your object to string (usually in a parsable property bag)

}
return base.ConvertTo(context, culture, value, destinationType);
}


public override object ConvertFrom(ITypeDescriptorContext context,
CultureInfo culture, object value)
{

StatusCommand statusCommand = new StatusCommand();

if (value is string)
{
try
{

//Parse the string
string s = (string)value;
string[] elements = s.Split(';');

foreach (var elem in elements)
{
string[] fields = elem.Split('=');
switch (fields[0])
{
case "Version":
break;
break;
case "FirmwareVersionMajor":
statusCommand.FirmwareVersionMajor = Convert.ToByte(fields[1]);
break;
case "FirmwareVersionMinor":
statusCommand.FirmwareVersionMinor = Convert.ToByte(fields[1]);
break;


}
}

return statusCommand;
}
catch (Exception ex)
{

Trace.TraceError(ex.ToString());
throw new ArgumentException(
"Can not convert '" + (string)value +
"' to type SpellingOptions");
}
}
return base.ConvertFrom(context, culture, value);
}

public override bool CanConvertFrom(ITypeDescriptorContext context,
System.Type sourceType)
{
if (sourceType == typeof(string))
return true;

return base.CanConvertFrom(context, sourceType);
}

public override bool CanConvertTo(ITypeDescriptorContext context,
System.Type destinationType)
{
if (destinationType == typeof(StatusCommand))
return true;

return base.CanConvertTo(context, destinationType);
}

Creating sites with modular Typescript, JQuery, requireJS and D3js (v4)

Standard Approach for a page is to setup div with an ID that will become the SVG Canvas

  • The SVG Canvas object (implements ISvgCanvas)
    • maitains identity with the page via div:id, fetching attribute data for canvas dimensions
    • Creates a Defines child object with stores filters, markers that can be used by any of the child objects
    • Creates a d3v4 selection object that other controls will use for appended graphics
    • The SVG Canvas object is passed to all child controls so they can
      • Figure out the extents of the window
      • Access the Defs (or create additional ones at the correct level)
      • Append to the main SVG node

Note – the modular (AMD/EC5) approach uses the following imports from a d3 modular typings:

import * as d3_selection from “d3-selection”;
import * as $ from “jquery”;

export type d3v4Selection = d3_selection.Selection<d3_selection.BaseType, any, any, any>;

ISvgCanvas

export interface ISvgCanvas{
 id:String;
 defines:ICanvasDefines; 
 svgCanvas:d3v4Selection;
 width:number;
 height:number;
}

ICanvasDefines – for addding gradients, filters, markers to the <defs> child of the canvas

export interface ICanvasDefines{
 AddLinearGradient(gradientId: string): d3v4Selection;
 AddGaussianBlurFilter(filterID: string): d3v4Selection;
 //stop1:string='70%',stop1color:string='lightgrey', stop2:string= '100%', stop2color:string= 'gray'
 AddRadialGradiantWithTwoStops(gradientID:string, stop1?:string,stop1color?:string, stop2?:string, stop2color?:string): d3v4Selection;
 AddArrow(markerID:string,markerWidth?:number,markerHeight?:number,refX?:number,refY?:number): d3v4Selection
}

Canvas Object (SvgD3Canvas implements ISvgCanvas)

export class SvgD3Canvas implements ISvgCanvas{

 private _container:JQuery;
 private _d3SVG:d3v4Selection;
 private _width:number;
 private _height:number;
 private _defines:ICanvasDefines;


 constructor(divID:string){

 this._container = $(divID);
 let itemHeight = this._container.attr("item-height");
 if(!itemHeight){
   itemHeight = this._container.css("height").replace(/[^-\d\.]/g, '');;
 }
 if(!itemHeight){
   itemHeight = "2000";
 }

 let itemwidth = this._container.attr("item-width");
 if(!itemwidth){
   itemwidth = this._container.css("width").replace(/[^-\d\.]/g, '');
 }
 if(!itemwidth){
   itemwidth = "2000";
 }


 this._height = Math.round(Number(itemHeight));
 this._width =Math.round(Number(itemwidth));
 this._d3SVG = d3_selection.select(divID).append("svg").attr("width",this._width).attr("height", this._height);
 this._defines= new SVGdefsHelper(this._d3SVG);
 
 }

 public get width():number{
 return this._width;
 }
 public get height():number{
 return this._height;
 }
 public get svgCanvas():d3v4Selection{
 return this._d3SVG;
 }

 public get defines():ICanvasDefines{
 return this._defines;
 }
}

Defines Object


export class SVGdefsHelper implements ICanvasDefines {

 _svgDefsSection: d3v4Selection;

 constructor(svgDefs: d3v4Selection) {
 this._svgDefsSection = svgDefs;
 }


 public AddRadialGradiantWithTwoStops(gradientID:string, stop1:string='70%',stop1color:string='lightgrey', stop2:string= '100%', stop2color:string= 'gray'): d3v4Selection{
 let gradient = this._svgDefsSection.append('radialGradient')
 .attr("id", gradientID);

 gradient.append("stop").attr("offset", stop1).attr("stop-color", stop1color);
 gradient.append("stop").attr("offset", stop2).attr("stop-color", stop2color);

 return gradient;
 }

 public AddArrow(markerID:string,markerWidth:number=10,markerHeight:number=10,refX:number=6,refY:number=3): d3v4Selection{
 let marker = this._svgDefsSection.append('marker').attr("class","def-marker-arrow").attr("id", markerID)
 .attr("markerWidth", markerWidth)
 .attr("markerHeight",markerHeight)
 .attr("refX",refX)
 .attr("refY",refY)
 .attr("orient","auto")
 .attr("markerUnits", "strokeWidth");

 let path = marker.append("path").attr("d","M0,0 L0,6 L9,3 z").attr("class","def-marker-arrow");
 
 return marker;

 
// <marker id="arrow" markerWidth="10" markerHeight="10" refX="0" refY="3" orient="auto" markerUnits="strokeWidth">
// <path d="M0,0 L0,6 L9,3 z" fill="#f00" />
// </marker>
 }
 public AddRadialGradient(gradiantParams: IGradientStop2): d3v4Selection {
 // <radialGradient id="exampleGradient">
 // <stop offset="70%" stop-color="lightgrey"/>
 // <stop offset="100%" stop-color="gray"/>
 //</radialGradient>
 var grayCircularRadialGrad = { id: 'grayRadial', stop1: '70%', stop1color: 'lightgrey', stop2: '100%', stop2color: 'gray' };
 var gradient = this._svgDefsSection.append('radialGradient')
 .attr("id", gradiantParams.id);

 gradient.append("stop").attr("offset", gradiantParams.stop1).attr("stop-color", gradiantParams.stop1color);
 gradient.append("stop").attr("offset", gradiantParams.stop2).attr("stop-color", gradiantParams.stop2color);

 return gradient;

 }

 public AddLinearGradient(gradientId: string): d3v4Selection {

 //<linearGradient id="grad1" x1="0%" y1="0%" x2="100%" y2="0%">
 // <stop offset="0%" style="stop-color:rgb(255,255,0);stop-opacity:1" />
 // <stop offset="100%" style="stop-color:rgb(255,0,0);stop-opacity:1" />
 // </linearGradient>

 var mainGradient = this._svgDefsSection.append('linearGradient')
 .attr("id", gradientId)
 .attr("x1", "0%")
 .attr("y1", "0%")
 .attr("x2", "100%")
 .attr("y2", "0%")

 mainGradient.append('stop')
 .attr('class', 'stop-left')
 .attr('offset', '0%')
 .attr('style', 'stop-color:rgb(255,255,0);stop-opacity:1');

 mainGradient.append('stop')
 .attr('class', 'stop-left')
 .attr('offset', '100%')
 .attr('style', 'stop-color:rgb(255,0,0);stop-opacity:1');

 return mainGradient;


 }

 public AddGaussianBlurFilter(filterID: string): d3v4Selection {
 //<filter id="f3" x="0" y="0" width="200%" height="200%">
 // <feOffset result="offOut" in="SourceAlpha" dx="20" dy="20" />
 // <feGaussianBlur result="blurOut" in="offOut" stdDeviation="10" />
 // <feBlend in="SourceGraphic" in2="blurOut" mode="normal" />
 // </filter>
 var mainFilter = this._svgDefsSection.append('filter')
 .attr("id", filterID)
 .attr("x", "0")
 .attr("y", "0")
 .attr("width", "200%")
 .attr("height", "200%");

 mainFilter.append("feOffset")
 .attr("result", "offOut")
 .attr("in", "SourceAlpha")
 .attr("dx", "20")
 .attr("dy", "20");

 mainFilter.append("feGaussianBlur")
 .attr("result", "blurOut")
 .attr("in", "offOut")
 .attr("stdDeviation", "10");

 mainFilter.append("feBlend")
 .attr("in", "SourceGraphic")
 .attr("in2", "blurOut")
 .attr("mode", "normal");

 return mainFilter;


 }
 public AddFilterToDefs(filterID: string): d3v4Selection {
 //<filter id="f3" x="0" y="0" width="200%" height="200%">
 // <feOffset result="offOut" in="SourceAlpha" dx="20" dy="20" />
 // <feGaussianBlur result="blurOut" in="offOut" stdDeviation="10" />
 // <feBlend in="SourceGraphic" in2="blurOut" mode="normal" />
 // </filter>
 var mainFilter = this._svgDefsSection.append('filter')
 .attr("id", filterID)
 .attr("x", "0")
 .attr("y", "0")
 .attr("width", "200%")
 .attr("height", "200%");

 mainFilter.append("feOffset")
 .attr("result", "offOut")
 .attr("in", "SourceAlpha")
 .attr("dx", "20")
 .attr("dy", "20");

 mainFilter.append("feGaussianBlur")
 .attr("result", "blurOut")
 .attr("in", "offOut")
 .attr("stdDeviation", "10");

 mainFilter.append("feBlend")
 .attr("in", "SourceGraphic")
 .attr("in2", "blurOut")
 .attr("mode", "normal");

 return mainFilter;


 }
 public AddWhiteToColorGradient(gradientID: string, color: string): d3v4Selection {
 //<linearGradient id="gradientOrange" x1="0%" y1="0%" x2="0%" y2="100%" spreadMethod="pad">
 // <stop offset="000%" stop-color="#FF9600" stop-opacity="1"/>
 // <stop offset="050%" stop-color="#FFFFFF" stop-opacity="1"/>
 // <stop offset="100%" stop-color="#000000" stop-opacity="1"/>
 //</linearGradient>

 //<linearGradient id="gradientGreen" x1="0%" y1="0%" x2="0%" y2="100%" spreadMethod="pad">
 // <stop offset="000%" stop-color="#22DD00" stop-opacity="1"/>
 // <stop offset="050%" stop-color="#FFFFFF" stop-opacity="1"/>
 // <stop offset="100%" stop-color="#000000" stop-opacity="1"/>
 //</linearGradient>

 var gradient = this._svgDefsSection.append('linearGradient')
 .attr("id", gradientID)
 .attr("x1", "0%")
 .attr("y1", "0%")
 .attr("x2", "0%")
 .attr("y2", "100%")

 gradient.append('stop')
 .attr('offset', '0%')
 .attr('stop-color', color)
 .attr('stop-opacity', 1);


 gradient.append('stop')
 .attr('offset', '50%')
 .attr('stop-color', "#FFFFFF")
 .attr('stop-opacity', 1);

 gradient.append('stop')
 .attr('offset', '100%')
 .attr('stop-color', "#000000")
 .attr('stop-opacity', 1);

 return gradient;

 }
}

D3 Sliders – SVG

SVG Slider Libraries that are close to desired behavior

Web Page

<!DOCTYPE html>
<html lang="en">
<head>
 <meta charset="UTF-8">
 <title>Title</title>
 <script src="https://d3js.org/d3.v3.min.js" charset="utf-8"></script>
 <script src="simpleD3Slider.js"></script>
</head>

<body>
<div id="vis"></div>
</body>

<script>

 var svg = d3.select("#vis").append("svg").attr("width", 1000).attr("height", 700),
 slider1 = new simpleSlider(),
 slider2 = new simpleSlider(),
 circle = svg.append("circle").attr("cx", 50).attr("cy", 100).attr("r", 30);


 slider1.width(200).x(30).y(200).value(1.0).event(function(){
 circle.attr("r", 30 * slider1.value());
 });

 slider2.width(200).x(30).y(230).value(0.5).event(function(){
 circle.attr("cx", 50 + (170 * slider2.value()));
 });

 svg.call(slider1);
 svg.call(slider2);

</script>
</html>
/* Simple, reusable slider in pure d3 */

function simpleSlider () {

 var width = 100,
 value = 0.5, /* Domain assumes to be [0 - 1] */
 event,
 x = 0,
 y = 0;

 function slider (selection) {

 //Line to represent the current value
 var valueLine = selection.append("line")
 .attr("x1", x)
 .attr("x2", x + (width * value))
 .attr("y1", y)
 .attr("y2", y)
 .style({stroke: "#51CB3F",
 "stroke-linecap": "round",
 "stroke-width": 6 });

 //Line to show the remaining value
 var emptyLine = selection.append("line")
 .attr("x1", x + (width * value))
 .attr("x2", x + width)
 .attr("y1", y)
 .attr("y2", y)
 .style({
 "stroke": "#ECECEC",
 "stroke-linecap": "round",
 "stroke-width": 6
 });

 var drag = d3.behavior.drag().on("drag", function() {
 var newX = d3.mouse(this)[0];

 if (newX < x)
 newX = x;
 else if (newX > x + width)
 newX = x + width;

 value = (newX - x) / width;
 valueCircle.attr("cx", newX);
 valueLine.attr("x2", x + (width * value));
 emptyLine.attr("x1", x + (width * value));

 if (event)
 event();

 d3.event.sourceEvent.stopPropagation();
 })

 //Draggable circle to represent the current value
 var valueCircle = selection.append("circle")
 .attr("cx", x + (width * value))
 .attr("cy", y)
 .attr("r", 8)
 .style({
 "stroke": "black",
 "stroke-width": 1.0,
 "fill": "white"
 })
 .call(drag);
 }


 slider.x = function (val) {
 x = val;
 return slider;
 }

 slider.y = function (val) {
 y = val;
 return slider;
 }

 slider.value = function (val) {
 if (val) {
 value = val;
 return slider;
 } else {
 return value;
 }
 }

 slider.width = function (val) {
 width = val;
 return slider;
 }

 slider.event = function (val) {
 event = val;
 return slider;
 }

 return slider;
}

Code Snippets – Code Prettify

Another plugin, Code Prettify, leverages the Google Prettify library without having to manually link code and add classes (applies to <pre> and <code> blocks).

private static string LoremIpsum(int minWords, int maxWords, int minSentences, int maxSentences, int numLines)
    {
        var words = new[]{"lorem", "ipsum", "dolor", "sit", "amet", "consectetuer", "adipiscing", "elit", "sed", "diam", "nonummy", "nibh", "euismod", "tincidunt", "ut", "laoreet", "dolore", "magna", "aliquam", "erat"};

        var rand = new Random();
        int numSentences = rand.Next(maxSentences - minSentences)
            + minSentences + 1;
        int numWords = rand.Next(maxWords - minWords) + minWords + 1;

        var sb = new StringBuilder();
        for (int p = 0; p < numLines; p++)
        {
            for (int s = 0; s < numSentences; s++)
            {
                for (int w = 0; w < numWords; w++) { if (w > 0) { sb.Append(" "); }
                    sb.Append(words[rand.Next(words.Length)]);
                }
                sb.Append(". ");
            }
            sb.AppendLine();
        }
        return sb.ToString();
    }

Code Snippets – Google Prettify

Another option for syntax highlighting appears to be Google Prettify.js (assuming we can link external scripts).

Link the script <script src=”https://cdn.rawgit.com/google/code-prettify/master/loader/run_prettify.js”></script>.

Operates on blocks with “prettyprint” class.

Note: incompatble with Mivhak. To bypass Mivhak syntax plugin, you can wrap in <pre> block (without class) and add the class to a <code> block.

Git Page

private static string LoremIpsum(int minWords, int maxWords, int minSentences, int maxSentences, int numLines)
    {
        var words = new[]{"lorem", "ipsum", "dolor", "sit", "amet", "consectetuer", "adipiscing", "elit", "sed", "diam", "nonummy", "nibh", "euismod", "tincidunt", "ut", "laoreet", "dolore", "magna", "aliquam", "erat"};

        var rand = new Random();
        int numSentences = rand.Next(maxSentences - minSentences)
            + minSentences + 1;
        int numWords = rand.Next(maxWords - minWords) + minWords + 1;

        var sb = new StringBuilder();
        for (int p = 0; p < numLines; p++)
        {
            for (int s = 0; s < numSentences; s++)
            {
                for (int w = 0; w < numWords; w++) { if (w > 0) { sb.Append(" "); }
                    sb.Append(words[rand.Next(words.Length)]);
                }
                sb.Append(". ");
            }
            sb.AppendLine();
        }
        return sb.ToString();
    }

Code Snippets w/ Mivhak Syntax Highlighter

Using version 1.3.6 with wordpress.

Insert code with newly added “code” icon. Options can be set from the visual editor.

New plugin has options for appearance, defaults etc. on admin toolbar. Icon looks like <>.

Reference Page

static string LoremIpsum(int minWords, int maxWords,
    int minSentences, int maxSentences,
    int numParagraphs) {

    var words = new[]{"lorem", "ipsum", "dolor", "sit", "amet", "consectetuer",
        "adipiscing", "elit", "sed", "diam", "nonummy", "nibh", "euismod",
        "tincidunt", "ut", "laoreet", "dolore", "magna", "aliquam", "erat"};

    var rand = new Random();
    int numSentences = rand.Next(maxSentences - minSentences)
        + minSentences + 1;
    int numWords = rand.Next(maxWords - minWords) + minWords + 1;

    StringBuilder result = new StringBuilder();

    for(int p = 0; p < numParagraphs; p++) {
        result.Append("<p>");
        for(int s = 0; s < numSentences; s++) {
            for(int w = 0; w < numWords; w++) {
                if (w > 0) { result.Append(" "); }
                result.Append(words[rand.Next(words.Length)]);
            }
            result.Append(". ");
        }
        result.Append("</p>");
    }

    return result.ToString();
}

 

Code Snippets w/ WP-Syntax

Hello! This is a test on adding code snippets with syntax highlighting to a WP site.

Syntax highlighting can be done with the WP-Syntax plugin (currently version 1.0).

That being said, I had to make an edit to the wp-syntax.css file to get line numbering to work correctly.

.wp_syntax td.code{
	background-color: #EEE;
	background-image: -webkit-linear-gradient( transparent 50%, rgba(255, 255, 255, .9) 50% );
	background-image: -moz-linear-gradient( transparent 50%, rgba(255, 255, 255, .9) 50% );
	background-image: -ms-linear-gradient( transparent 50%, rgba(255, 255, 255, .9) 50% );
	background-image: -o-linear-gradient( transparent 50%, rgba(255, 255, 255, .9) 50% );
	background-image: linear-gradient( transparent 50%, rgba(255, 255, 255, .9) 50% );
	background-size : 1px 32px;
	line-height     : normal !important;
	white-space     : normal !important;
	width           : 100% !important;
	padding-left: 10px !important;
}

Without this edit, there is overlap between the line numbers and the code.