propertyGrid with hastable in stringconvertor inherited class - c#

i have hashtable in videoformates class inherited from StringConvertor class. Two functions ConvertFrom and ConvertTo override there. How iplement these two functions to show video formates as string.
public class VideoFormate : StringConverter
{
private Hashtable VideoFormates;
public VideoFormate() {
VideoFormates = new Hashtable();
VideoFormates[".3g2"] = "3GPP2";
VideoFormates[".3gp"] = "3GPP";
}
public override bool GetStandardValuesSupported(ITypeDescriptorContext context)
{
return true;
}
public override StandardValuesCollection GetStandardValues(ITypeDescriptorContext context)
{
return new StandardValuesCollection(VideoFormates);
}
public override bool GetStandardValuesExclusive(ITypeDescriptorContext context)
{
return true;
}
public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType)
{
return base.ConvertTo(context, culture, value, destinationType);
}
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
{
return base.ConvertFrom(context, culture, value);
}
class for video properties is
class videoProperties
{
private string _VideoFormat;
[TypeConverter(typeof(VideoFormate)),
CategoryAttribute("Video Setting"),
DefaultValueAttribute(0),
DescriptionAttribute("Select a Formate from the list")]
public string VideoFormat
{
get { return _VideoFormat; }
set { _VideoFormat = value; }
}
}
i want to display 3GPP2 as display member and .3gp2 as value member in combo box in propertyGrid.

After debugging the code i found the answer.
On first run, in above code, propertyGrid dropdown fill with Hashtable collection. ConvertTo method convert it into string. so it save as System.Collections.DictionaryEntry.
when select an element from combo box it set videoProperties.VideoFormat as System.Collections.DictionaryEntry. So i changed ConvertTo function as below.
public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType)
{
if (value is DictionaryEntry)
{
return ((DictionaryEntry)value).Key;
}
else if (value != null)
{
return VideoFormates[value];
}
return base.ConvertTo(context, culture, value, destinationType);
}
function check if value type is DictionaryEntry then it cast it and return the key element of value parameter. So combo box fill out with key values. when form shows ConvertTo function again called and second time return combo box values. then simplay return Hashtable value on the base of combo box value.

Related

Json.Net: Serialize/Deserialize property as a value, not as an object

How can I achieve the following JSON representation of Id class when used in another class?
class Car
{
public StringId Id { get; set; }
public string Name { get; set; }
}
class StringId
{
public string Value { get; set; }
}
// ---------------------------------------------
// Desired representation
{ "Id": "someId", "Name": "Ford" }
// Default (undesired) representation
{ "Id" : { "Value": "someId" }, "Name": "Ford" }
You could add a TypeConverter for StringId. Json.NET will pick up the type converter and use it to convert it from and to a string:
[TypeConverter(typeof(StringIdConverter))]
class StringId
{
public string Value { get; set; }
}
class StringIdConverter : TypeConverter
{
public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
{
if (sourceType == typeof(string))
return true;
return base.CanConvertFrom(context, sourceType);
}
public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
{
if (destinationType == typeof(StringId))
return true;
return base.CanConvertTo(context, destinationType);
}
public override object ConvertFrom(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value)
{
if (value is string)
{
return new StringId { Value = (string)value };
}
return base.ConvertFrom(context, culture, value);
}
public override object ConvertTo(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value, Type destinationType)
{
if (destinationType == typeof(string) && value is StringId)
{
return ((StringId)value).Value;
}
return base.ConvertTo(context, culture, value, destinationType);
}
}
If your string representation contains embedded numeric or date/time data, be sure to convert that data using the culture passed in rather than the default, current culture. Json.NET will call the converter with the correct culture, which is the invariant culture by default, thus ensuring the generated JSON files are portable between cultures.
Sample fiddle.
Note however that, if you are using .Net Core, support for type converters was only added as of Json.NET 10.0.1. And support for type converters in Json.NET Portable builds is not available as of 10.0.3.
Alternatively, if you don't mind adding Json.NET-specific attributes to your type, you could use a custom JsonConverter:
[JsonConverter(typeof(StringIdConverter))]
class StringId
{
public string Value { get; set; }
}
class StringIdConverter : JsonConverter
{
public override bool CanConvert(Type objectType)
{
return objectType == typeof(StringId);
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
if (reader.TokenType == JsonToken.Null)
return null;
var token = JToken.Load(reader);
return new StringId { Value = (string)token };
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
var id = (StringId)value;
writer.WriteValue(id.Value);
}
}
You can also set the converter in global settings.
Sample fiddle.
You can override the ToString method of the StringId class to return the value
public override string ToString()
{
return this.Value;
}
You will need a TypeConverter later to deserialize from string to StringId
public class StringIdConverter : TypeConverter
{
public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
{
if (sourceType == typeof(string))
{
return true;
}
return base.CanConvertFrom(context, sourceType);
}
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
{
if (value is string)
{
return new StringId(value.ToString());
}
return base.ConvertFrom(context, culture, value);
}
}
And decorate your StringId class with this attribute
[TypeConverter(typeof(StringIdConverter))]
public class StringId{
...
}

