Control with custom TypeConverter does not work after project rebuildICustomTypeDescriptor, TypeDescriptionProvider, TypeConverter, and UITypeEditorUsing CsvHelper can I translate white space to a nullable?ListView showing date field as blankCould not load file or assembly 'System.Web.Http 4.0.0 after update from 2012 to 2013How to directly bind to a Dictionary in Windows Phone 8.1WPF combobox in DataGridDataGridView Default Error Dialog ,Parameter is not validErrors while passing event log into dataGridViewRestrict custom TypeConverter to a specific assemblyFormatException and ArgumentException errors
Could the museum Saturn V's be refitted for one more flight?
Why didn't Boeing produce its own regional jet?
What are the G forces leaving Earth orbit?
Is there an expression that means doing something right before you will need it rather than doing it in case you might need it?
How obscure is the use of 令 in 令和?
files created then deleted at every second in tmp directory
How do conventional missiles fly?
How to install cross-compiler on Ubuntu 18.04?
Am I breaking OOP practice with this architecture?
Knowledge-based authentication using Domain-driven Design in C#
Avoiding the "not like other girls" trope?
Do creatures with a listed speed of "0 ft., fly 30 ft. (hover)" ever touch the ground?
Is this answer explanation correct?
What is the most common color to indicate the input-field is disabled?
How exploitable/balanced is this homebrew spell: Spell Permanency?
How to stretch the corners of this image so that it looks like a perfect rectangle?
Can a virus destroy the BIOS of a modern computer?
Venezuelan girlfriend wants to travel the USA to be with me. What is the process?
Why was Sir Cadogan fired?
how do we prove that a sum of two periods is still a period?
Processor speed limited at 0.4 Ghz
Unlock My Phone! February 2018
What reasons are there for a Capitalist to oppose a 100% inheritance tax?
How to compactly explain secondary and tertiary characters without resorting to stereotypes?
Control with custom TypeConverter does not work after project rebuild
ICustomTypeDescriptor, TypeDescriptionProvider, TypeConverter, and UITypeEditorUsing CsvHelper can I translate white space to a nullable?ListView showing date field as blankCould not load file or assembly 'System.Web.Http 4.0.0 after update from 2012 to 2013How to directly bind to a Dictionary in Windows Phone 8.1WPF combobox in DataGridDataGridView Default Error Dialog ,Parameter is not validErrors while passing event log into dataGridViewRestrict custom TypeConverter to a specific assemblyFormatException and ArgumentException errors
Overview
I have a C# project ControlsLib
which contains the following (code to follow later):
- A custom C# control
Control_Audible
that plays a .wav file that is selected at design-time from the properties pane - A
SoundItem
class as the class to support which file will be played - A
SoundItemConverter
class as aTypeConverter
for elegantly selecting which audio file to play in the properties window.
What IS working
My code works as expected when my solution is FIRST opened and my ControlsLib
project is NOT built.
When I add Control_Audible
to a form, I can select an audio file from the available audio resources:
And the designer file generates code as I would expect when the non-default SoundItem is selected:
What is NOT working
My code seems to NOT work as expected after building/rebuilding my ControlsLib
project and add my Control_Audible
control to a form...
The available audio resource files are populated in the dropdown as expected, but the SoundItem specified as the DefaultValue
("None") is Bold when it really should not be:
Also, whenever I try to save the form, I receive the following error:
I was at one time able to generate some auto-code for my Control_Audible
, but even then it did not generate the code I expected, and now it seems to not generate any code at all and my ConvertTo
function is messed up.
Question
It seems to work fine if I don't build my ControlsLib
project, but I can't expect to have to restart Visual Studio every time I want this thing to work. I should be able to rebuild my project as much as desired and still have my control work properly. I will mention I am using Visual Studio 2015.
Does anyone have any ideas why this is behaving this way? I've spent quite a bit of time on this and cannot figure out why this is happening!
The Code
Control_Audible.cs
using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.ComponentModel.Design.Serialization;
using System.Drawing;
using System.Globalization;
using System.Media;
using System.Reflection;
using System.Resources;
using System.Windows.Forms;
namespace ControlsLib
public class Control_Audible : UserControl
public Control_Audible() : base()
FileToPlay = SoundItem.None;
InitializeComponent();
private void InitializeComponent()
this.SuspendLayout();
//
// Control_Audible
//
this.AutoScaleDimensions = new SizeF(6F, 13F);
this.Name = "Control_Audible";
this.ResumeLayout(false);
[Category("Sounds")]
[DisplayName("SoundToPlay")]
[Description("File to play")]
[DefaultValue(typeof(SoundItem), "None")]
//[DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
public SoundItem FileToPlay
get;
set;
[TypeConverter(typeof(SoundItemConverter))]
[Serializable]
public struct SoundItem
public static readonly SoundItem None = new SoundItem("None");
//[Browsable(false)]
//[DefaultValue("None")]
//[DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
internal string Name
get;
set;
// Todo: Create a valid flag
public SoundItem(string Name) : this()
this.Name = Name;
public SoundPlayer GetSoundPlayer()
SoundPlayer retVal = null;
if (!string.IsNullOrEmpty(Name))
retVal = new SoundPlayer(AudibleSounds.ResourceManager.GetStream(Name));
return retVal;
public override string ToString()
return Name;
public static bool operator ==(SoundItem left, SoundItem right)
return left.Name == right.Name;
public static bool operator !=(SoundItem left, SoundItem right)
return !(left == right);
public override bool Equals(object obj)
// override Equals and write code to actually
// test for equality so that the SoundItem created
// from the call to ConvertFrom will be equal to
// the field you created
if (!(obj is SoundItem))
return false;
SoundItem comp = (SoundItem)obj;
// Note value types can't have derived classes, so we don't need
// to check the types of the objects here. -- Microsoft, 2/21/2001
return comp.Name == Name;
public override int GetHashCode()
return Name.GetHashCode();
public class SoundItemConverter : TypeConverter
private Dictionary<string, object> _resourceValues = new Dictionary<string, object>()
"None", SoundItem.None ,
;
public SoundItemConverter()
// Initializes the standard values list with defaults.
ResourceSet _resourceSet = AudibleSounds.ResourceManager.GetResourceSet(CultureInfo.CurrentCulture, true, true);
if (_resourceSet == null)
throw new Exception("Missing Resource Audio files");
// Make a dictionary now for easier use
foreach (DictionaryEntry entry in _resourceSet)
string resourceKey = entry.Key.ToString();
//object resource = entry.Value;
_resourceValues.Add(resourceKey,
new SoundItem(resourceKey));
// Indicates this converter provides a list of standard values.
public override bool GetStandardValuesSupported(ITypeDescriptorContext context)
return true;
// Returns a StandardValuesCollection of standard value objects.
public override StandardValuesCollection GetStandardValues(ITypeDescriptorContext context)
return new StandardValuesCollection( _resourceValues.Values);
// Returns true for a sourceType of string to indicate that
// conversions from string are supported. (The
// GetStandardValues method requires a string to native type
// conversion because the items in the drop-down list are
// translated to string.)
public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
if (sourceType == typeof(string))
return true;
return base.CanConvertFrom(context, sourceType);
// If the type of the value to convert is string, parses the string
// to set the value of the property to.
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
// This is the method that is called when you specify a default value for your type.
// Convert a string representation to SoundItem.
string strValue = value as string;
if (strValue != null)
string text = strValue.Trim();
if (text.Length == 0)
return SoundItem.None;
else
return new SoundItem(text);
return base.ConvertFrom(context, culture, value);
public override bool CanConvertTo(ITypeDescriptorContext context, Type destType)
if (destType == typeof(InstanceDescriptor))
return true;
return base.CanConvertTo(context, destType);
public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destType)
if (destType == null)
throw new ArgumentNullException("destinationType");
if (value is SoundItem)
SoundItem si = (SoundItem)value;
if (destType == typeof(string))
TypeConverter stringConverter = TypeDescriptor.GetConverter(typeof(string));
// Note: ConvertToString will raise exception if value cannot be converted.
return stringConverter.ConvertToString(context, culture, si.Name);
else if (destType == typeof(InstanceDescriptor))
ConstructorInfo ctor = typeof(SoundItem).GetConstructor(new Type[] typeof(string) );
if (ctor != null)
return new InstanceDescriptor(ctor, new object[] si.Name );
return base.ConvertTo(context, culture, value, destType);
//
// Summary:
// Creates an instance of this type given a set of property values for the object.
//
// Parameters:
// context:
// A type descriptor through which additional context can be provided.
//
// propertyValues:
// A dictionary of new property values. The dictionary contains a series of name-value
// pairs, one for each property returned from SoundItemConverter.GetProperties(System.ComponentModel.ITypeDescriptorContext,System.Object,System.Attribute[]).
//
// Returns:
// The newly created object, or null if the object could not be created. The default
// implementation returns null.
public override object CreateInstance(ITypeDescriptorContext context, IDictionary propertyValues)
!(name is string))
throw new ArgumentException();
return new SoundItem((string)name);
//
// Summary:
// Determines if changing a value on this object should require a call to SoundItemConverter.CreateInstance(System.ComponentModel.ITypeDescriptorContext,System.Collections.IDictionary)
// to create a new value.
//
// Parameters:
// context:
// A System.ComponentModel.TypeDescriptor through which additional context can be
// provided.
//
// Returns:
// true if the SoundItemConverter.CreateInstance(System.ComponentModel.ITypeDescriptorContext,System.Collections.IDictionary)
// method should be called when a change is made to one or more properties of this
// object; otherwise, false.
public override bool GetCreateInstanceSupported(ITypeDescriptorContext context)
return true;
//
// Summary:
// Retrieves the set of properties for this type. By default, a type does not return
// any properties.
//
// Parameters:
// context:
// A type descriptor through which additional context can be provided.
//
// value:
// The value of the object to get the properties for.
//
// attributes:
// An array of System.Attribute objects that describe the properties.
//
// Returns:
// The set of properties that are exposed for this data type. If no properties are
// exposed, this method might return null. The default implementation always returns
// null.
public override PropertyDescriptorCollection GetProperties(ITypeDescriptorContext context, object value, Attribute[] attributes)
PropertyDescriptorCollection props = TypeDescriptor.GetProperties(typeof(SoundItem), attributes);
return props.Sort(new string[] "Name" );
//
// Summary:
// Determines if this object supports properties. By default, this is false.
//
// Parameters:
// context:
// A System.ComponentModel.TypeDescriptor through which additional context can be
// provided.
//
// Returns:
// true if SoundItemCoverter.GetProperties(System.ComponentModel.ITypeDescriptorContext,System.Object,System.Attribute[])
// should be called to find the properties of this object; otherwise, false.
public override bool GetPropertiesSupported(ITypeDescriptorContext context)
return true;
AudibleSounds.Designer.cs
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:4.0.30319.42000
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace ControlsLib
using System;
/// <summary>
/// A strongly-typed resource class, for looking up localized strings, etc.
/// </summary>
// This class was auto-generated by the StronglyTypedResourceBuilder
// class via a tool like ResGen or Visual Studio.
// To add or remove a member, edit your .ResX file then rerun ResGen
// with the /str option, or rebuild your VS project.
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
public class AudibleSounds
private static global::System.Resources.ResourceManager resourceMan;
private static global::System.Globalization.CultureInfo resourceCulture;
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
internal AudibleSounds()
/// <summary>
/// Returns the cached ResourceManager instance used by this class.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
public static global::System.Resources.ResourceManager ResourceManager
get
if (object.ReferenceEquals(resourceMan, null))
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("ControlsLib.AudibleSounds", typeof(AudibleSounds).Assembly);
resourceMan = temp;
return resourceMan;
/// <summary>
/// Overrides the current thread's CurrentUICulture property for all
/// resource lookups using this strongly typed resource class.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
public static global::System.Globalization.CultureInfo Culture
get
return resourceCulture;
set
resourceCulture = value;
/// <summary>
/// Looks up a localized resource of type System.IO.UnmanagedMemoryStream similar to System.IO.MemoryStream.
/// </summary>
public static System.IO.UnmanagedMemoryStream Horn
get
return ResourceManager.GetStream("Horn", resourceCulture);
/// <summary>
/// Looks up a localized resource of type System.IO.UnmanagedMemoryStream similar to System.IO.MemoryStream.
/// </summary>
public static System.IO.UnmanagedMemoryStream HornOff
get
return ResourceManager.GetStream("HornOff", resourceCulture);
AudibleSounds.resx
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<assembly alias="System.Windows.Forms" name="System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
<data name="HornOff" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>ResourcesHornOff.wav;System.IO.MemoryStream, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data>
<data name="Horn" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>ResourcesHorn.wav;System.IO.MemoryStream, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data>
</root>
Edits
Edit #1
I should also mention my code works as expected when the solution is debugged by running Visual Studio as an external program as so:
But the code does NOT work after building my ControlsLib
project and I add my Control_Audible
control to a form WITHOUT debugging via an external Visual Studio (as most normal users would...).
c# visual-studio typeconverter
add a comment |
Overview
I have a C# project ControlsLib
which contains the following (code to follow later):
- A custom C# control
Control_Audible
that plays a .wav file that is selected at design-time from the properties pane - A
SoundItem
class as the class to support which file will be played - A
SoundItemConverter
class as aTypeConverter
for elegantly selecting which audio file to play in the properties window.
What IS working
My code works as expected when my solution is FIRST opened and my ControlsLib
project is NOT built.
When I add Control_Audible
to a form, I can select an audio file from the available audio resources:
And the designer file generates code as I would expect when the non-default SoundItem is selected:
What is NOT working
My code seems to NOT work as expected after building/rebuilding my ControlsLib
project and add my Control_Audible
control to a form...
The available audio resource files are populated in the dropdown as expected, but the SoundItem specified as the DefaultValue
("None") is Bold when it really should not be:
Also, whenever I try to save the form, I receive the following error:
I was at one time able to generate some auto-code for my Control_Audible
, but even then it did not generate the code I expected, and now it seems to not generate any code at all and my ConvertTo
function is messed up.
Question
It seems to work fine if I don't build my ControlsLib
project, but I can't expect to have to restart Visual Studio every time I want this thing to work. I should be able to rebuild my project as much as desired and still have my control work properly. I will mention I am using Visual Studio 2015.
Does anyone have any ideas why this is behaving this way? I've spent quite a bit of time on this and cannot figure out why this is happening!
The Code
Control_Audible.cs
using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.ComponentModel.Design.Serialization;
using System.Drawing;
using System.Globalization;
using System.Media;
using System.Reflection;
using System.Resources;
using System.Windows.Forms;
namespace ControlsLib
public class Control_Audible : UserControl
public Control_Audible() : base()
FileToPlay = SoundItem.None;
InitializeComponent();
private void InitializeComponent()
this.SuspendLayout();
//
// Control_Audible
//
this.AutoScaleDimensions = new SizeF(6F, 13F);
this.Name = "Control_Audible";
this.ResumeLayout(false);
[Category("Sounds")]
[DisplayName("SoundToPlay")]
[Description("File to play")]
[DefaultValue(typeof(SoundItem), "None")]
//[DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
public SoundItem FileToPlay
get;
set;
[TypeConverter(typeof(SoundItemConverter))]
[Serializable]
public struct SoundItem
public static readonly SoundItem None = new SoundItem("None");
//[Browsable(false)]
//[DefaultValue("None")]
//[DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
internal string Name
get;
set;
// Todo: Create a valid flag
public SoundItem(string Name) : this()
this.Name = Name;
public SoundPlayer GetSoundPlayer()
SoundPlayer retVal = null;
if (!string.IsNullOrEmpty(Name))
retVal = new SoundPlayer(AudibleSounds.ResourceManager.GetStream(Name));
return retVal;
public override string ToString()
return Name;
public static bool operator ==(SoundItem left, SoundItem right)
return left.Name == right.Name;
public static bool operator !=(SoundItem left, SoundItem right)
return !(left == right);
public override bool Equals(object obj)
// override Equals and write code to actually
// test for equality so that the SoundItem created
// from the call to ConvertFrom will be equal to
// the field you created
if (!(obj is SoundItem))
return false;
SoundItem comp = (SoundItem)obj;
// Note value types can't have derived classes, so we don't need
// to check the types of the objects here. -- Microsoft, 2/21/2001
return comp.Name == Name;
public override int GetHashCode()
return Name.GetHashCode();
public class SoundItemConverter : TypeConverter
private Dictionary<string, object> _resourceValues = new Dictionary<string, object>()
"None", SoundItem.None ,
;
public SoundItemConverter()
// Initializes the standard values list with defaults.
ResourceSet _resourceSet = AudibleSounds.ResourceManager.GetResourceSet(CultureInfo.CurrentCulture, true, true);
if (_resourceSet == null)
throw new Exception("Missing Resource Audio files");
// Make a dictionary now for easier use
foreach (DictionaryEntry entry in _resourceSet)
string resourceKey = entry.Key.ToString();
//object resource = entry.Value;
_resourceValues.Add(resourceKey,
new SoundItem(resourceKey));
// Indicates this converter provides a list of standard values.
public override bool GetStandardValuesSupported(ITypeDescriptorContext context)
return true;
// Returns a StandardValuesCollection of standard value objects.
public override StandardValuesCollection GetStandardValues(ITypeDescriptorContext context)
return new StandardValuesCollection( _resourceValues.Values);
// Returns true for a sourceType of string to indicate that
// conversions from string are supported. (The
// GetStandardValues method requires a string to native type
// conversion because the items in the drop-down list are
// translated to string.)
public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
if (sourceType == typeof(string))
return true;
return base.CanConvertFrom(context, sourceType);
// If the type of the value to convert is string, parses the string
// to set the value of the property to.
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
// This is the method that is called when you specify a default value for your type.
// Convert a string representation to SoundItem.
string strValue = value as string;
if (strValue != null)
string text = strValue.Trim();
if (text.Length == 0)
return SoundItem.None;
else
return new SoundItem(text);
return base.ConvertFrom(context, culture, value);
public override bool CanConvertTo(ITypeDescriptorContext context, Type destType)
if (destType == typeof(InstanceDescriptor))
return true;
return base.CanConvertTo(context, destType);
public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destType)
if (destType == null)
throw new ArgumentNullException("destinationType");
if (value is SoundItem)
SoundItem si = (SoundItem)value;
if (destType == typeof(string))
TypeConverter stringConverter = TypeDescriptor.GetConverter(typeof(string));
// Note: ConvertToString will raise exception if value cannot be converted.
return stringConverter.ConvertToString(context, culture, si.Name);
else if (destType == typeof(InstanceDescriptor))
ConstructorInfo ctor = typeof(SoundItem).GetConstructor(new Type[] typeof(string) );
if (ctor != null)
return new InstanceDescriptor(ctor, new object[] si.Name );
return base.ConvertTo(context, culture, value, destType);
//
// Summary:
// Creates an instance of this type given a set of property values for the object.
//
// Parameters:
// context:
// A type descriptor through which additional context can be provided.
//
// propertyValues:
// A dictionary of new property values. The dictionary contains a series of name-value
// pairs, one for each property returned from SoundItemConverter.GetProperties(System.ComponentModel.ITypeDescriptorContext,System.Object,System.Attribute[]).
//
// Returns:
// The newly created object, or null if the object could not be created. The default
// implementation returns null.
public override object CreateInstance(ITypeDescriptorContext context, IDictionary propertyValues)
!(name is string))
throw new ArgumentException();
return new SoundItem((string)name);
//
// Summary:
// Determines if changing a value on this object should require a call to SoundItemConverter.CreateInstance(System.ComponentModel.ITypeDescriptorContext,System.Collections.IDictionary)
// to create a new value.
//
// Parameters:
// context:
// A System.ComponentModel.TypeDescriptor through which additional context can be
// provided.
//
// Returns:
// true if the SoundItemConverter.CreateInstance(System.ComponentModel.ITypeDescriptorContext,System.Collections.IDictionary)
// method should be called when a change is made to one or more properties of this
// object; otherwise, false.
public override bool GetCreateInstanceSupported(ITypeDescriptorContext context)
return true;
//
// Summary:
// Retrieves the set of properties for this type. By default, a type does not return
// any properties.
//
// Parameters:
// context:
// A type descriptor through which additional context can be provided.
//
// value:
// The value of the object to get the properties for.
//
// attributes:
// An array of System.Attribute objects that describe the properties.
//
// Returns:
// The set of properties that are exposed for this data type. If no properties are
// exposed, this method might return null. The default implementation always returns
// null.
public override PropertyDescriptorCollection GetProperties(ITypeDescriptorContext context, object value, Attribute[] attributes)
PropertyDescriptorCollection props = TypeDescriptor.GetProperties(typeof(SoundItem), attributes);
return props.Sort(new string[] "Name" );
//
// Summary:
// Determines if this object supports properties. By default, this is false.
//
// Parameters:
// context:
// A System.ComponentModel.TypeDescriptor through which additional context can be
// provided.
//
// Returns:
// true if SoundItemCoverter.GetProperties(System.ComponentModel.ITypeDescriptorContext,System.Object,System.Attribute[])
// should be called to find the properties of this object; otherwise, false.
public override bool GetPropertiesSupported(ITypeDescriptorContext context)
return true;
AudibleSounds.Designer.cs
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:4.0.30319.42000
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace ControlsLib
using System;
/// <summary>
/// A strongly-typed resource class, for looking up localized strings, etc.
/// </summary>
// This class was auto-generated by the StronglyTypedResourceBuilder
// class via a tool like ResGen or Visual Studio.
// To add or remove a member, edit your .ResX file then rerun ResGen
// with the /str option, or rebuild your VS project.
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
public class AudibleSounds
private static global::System.Resources.ResourceManager resourceMan;
private static global::System.Globalization.CultureInfo resourceCulture;
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
internal AudibleSounds()
/// <summary>
/// Returns the cached ResourceManager instance used by this class.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
public static global::System.Resources.ResourceManager ResourceManager
get
if (object.ReferenceEquals(resourceMan, null))
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("ControlsLib.AudibleSounds", typeof(AudibleSounds).Assembly);
resourceMan = temp;
return resourceMan;
/// <summary>
/// Overrides the current thread's CurrentUICulture property for all
/// resource lookups using this strongly typed resource class.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
public static global::System.Globalization.CultureInfo Culture
get
return resourceCulture;
set
resourceCulture = value;
/// <summary>
/// Looks up a localized resource of type System.IO.UnmanagedMemoryStream similar to System.IO.MemoryStream.
/// </summary>
public static System.IO.UnmanagedMemoryStream Horn
get
return ResourceManager.GetStream("Horn", resourceCulture);
/// <summary>
/// Looks up a localized resource of type System.IO.UnmanagedMemoryStream similar to System.IO.MemoryStream.
/// </summary>
public static System.IO.UnmanagedMemoryStream HornOff
get
return ResourceManager.GetStream("HornOff", resourceCulture);
AudibleSounds.resx
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<assembly alias="System.Windows.Forms" name="System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
<data name="HornOff" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>ResourcesHornOff.wav;System.IO.MemoryStream, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data>
<data name="Horn" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>ResourcesHorn.wav;System.IO.MemoryStream, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data>
</root>
Edits
Edit #1
I should also mention my code works as expected when the solution is debugged by running Visual Studio as an external program as so:
But the code does NOT work after building my ControlsLib
project and I add my Control_Audible
control to a form WITHOUT debugging via an external Visual Studio (as most normal users would...).
c# visual-studio typeconverter
add a comment |
Overview
I have a C# project ControlsLib
which contains the following (code to follow later):
- A custom C# control
Control_Audible
that plays a .wav file that is selected at design-time from the properties pane - A
SoundItem
class as the class to support which file will be played - A
SoundItemConverter
class as aTypeConverter
for elegantly selecting which audio file to play in the properties window.
What IS working
My code works as expected when my solution is FIRST opened and my ControlsLib
project is NOT built.
When I add Control_Audible
to a form, I can select an audio file from the available audio resources:
And the designer file generates code as I would expect when the non-default SoundItem is selected:
What is NOT working
My code seems to NOT work as expected after building/rebuilding my ControlsLib
project and add my Control_Audible
control to a form...
The available audio resource files are populated in the dropdown as expected, but the SoundItem specified as the DefaultValue
("None") is Bold when it really should not be:
Also, whenever I try to save the form, I receive the following error:
I was at one time able to generate some auto-code for my Control_Audible
, but even then it did not generate the code I expected, and now it seems to not generate any code at all and my ConvertTo
function is messed up.
Question
It seems to work fine if I don't build my ControlsLib
project, but I can't expect to have to restart Visual Studio every time I want this thing to work. I should be able to rebuild my project as much as desired and still have my control work properly. I will mention I am using Visual Studio 2015.
Does anyone have any ideas why this is behaving this way? I've spent quite a bit of time on this and cannot figure out why this is happening!
The Code
Control_Audible.cs
using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.ComponentModel.Design.Serialization;
using System.Drawing;
using System.Globalization;
using System.Media;
using System.Reflection;
using System.Resources;
using System.Windows.Forms;
namespace ControlsLib
public class Control_Audible : UserControl
public Control_Audible() : base()
FileToPlay = SoundItem.None;
InitializeComponent();
private void InitializeComponent()
this.SuspendLayout();
//
// Control_Audible
//
this.AutoScaleDimensions = new SizeF(6F, 13F);
this.Name = "Control_Audible";
this.ResumeLayout(false);
[Category("Sounds")]
[DisplayName("SoundToPlay")]
[Description("File to play")]
[DefaultValue(typeof(SoundItem), "None")]
//[DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
public SoundItem FileToPlay
get;
set;
[TypeConverter(typeof(SoundItemConverter))]
[Serializable]
public struct SoundItem
public static readonly SoundItem None = new SoundItem("None");
//[Browsable(false)]
//[DefaultValue("None")]
//[DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
internal string Name
get;
set;
// Todo: Create a valid flag
public SoundItem(string Name) : this()
this.Name = Name;
public SoundPlayer GetSoundPlayer()
SoundPlayer retVal = null;
if (!string.IsNullOrEmpty(Name))
retVal = new SoundPlayer(AudibleSounds.ResourceManager.GetStream(Name));
return retVal;
public override string ToString()
return Name;
public static bool operator ==(SoundItem left, SoundItem right)
return left.Name == right.Name;
public static bool operator !=(SoundItem left, SoundItem right)
return !(left == right);
public override bool Equals(object obj)
// override Equals and write code to actually
// test for equality so that the SoundItem created
// from the call to ConvertFrom will be equal to
// the field you created
if (!(obj is SoundItem))
return false;
SoundItem comp = (SoundItem)obj;
// Note value types can't have derived classes, so we don't need
// to check the types of the objects here. -- Microsoft, 2/21/2001
return comp.Name == Name;
public override int GetHashCode()
return Name.GetHashCode();
public class SoundItemConverter : TypeConverter
private Dictionary<string, object> _resourceValues = new Dictionary<string, object>()
"None", SoundItem.None ,
;
public SoundItemConverter()
// Initializes the standard values list with defaults.
ResourceSet _resourceSet = AudibleSounds.ResourceManager.GetResourceSet(CultureInfo.CurrentCulture, true, true);
if (_resourceSet == null)
throw new Exception("Missing Resource Audio files");
// Make a dictionary now for easier use
foreach (DictionaryEntry entry in _resourceSet)
string resourceKey = entry.Key.ToString();
//object resource = entry.Value;
_resourceValues.Add(resourceKey,
new SoundItem(resourceKey));
// Indicates this converter provides a list of standard values.
public override bool GetStandardValuesSupported(ITypeDescriptorContext context)
return true;
// Returns a StandardValuesCollection of standard value objects.
public override StandardValuesCollection GetStandardValues(ITypeDescriptorContext context)
return new StandardValuesCollection( _resourceValues.Values);
// Returns true for a sourceType of string to indicate that
// conversions from string are supported. (The
// GetStandardValues method requires a string to native type
// conversion because the items in the drop-down list are
// translated to string.)
public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
if (sourceType == typeof(string))
return true;
return base.CanConvertFrom(context, sourceType);
// If the type of the value to convert is string, parses the string
// to set the value of the property to.
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
// This is the method that is called when you specify a default value for your type.
// Convert a string representation to SoundItem.
string strValue = value as string;
if (strValue != null)
string text = strValue.Trim();
if (text.Length == 0)
return SoundItem.None;
else
return new SoundItem(text);
return base.ConvertFrom(context, culture, value);
public override bool CanConvertTo(ITypeDescriptorContext context, Type destType)
if (destType == typeof(InstanceDescriptor))
return true;
return base.CanConvertTo(context, destType);
public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destType)
if (destType == null)
throw new ArgumentNullException("destinationType");
if (value is SoundItem)
SoundItem si = (SoundItem)value;
if (destType == typeof(string))
TypeConverter stringConverter = TypeDescriptor.GetConverter(typeof(string));
// Note: ConvertToString will raise exception if value cannot be converted.
return stringConverter.ConvertToString(context, culture, si.Name);
else if (destType == typeof(InstanceDescriptor))
ConstructorInfo ctor = typeof(SoundItem).GetConstructor(new Type[] typeof(string) );
if (ctor != null)
return new InstanceDescriptor(ctor, new object[] si.Name );
return base.ConvertTo(context, culture, value, destType);
//
// Summary:
// Creates an instance of this type given a set of property values for the object.
//
// Parameters:
// context:
// A type descriptor through which additional context can be provided.
//
// propertyValues:
// A dictionary of new property values. The dictionary contains a series of name-value
// pairs, one for each property returned from SoundItemConverter.GetProperties(System.ComponentModel.ITypeDescriptorContext,System.Object,System.Attribute[]).
//
// Returns:
// The newly created object, or null if the object could not be created. The default
// implementation returns null.
public override object CreateInstance(ITypeDescriptorContext context, IDictionary propertyValues)
!(name is string))
throw new ArgumentException();
return new SoundItem((string)name);
//
// Summary:
// Determines if changing a value on this object should require a call to SoundItemConverter.CreateInstance(System.ComponentModel.ITypeDescriptorContext,System.Collections.IDictionary)
// to create a new value.
//
// Parameters:
// context:
// A System.ComponentModel.TypeDescriptor through which additional context can be
// provided.
//
// Returns:
// true if the SoundItemConverter.CreateInstance(System.ComponentModel.ITypeDescriptorContext,System.Collections.IDictionary)
// method should be called when a change is made to one or more properties of this
// object; otherwise, false.
public override bool GetCreateInstanceSupported(ITypeDescriptorContext context)
return true;
//
// Summary:
// Retrieves the set of properties for this type. By default, a type does not return
// any properties.
//
// Parameters:
// context:
// A type descriptor through which additional context can be provided.
//
// value:
// The value of the object to get the properties for.
//
// attributes:
// An array of System.Attribute objects that describe the properties.
//
// Returns:
// The set of properties that are exposed for this data type. If no properties are
// exposed, this method might return null. The default implementation always returns
// null.
public override PropertyDescriptorCollection GetProperties(ITypeDescriptorContext context, object value, Attribute[] attributes)
PropertyDescriptorCollection props = TypeDescriptor.GetProperties(typeof(SoundItem), attributes);
return props.Sort(new string[] "Name" );
//
// Summary:
// Determines if this object supports properties. By default, this is false.
//
// Parameters:
// context:
// A System.ComponentModel.TypeDescriptor through which additional context can be
// provided.
//
// Returns:
// true if SoundItemCoverter.GetProperties(System.ComponentModel.ITypeDescriptorContext,System.Object,System.Attribute[])
// should be called to find the properties of this object; otherwise, false.
public override bool GetPropertiesSupported(ITypeDescriptorContext context)
return true;
AudibleSounds.Designer.cs
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:4.0.30319.42000
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace ControlsLib
using System;
/// <summary>
/// A strongly-typed resource class, for looking up localized strings, etc.
/// </summary>
// This class was auto-generated by the StronglyTypedResourceBuilder
// class via a tool like ResGen or Visual Studio.
// To add or remove a member, edit your .ResX file then rerun ResGen
// with the /str option, or rebuild your VS project.
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
public class AudibleSounds
private static global::System.Resources.ResourceManager resourceMan;
private static global::System.Globalization.CultureInfo resourceCulture;
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
internal AudibleSounds()
/// <summary>
/// Returns the cached ResourceManager instance used by this class.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
public static global::System.Resources.ResourceManager ResourceManager
get
if (object.ReferenceEquals(resourceMan, null))
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("ControlsLib.AudibleSounds", typeof(AudibleSounds).Assembly);
resourceMan = temp;
return resourceMan;
/// <summary>
/// Overrides the current thread's CurrentUICulture property for all
/// resource lookups using this strongly typed resource class.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
public static global::System.Globalization.CultureInfo Culture
get
return resourceCulture;
set
resourceCulture = value;
/// <summary>
/// Looks up a localized resource of type System.IO.UnmanagedMemoryStream similar to System.IO.MemoryStream.
/// </summary>
public static System.IO.UnmanagedMemoryStream Horn
get
return ResourceManager.GetStream("Horn", resourceCulture);
/// <summary>
/// Looks up a localized resource of type System.IO.UnmanagedMemoryStream similar to System.IO.MemoryStream.
/// </summary>
public static System.IO.UnmanagedMemoryStream HornOff
get
return ResourceManager.GetStream("HornOff", resourceCulture);
AudibleSounds.resx
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<assembly alias="System.Windows.Forms" name="System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
<data name="HornOff" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>ResourcesHornOff.wav;System.IO.MemoryStream, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data>
<data name="Horn" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>ResourcesHorn.wav;System.IO.MemoryStream, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data>
</root>
Edits
Edit #1
I should also mention my code works as expected when the solution is debugged by running Visual Studio as an external program as so:
But the code does NOT work after building my ControlsLib
project and I add my Control_Audible
control to a form WITHOUT debugging via an external Visual Studio (as most normal users would...).
c# visual-studio typeconverter
Overview
I have a C# project ControlsLib
which contains the following (code to follow later):
- A custom C# control
Control_Audible
that plays a .wav file that is selected at design-time from the properties pane - A
SoundItem
class as the class to support which file will be played - A
SoundItemConverter
class as aTypeConverter
for elegantly selecting which audio file to play in the properties window.
What IS working
My code works as expected when my solution is FIRST opened and my ControlsLib
project is NOT built.
When I add Control_Audible
to a form, I can select an audio file from the available audio resources:
And the designer file generates code as I would expect when the non-default SoundItem is selected:
What is NOT working
My code seems to NOT work as expected after building/rebuilding my ControlsLib
project and add my Control_Audible
control to a form...
The available audio resource files are populated in the dropdown as expected, but the SoundItem specified as the DefaultValue
("None") is Bold when it really should not be:
Also, whenever I try to save the form, I receive the following error:
I was at one time able to generate some auto-code for my Control_Audible
, but even then it did not generate the code I expected, and now it seems to not generate any code at all and my ConvertTo
function is messed up.
Question
It seems to work fine if I don't build my ControlsLib
project, but I can't expect to have to restart Visual Studio every time I want this thing to work. I should be able to rebuild my project as much as desired and still have my control work properly. I will mention I am using Visual Studio 2015.
Does anyone have any ideas why this is behaving this way? I've spent quite a bit of time on this and cannot figure out why this is happening!
The Code
Control_Audible.cs
using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.ComponentModel.Design.Serialization;
using System.Drawing;
using System.Globalization;
using System.Media;
using System.Reflection;
using System.Resources;
using System.Windows.Forms;
namespace ControlsLib
public class Control_Audible : UserControl
public Control_Audible() : base()
FileToPlay = SoundItem.None;
InitializeComponent();
private void InitializeComponent()
this.SuspendLayout();
//
// Control_Audible
//
this.AutoScaleDimensions = new SizeF(6F, 13F);
this.Name = "Control_Audible";
this.ResumeLayout(false);
[Category("Sounds")]
[DisplayName("SoundToPlay")]
[Description("File to play")]
[DefaultValue(typeof(SoundItem), "None")]
//[DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
public SoundItem FileToPlay
get;
set;
[TypeConverter(typeof(SoundItemConverter))]
[Serializable]
public struct SoundItem
public static readonly SoundItem None = new SoundItem("None");
//[Browsable(false)]
//[DefaultValue("None")]
//[DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
internal string Name
get;
set;
// Todo: Create a valid flag
public SoundItem(string Name) : this()
this.Name = Name;
public SoundPlayer GetSoundPlayer()
SoundPlayer retVal = null;
if (!string.IsNullOrEmpty(Name))
retVal = new SoundPlayer(AudibleSounds.ResourceManager.GetStream(Name));
return retVal;
public override string ToString()
return Name;
public static bool operator ==(SoundItem left, SoundItem right)
return left.Name == right.Name;
public static bool operator !=(SoundItem left, SoundItem right)
return !(left == right);
public override bool Equals(object obj)
// override Equals and write code to actually
// test for equality so that the SoundItem created
// from the call to ConvertFrom will be equal to
// the field you created
if (!(obj is SoundItem))
return false;
SoundItem comp = (SoundItem)obj;
// Note value types can't have derived classes, so we don't need
// to check the types of the objects here. -- Microsoft, 2/21/2001
return comp.Name == Name;
public override int GetHashCode()
return Name.GetHashCode();
public class SoundItemConverter : TypeConverter
private Dictionary<string, object> _resourceValues = new Dictionary<string, object>()
"None", SoundItem.None ,
;
public SoundItemConverter()
// Initializes the standard values list with defaults.
ResourceSet _resourceSet = AudibleSounds.ResourceManager.GetResourceSet(CultureInfo.CurrentCulture, true, true);
if (_resourceSet == null)
throw new Exception("Missing Resource Audio files");
// Make a dictionary now for easier use
foreach (DictionaryEntry entry in _resourceSet)
string resourceKey = entry.Key.ToString();
//object resource = entry.Value;
_resourceValues.Add(resourceKey,
new SoundItem(resourceKey));
// Indicates this converter provides a list of standard values.
public override bool GetStandardValuesSupported(ITypeDescriptorContext context)
return true;
// Returns a StandardValuesCollection of standard value objects.
public override StandardValuesCollection GetStandardValues(ITypeDescriptorContext context)
return new StandardValuesCollection( _resourceValues.Values);
// Returns true for a sourceType of string to indicate that
// conversions from string are supported. (The
// GetStandardValues method requires a string to native type
// conversion because the items in the drop-down list are
// translated to string.)
public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
if (sourceType == typeof(string))
return true;
return base.CanConvertFrom(context, sourceType);
// If the type of the value to convert is string, parses the string
// to set the value of the property to.
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
// This is the method that is called when you specify a default value for your type.
// Convert a string representation to SoundItem.
string strValue = value as string;
if (strValue != null)
string text = strValue.Trim();
if (text.Length == 0)
return SoundItem.None;
else
return new SoundItem(text);
return base.ConvertFrom(context, culture, value);
public override bool CanConvertTo(ITypeDescriptorContext context, Type destType)
if (destType == typeof(InstanceDescriptor))
return true;
return base.CanConvertTo(context, destType);
public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destType)
if (destType == null)
throw new ArgumentNullException("destinationType");
if (value is SoundItem)
SoundItem si = (SoundItem)value;
if (destType == typeof(string))
TypeConverter stringConverter = TypeDescriptor.GetConverter(typeof(string));
// Note: ConvertToString will raise exception if value cannot be converted.
return stringConverter.ConvertToString(context, culture, si.Name);
else if (destType == typeof(InstanceDescriptor))
ConstructorInfo ctor = typeof(SoundItem).GetConstructor(new Type[] typeof(string) );
if (ctor != null)
return new InstanceDescriptor(ctor, new object[] si.Name );
return base.ConvertTo(context, culture, value, destType);
//
// Summary:
// Creates an instance of this type given a set of property values for the object.
//
// Parameters:
// context:
// A type descriptor through which additional context can be provided.
//
// propertyValues:
// A dictionary of new property values. The dictionary contains a series of name-value
// pairs, one for each property returned from SoundItemConverter.GetProperties(System.ComponentModel.ITypeDescriptorContext,System.Object,System.Attribute[]).
//
// Returns:
// The newly created object, or null if the object could not be created. The default
// implementation returns null.
public override object CreateInstance(ITypeDescriptorContext context, IDictionary propertyValues)
!(name is string))
throw new ArgumentException();
return new SoundItem((string)name);
//
// Summary:
// Determines if changing a value on this object should require a call to SoundItemConverter.CreateInstance(System.ComponentModel.ITypeDescriptorContext,System.Collections.IDictionary)
// to create a new value.
//
// Parameters:
// context:
// A System.ComponentModel.TypeDescriptor through which additional context can be
// provided.
//
// Returns:
// true if the SoundItemConverter.CreateInstance(System.ComponentModel.ITypeDescriptorContext,System.Collections.IDictionary)
// method should be called when a change is made to one or more properties of this
// object; otherwise, false.
public override bool GetCreateInstanceSupported(ITypeDescriptorContext context)
return true;
//
// Summary:
// Retrieves the set of properties for this type. By default, a type does not return
// any properties.
//
// Parameters:
// context:
// A type descriptor through which additional context can be provided.
//
// value:
// The value of the object to get the properties for.
//
// attributes:
// An array of System.Attribute objects that describe the properties.
//
// Returns:
// The set of properties that are exposed for this data type. If no properties are
// exposed, this method might return null. The default implementation always returns
// null.
public override PropertyDescriptorCollection GetProperties(ITypeDescriptorContext context, object value, Attribute[] attributes)
PropertyDescriptorCollection props = TypeDescriptor.GetProperties(typeof(SoundItem), attributes);
return props.Sort(new string[] "Name" );
//
// Summary:
// Determines if this object supports properties. By default, this is false.
//
// Parameters:
// context:
// A System.ComponentModel.TypeDescriptor through which additional context can be
// provided.
//
// Returns:
// true if SoundItemCoverter.GetProperties(System.ComponentModel.ITypeDescriptorContext,System.Object,System.Attribute[])
// should be called to find the properties of this object; otherwise, false.
public override bool GetPropertiesSupported(ITypeDescriptorContext context)
return true;
AudibleSounds.Designer.cs
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:4.0.30319.42000
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace ControlsLib
using System;
/// <summary>
/// A strongly-typed resource class, for looking up localized strings, etc.
/// </summary>
// This class was auto-generated by the StronglyTypedResourceBuilder
// class via a tool like ResGen or Visual Studio.
// To add or remove a member, edit your .ResX file then rerun ResGen
// with the /str option, or rebuild your VS project.
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
public class AudibleSounds
private static global::System.Resources.ResourceManager resourceMan;
private static global::System.Globalization.CultureInfo resourceCulture;
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
internal AudibleSounds()
/// <summary>
/// Returns the cached ResourceManager instance used by this class.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
public static global::System.Resources.ResourceManager ResourceManager
get
if (object.ReferenceEquals(resourceMan, null))
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("ControlsLib.AudibleSounds", typeof(AudibleSounds).Assembly);
resourceMan = temp;
return resourceMan;
/// <summary>
/// Overrides the current thread's CurrentUICulture property for all
/// resource lookups using this strongly typed resource class.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
public static global::System.Globalization.CultureInfo Culture
get
return resourceCulture;
set
resourceCulture = value;
/// <summary>
/// Looks up a localized resource of type System.IO.UnmanagedMemoryStream similar to System.IO.MemoryStream.
/// </summary>
public static System.IO.UnmanagedMemoryStream Horn
get
return ResourceManager.GetStream("Horn", resourceCulture);
/// <summary>
/// Looks up a localized resource of type System.IO.UnmanagedMemoryStream similar to System.IO.MemoryStream.
/// </summary>
public static System.IO.UnmanagedMemoryStream HornOff
get
return ResourceManager.GetStream("HornOff", resourceCulture);
AudibleSounds.resx
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<assembly alias="System.Windows.Forms" name="System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
<data name="HornOff" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>ResourcesHornOff.wav;System.IO.MemoryStream, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data>
<data name="Horn" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>ResourcesHorn.wav;System.IO.MemoryStream, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data>
</root>
Edits
Edit #1
I should also mention my code works as expected when the solution is debugged by running Visual Studio as an external program as so:
But the code does NOT work after building my ControlsLib
project and I add my Control_Audible
control to a form WITHOUT debugging via an external Visual Studio (as most normal users would...).
c# visual-studio typeconverter
c# visual-studio typeconverter
edited Mar 8 at 12:24
Kyle Ross
asked Mar 7 at 21:25
Kyle RossKyle Ross
536
536
add a comment |
add a comment |
0
active
oldest
votes
Your Answer
StackExchange.ifUsing("editor", function ()
StackExchange.using("externalEditor", function ()
StackExchange.using("snippets", function ()
StackExchange.snippets.init();
);
);
, "code-snippets");
StackExchange.ready(function()
var channelOptions =
tags: "".split(" "),
id: "1"
;
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function()
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled)
StackExchange.using("snippets", function()
createEditor();
);
else
createEditor();
);
function createEditor()
StackExchange.prepareEditor(
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader:
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
,
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
);
);
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f55053018%2fcontrol-with-custom-typeconverter-does-not-work-after-project-rebuild%23new-answer', 'question_page');
);
Post as a guest
Required, but never shown
0
active
oldest
votes
0
active
oldest
votes
active
oldest
votes
active
oldest
votes
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f55053018%2fcontrol-with-custom-typeconverter-does-not-work-after-project-rebuild%23new-answer', 'question_page');
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown