{"id":576,"date":"2013-07-18T13:39:22","date_gmt":"2013-07-18T13:39:22","guid":{"rendered":"http:\/\/putridparrot.com\/blog\/?p=576"},"modified":"2013-07-19T07:56:29","modified_gmt":"2013-07-19T07:56:29","slug":"typeconverters-and-xaml","status":"publish","type":"post","link":"https:\/\/putridparrot.com\/blog\/typeconverters-and-xaml\/","title":{"rendered":"TypeConverters and XAML"},"content":{"rendered":"<p>When we&#8217;re setting margins, backgrounds etc. in XAML we use string representations which get converted to the actual objects. For example <\/p>\n<pre class=\"brush: xml; title: ; notranslate\" title=\"\">\r\n&lt;Button Margin=&quot;0,3,0,3&quot; \/&gt;\r\n<\/pre>\n<p>in this example the string <em>0,3,0,3<\/em> is converted into a <em>Margin<\/em> object by the MarginConverter. <\/p>\n<p>Strings are converted to types using TypeConverters. A simple example of one is listed below<\/p>\n<pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\r\npublic class AbbreviatedNumberConverter : TypeConverter\r\n{\r\n   public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)\r\n   {\r\n      return sourceType == typeof(string) || base.CanConvertFrom(context, sourceType);\r\n   }\r\n\r\n   public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)\r\n   {\r\n      return destinationType == typeof(InstanceDescriptor) || \r\n                 base.CanConvertTo(context, destinationType);\r\n   }\r\n\r\n   public override object ConvertFrom(ITypeDescriptorContext context, \r\n                            CultureInfo culture, object value)\r\n   {\r\n      string text = value as string;\r\n      if (text == null)\r\n      {\r\n         return base.ConvertFrom(context, culture, value);\r\n      }\r\n\r\n      if (String.IsNullOrWhiteSpace(text))\r\n      {\r\n         return 0.0;\r\n      }\r\n\r\n      if (culture == null)\r\n      {\r\n         culture = CultureInfo.CurrentCulture;\r\n      }\r\n\r\n      double number;\r\n      if (AbbreviatedNumeric.ValidateDouble(text, out number, culture))\r\n         return number;\r\n\r\n      return 0.0;\r\n   }\r\n\r\n   public override object ConvertTo(ITypeDescriptorContext context, \r\n                     CultureInfo culture, object value, Type destinationType)\r\n   {\r\n      if (destinationType != null &amp;&amp; value is Double)\r\n      {\r\n         if (destinationType == typeof(string))\r\n         {\r\n            return value.ToString();\r\n \t }\r\n      }\r\n      return base.ConvertTo(context, culture, value, destinationType);\r\n   }\r\n}\r\n<\/pre>\n<p>So the above demonstrated a very simple TypeConverter that converts strings like &#8220;134m&#8221; into 134000000 or the likes of &#8220;10k&#8221; to 10000. The actual code for the conversion occurs in the AbbreviatedNumeric.ValidateDouble method which I&#8217;ll list at the end of this post but will exclude the tests just to save space. This is not an all encompassing converter, it will only convert k for thousands, m for millions and b for billions and also doesn&#8217;t handle multiple languages, but it&#8217;s here as an example.<\/p>\n<p>Now let&#8217;s assume we&#8217;ve created some edit control which has an Amount dependency property which we want to allow the user to enter abbreviated numeric strings into. So the dependency property might look like<\/p>\n<pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\r\npublic Double Amount\r\n{\r\n   get { return (Double)GetValue(AmountProperty); }\r\n   set { SetValue(AmountProperty, value); }\r\n}\r\n\r\npublic static readonly DependencyProperty AmountProperty =\r\n                    DependencyProperty.Register(&quot;Amount&quot;, typeof(Double), \r\n                    typeof(OnlineStatusControl), new PropertyMetadata(0.0));\r\n<\/pre>\n<p>To apply our type converter we simple add the TypeConverterAttribute to the Amount property as below<\/p>\n<pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\r\n&#x5B;TypeConverter(typeof(AbbreviatedNumberConverter))]\r\npublic Double Amount\r\n{\r\n   get { return (Double)GetValue(AmountProperty); }\r\n   set { SetValue(AmountProperty, value); }\r\n}\r\n<\/pre>\n<p>and finally when using this new control we can do the following<\/p>\n<pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\r\n&lt;Controls:AbbreviatedNumericEditor Amount=&quot;123m&quot; \/&gt;\r\n<\/pre>\n<p>The type converter is called on this and 123m is converted to 123000000 which is now stored as a Double in the dependency property Amount.<\/p>\n<p>For completeness, here&#8217;s the simple AbbreviatedNumeric class<\/p>\n<pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\r\npublic static class AbbreviatedNumeric\r\n{\r\n   public static bool ValidateDouble(string value, out double? numeric, \r\n              CultureInfo cultureInfo = null)\r\n   {\r\n      double result;\r\n      if(ValidateDouble(value, out result, cultureInfo))\r\n      {\r\n         numeric = result;\r\n         return true;\r\n      }\r\n      numeric = null;\r\n      return false;\r\n   }\r\n\r\n   public static bool ValidateDouble(string value, out double numeric, \r\n              CultureInfo cultureInfo = null)\r\n   {\t\r\n      if (String.IsNullOrEmpty(value))\r\n      {\r\n         numeric = 0;\r\n         return false;\r\n      }\r\n\r\n      if (Double.TryParse(value, out numeric))\r\n      {\r\n         return true;\r\n      }\r\n      if (value.Length &gt; 0)\r\n      {\r\n         if (cultureInfo == null)\r\n         {\r\n\t    cultureInfo = CultureInfo.CurrentCulture;\r\n\t }\r\n\r\n\t NumberFormatInfo numberFormat = cultureInfo.NumberFormat;\r\n \t if (value.Substring(0, 1) == numberFormat.NumberDecimalSeparator)\r\n\t {\r\n\t    value = &quot;0&quot; + value;\r\n\t }\r\n\t if (Double.TryParse(value.Substring(0, value.Length - 1), \r\n                     NumberStyles.AllowLeadingWhite | \r\n                     NumberStyles.AllowTrailingWhite |                      \r\n                     NumberStyles.AllowLeadingSign |\r\n \t\t     NumberStyles.AllowDecimalPoint | \r\n                     NumberStyles.AllowThousands | \r\n\t\t     NumberStyles.AllowExponent, cultureInfo, out numeric))\r\n\t {\r\n\t    switch (Char.ToUpper(value&#x5B;value.Length - 1]))\r\n\t    {\r\n\t        case 'B':\r\n\t\t   numeric = numeric * 1000000000;\r\n\t\t   break;\r\n\t\tcase 'M':\r\n\t\t   numeric = numeric * 1000000;\r\n\t\t   break;\r\n\t\tcase 'K':\r\n\t\t   numeric = numeric * 1000;\r\n\t\t   break;\r\n\t\tdefault:\r\n\t\t   return false;\r\n\t    }\r\n            return true;\r\n\t }\r\n      }\r\n      return false;\r\n   }\r\n}\r\n<\/pre>\n","protected":false},"excerpt":{"rendered":"<p>When we&#8217;re setting margins, backgrounds etc. in XAML we use string representations which get converted to the actual objects. For example &lt;Button Margin=&quot;0,3,0,3&quot; \/&gt; in this example the string 0,3,0,3 is converted into a Margin object by the MarginConverter. Strings are converted to types using TypeConverters. A simple example of one is listed below public [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_jetpack_memberships_contains_paid_content":false,"footnotes":""},"categories":[13,20],"tags":[],"class_list":["post-576","post","type-post","status-publish","format-standard","hentry","category-wpf","category-xaml"],"jetpack_sharing_enabled":true,"jetpack_featured_media_url":"","_links":{"self":[{"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/posts\/576","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/comments?post=576"}],"version-history":[{"count":4,"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/posts\/576\/revisions"}],"predecessor-version":[{"id":586,"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/posts\/576\/revisions\/586"}],"wp:attachment":[{"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/media?parent=576"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/categories?post=576"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/tags?post=576"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}