XAML parser error: The TypeConverter for "MyType" does not support converting from a string

But it does. I have created a type converter that implements CanConvertFrom(), defined the type converter on type type. Everything runs fine. This is just XAML that defines design time data for Blend, but the error is very annoying.
It appears that VS is just not trying to use the type converter. Is there some place that you have to register type converters so that they will be used at design time by Visual Studio?
[TypeConverter(typeof(MyTypeTypeConverter))]
[DataContract]
public struct MyType
{
[DataMember]
internal readonly float _Value;
public MyType(float value)
{
_Value = (float)Math.Round(value, 3);
}
}
public class MyTypeTypeConverter : TypeConverter
{
public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
{
if (sourceType == typeof(String))
return true;
return base.CanConvertFrom(context, sourceType);
}
public override object ConvertFrom(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value)
{
if (value is string)
{
float f;
if (!Single.TryParse((string)value, out f))
return null;
return new MyType(f);
}
return base.ConvertFrom(context, culture, value);
}
public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
{
if (destinationType == typeof(string))
return true;
return base.CanConvertTo(context, destinationType);
}
public override object ConvertTo(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value, Type destinationType)
{
if (destinationType == typeof(string))
{
return ((MyType)value).ToString();
}
return base.ConvertTo(context, culture, value, destinationType);
}
}

Bind Enum Collection in PropertyGrid

I have following enumeration.
public enum Digits
{One, Two, Three}
and a property with two entries.
public List<Digits> DigitList{get;set;}
DigitList.Add(Digits.One); DigitList.Add(Digits.Three);
When this object is bound to PropertyGrid it is displayed as (Collection) and when it is opened (using small browse button) an exception with (no useful message) is displayed. I am confused how the PropertyGrid interprets list of enumerations.
I searched for a solution, but all i could find was about how to bind a enum value, not list of enums.
You have to create a TypeConverter Class that will help the PropertyEditor to parse the Enum into a PropertyEditor.
Sample TypeConverter
public class FooDataTypeConverter : TypeConverter
{
public override bool GetStandardValuesSupported(ITypeDescriptorContext context)
{
return true;
}
public override StandardValuesCollection GetStandardValues(ITypeDescriptorContext context)
{
return base.GetStandardValues(context);
}
public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
{
if (sourceType == typeof(string))
return true;
return (sourceType.Equals(typeof(Enum)));
}
public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
{
return (destinationType.Equals(typeof(String)));
}
public override object ConvertFrom(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value)
{
if (value is string)
{
return (ValidationDataType)Enum.Parse(typeof(ValidationDataType), value.ToString(), true);
}
return base.ConvertFrom(context, culture, value);
}
public override object ConvertTo(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value, Type destinationType)
{
if (!destinationType.Equals(typeof(string)))
throw new ArgumentException("Can only convert to string", "destinationType");
if (!value.GetType().BaseType.Equals(typeof(Enum)))
throw new ArgumentException("Can only convert an instance of enum", "value");
string name = value.ToString();
object[] attr =
value.GetType().GetField(name).GetCustomAttributes(typeof(DescriptionAttribute), false);
return (attr.Length > 0) ? ((DescriptionAttribute)attr[0]).Description : name;
}
}
After add this declaration to the enums that you want to parse in a propertyeditor.
[TypeConverter(typeof(FooDataTypeConverter ))]
public enum ValidationDataType
{
/// <summary>
/// None
/// </summary>
[Description("None")]
None,
.....
}
The last step is to add it to the property of your component that will show in the propertyeditor
[Category("Behavior")]
[Description("Gets or sets the type of data that will be compared")]
[TypeConverter(typeof(DataTypeConverter))]
[EditorAttribute(typeof(ValidatorTypeEditor), typeof(System.Drawing.Design.UITypeEditor))]
public ValidationDataType Type
{
get { return this.type; }
set
{
this.type = value;
if (this is RangeValidator)
{
this.SetRange();
}
}
}

Custom editors in a property grid that uses Dictionary

I am using a property grid that uses a dictionary using the adapter found here.
I now need the ability to use a custom editor. More specifically a file chooser. If the object in the dictionary is a string it just uses the default string editor.
Could I implement a new class called FilePath or something that would just act as a wrapper for string but would cause the property grid to use the OpenFileDialog, and display the result as a string in the PropertyGrid once chosen?
Is this possible? And if so how?
If you want to have the file path editor in the property grid using the dictionary adapter you have referenced, I would make the FilePath class like you suggest. You will need to also implement two additional classes to make this all work with the property grid: An editor and a type converter.
Let's assume your FilePath object is a simple one:
class FilePath
{
public FilePath(string inPath)
{
Path = inPath;
}
public string Path { get; set; }
}
Your property grid will display the class name in light gray, not very useful. Let's write a TypeConverter to display the string that this class really wraps around
class FilePathConverter : TypeConverter
{
public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
{
if (sourceType == typeof(string))
return true;
return base.CanConvertFrom(context, sourceType);
}
public override object ConvertFrom(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value)
{
if (IsValid(context, value))
return new FilePath((string)value);
return base.ConvertFrom(context, culture, value);
}
public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
{
if (destinationType == typeof(string))
return destinationType == typeof(string);
return base.CanConvertTo(context, destinationType);
}
public override object ConvertTo(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value, Type destinationType)
{
if (destinationType == typeof(string))
return ((FilePath)value).Path;
return base.ConvertTo(context, culture, value, destinationType);
}
public override bool IsValid(ITypeDescriptorContext context, object value)
{
if (value.GetType() == typeof(string))
return true;
return base.IsValid(context, value);
}
}
Add the TypeConverter attribute to our FilePath class to convert to and from a string.
[TypeConverter(typeof(FilePathConverter))]
class FilePath
{
...
}
Now the property grid will display the string and not the type name, but you want the ellipsis to bring up a file selection dialog, so we make a UITypeEditor:
class FilePathEditor : UITypeEditor
{
public override System.Drawing.Design.UITypeEditorEditStyle GetEditStyle(ITypeDescriptorContext context)
{
return System.Drawing.Design.UITypeEditorEditStyle.Modal;
}
public override object EditValue(ITypeDescriptorContext context, IServiceProvider provider, object value)
{
FilePath path = (FilePath)value;
OpenFileDialog openFile = new OpenFileDialog();
openFile.FileName = path.Path;
if (openFile.ShowDialog() == DialogResult.OK)
path.Path = openFile.FileName;
return path;
}
}
Add the Editor attribute to our FilePath class to use the new class:
[TypeConverter(typeof(FilePathConverter))]
[Editor(typeof(FilePathEditor), typeof(UITypeEditor))]
class FilePath
{
...
}
Now you can add FilePath objects to your IDictionary and have them editable through the property grid
IDictionary d = new Dictionary<string, object>();
d["Path"] = new FilePath("C:/");

Hide ellipsis (…) button of expandable property like "…" button of font property in the property grid

I've added a new property to my custom control as expandable property like font property in Property Grid. After using from my custom control in a Windows Forms Application project, I see an ellipsis (…) button like "…" button of font property in Property Grid. (For more information, please see the following picture.)
Now, I want to hide the ellipsis (…) button for my new expandable property.
Expandable property codes are:
[DisplayName("Floors Information")]
[Description("Floors Informationnnnnnnnnnnnnnnn")]
[DefaultProperty("TitleText")]
[DesignerCategory("Component")]
public class FloorsInformation : DockContainerItem
{
private SimilarFloorsInformation similarFloorsInformation = new SimilarFloorsInformation();
public FloorsInformation()
{
}
[Category("Data")]
[DisplayName("Similar Floors Panel")]
[Description("Similar Floors Panellllllllllllllllllll")]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
[Editor(typeof(ItemsCollectionEditor), typeof(UITypeEditor))]
//[TypeConverter(typeof(ExpandableObjectConverter))]
//[TypeConverter(typeof(SimilarFloorsInformationTypeConverter))]
public SimilarFloorsInformation SimilarFloorsInfo
{
get
{
return similarFloorsInformation;
}
}
}
[DisplayName("Similar Floors Information")]
[Description("Similar Floors Informationnnnnnnnnnnnnnnn")]
[DefaultProperty("Text")]
[DesignerCategory("Component")]
[TypeConverter(typeof(SimilarFloorsInformationTypeConverter))]
//[TypeConverter(typeof(ExpandableObjectConverter))]
public class SimilarFloorsInformation : ExpandablePanel
{
private Color canvasColor = SystemColors.Control;
private eCollapseDirection collapseDirection = eCollapseDirection.LeftToRight;
private eDotNetBarStyle colorSchemeStyle = eDotNetBarStyle.StyleManagerControlled;
private DockStyle dock = DockStyle.Right;
private eTitleButtonAlignment expandButtonAlignment = eTitleButtonAlignment.Left;
private bool expanded = false;
private bool markupUsesStyleAlignment = true;
private Size size = new Size(30, 177);
public SimilarFloorsInformation()
{
}
}
public class SimilarFloorsInformationTypeConverter : ExpandableObjectConverter//TypeConverter
{
public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
{
if (destinationType == typeof(SimilarFloorsInformation))
{
return true;
}
return base.CanConvertTo(context, destinationType);
}
public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType)
{
if (destinationType == typeof(String) && value is SimilarFloorsInformation)
{
SimilarFloorsInformation similarFloorsInformation = (SimilarFloorsInformation)value;
return similarFloorsInformation.TitleText;
}
return base.ConvertTo(context, culture, value, destinationType);
}
public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
{
if (sourceType == typeof(string))
{
return true;
}
return base.CanConvertFrom(context, sourceType);
}
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
{
if (value is string)
{
SimilarFloorsInformation similarFloorsInformation = new SimilarFloorsInformation();
similarFloorsInformation.TitleText = (string)value;
return similarFloorsInformation;
}
return base.ConvertFrom(context, culture, value);
}
}
You should implement your own class derived from UITypeEditor and override GetEditStyle method as follows:
public override UITypeEditorEditStyle GetEditStyle(ITypeDescriptorContext context)
{
return UITypeEditorEditStyle.None;
}
Then use EditorAttribute:
[Editor(typeof(YourTypeEditor), typeof(UITypeEditor))]
Update 1:
Well. I just realized you're already applying EditorAttribute on the property:
[Editor(typeof(ItemsCollectionEditor), typeof(UITypeEditor))]
public SimilarFloorsInformation SimilarFloorsInfo
{
get
{
return similarFloorsInformation;
}
}
So you should override GetEditStyle in ItemsCollectionEditor.
I solved my problem according to Nikolay Khil answer. Ellipsis (...) button is shown for following line of code (Attribute) that I've applied to the "SimilarFloorsInfo" property of my custom control:
[Editor(typeof(ItemsCollectionEditor), typeof(UITypeEditor))]
So, this line of code must be deleted or commented. Now, Ellipsis (...) button not shown for my property in the property grid.

Categories