I coming unglued... really need some help. 3 days chasing my tail all over
MSDN's documentation ...and I'm getting nowhere.
I have a problem with TypeConverters and
storage of expandableobjec ts to attributes in tags (think Style tag -> Style
object).
The problem that I am chasing is:
Html side:
<CC1:MyContro l id=whatever Stuff="A:Some stuff;B:Another value;C:Bad hair
days"/>
The code behind is 3 classes:
* cStuff which is a complex property -- an instance of a 3 string class: (A,
B,C);
* StuffConverter -- a TypeConverter enherited from ExpandableObjec tConverter
that converts an instance of cStuff to "key:value;key: value;key;value "...
(ie: Stuff="A:Some stuff;B:Another value;C:Bad hair days") and back again.
* MyControl -- a generic test control to see how it works.
* Use of the following attributes on various elements, trying to keep it
glued together:
// [NotifyParentPro perty(true)]
//[Serializable(), TypeConverter(t ypeof(StuffConv erter))]
// [PersistenceMode (PersistenceMod e.Attribute)]
//[DesignerSeriali zationVisibilit y(DesignerSeria lizationVisibil ity.Visible)]
It doesn't matter what I do -- this is not working as expected.
There are 2 areas of error:
a) In the IDE, it doesn't serialize the values back to the backend xml/html
attribute. I can edit both the backend tag -- or the IDE's property and it
renders it correctly in realtime. In other words it can string->object fine.
But it won't save it back to the html (serialize).
b) Problem 2 -- when I run it I get a runtime error //Unable to generate
code for a value of type 'XAct.Web.Contr ols.cStuff'. This error occurred
while trying to generate the property value for Stuff.
The closest match I have seen to a post/answer on the web is at
http://www.dotnet247.com/247referenc.../18/94895.aspx -- but I am not
sure if this applies since that was more complex and had to do with data
binding.
Can any kind soul take a look at this? The code below should contain all
parts and be able to be dropped into one *.cs file to compile and test as a
control.
using System;
using System.Web.UI.D esign;
using System.Web;
using System.Componen tModel;
using System.Globaliz ation;
using System.Reflecti on;
using System.Collecti ons;
using System.Componen tModel.Design;
using System.Web.UI;
using System.Web.UI.W ebControls;
//http://msdn.microsoft. com/library/default.asp?url =/library/en-us/dndotnet/
html/vsnetpropbrow.a sp
namespace XAct.Web.Contro ls {
//=============== =============== ========
//'STUFF' CLASS DEF
//=============== =============== ========
[Serializable(), TypeConverter(t ypeof(StuffConv erter))]
public class cStuff{
private string _A=string.Empty ;
private string _B=string.Empty ;
private string _C=string.Empty ;
[NotifyParentPro perty(true)]
public string A {get {return _A;}set{_A=valu e;}}
[NotifyParentPro perty(true),Def aultValue("Fish ")]
public string B {get {return _B;}set{_B=valu e;}}
[NotifyParentPro perty(true)]
public string C {get {return _C;}set{_C=valu e;}}
}
//=============== =============== ========
//TEST CONTROL CLASS
//=============== =============== ========
public class MyControl : WebControl {
public MyControl(){
this.Controls.A dd(new LiteralControl( "ANGRY TODAY:<br/>"));
}
private cStuff _Stuff = new cStuff();
//Variation Tried:
// [PersistenceMode (PersistenceMod e.Attribute)]
[DesignerSeriali zationVisibilit y(DesignerSeria lizationVisibil ity.Visible)]
// Accepts changes from IDE -- updates PropertySummary , updates
// Rendering -- fails to save as serialized attrib.
// Fails in IDE: "Unable to generate code for a value of type
// XAct.Web.Contro ls.cStuff'.
// This error occurred while trying to generate the
// property value for Stuff."
//Tried:
//[DesignerSeriali zationVisibilit y(DesignerSeria lizationVisibil ity.Visible)]
// Synchs IDE to Render -- doesn't Serialize, and Fails in RunTime
//Tried:
//[PersistenceMode (PersistenceMod e.Attribute)]
// Synchs IDE to Render -- doesn't Serialize, and Fails in RunTime
//BTW: Works if I remove the stuff="" tag from the HTML it doesn't complain.
//In other words, it is failing in runtime when trying to parse the tag. Why
//it is failing to serialize in the ide, I don't know.
[DesignerSeriali zationVisibilit y(DesignerSeria lizationVisibil ity.Visible )]
public cStuff Stuff {get {return _Stuff;}set{_St uff=value;}}
protected override void Render(System.W eb.UI.HtmlTextW riter output) {
//To see what it THINKS it should be:
StuffConverter oSC = new StuffConverter( );
string tSerialized =
(string)oSC.Con vertTo(null,nul l,_Stuff,typeof (string));
output.Write("O nscreen Changes: " + this._Stuff.ToS tring() + ":" +
this._Stuff.A + ":" + ":[" + tSerialized + "]");
base.Render(out put);
}
}
//=============== =============== ========
//TYPE CONVERTER CLASS
//=============== =============== ========
public class StuffConverter : ExpandableObjec tConverter {
System.Type _Type = typeof(cStuff);
public override bool CanConvertFrom( ITypeDescriptor Context context, Type t)
{
if (t == typeof(string)) {return true;}
return base.CanConvert From(context, t);
}
//Convert From String:
public override object ConvertFrom(ITy peDescriptorCon text context,
CultureInfo info,object value) {
if (value is string) {
try {
//_Type = context.Propert yDescriptor.Pro pertyType;
string[] tParts;
tParts = SplitPlus((stri ng) value, ";");
object o = _Type.Assembly. CreateInstance( _Type.ToString( ));
string tKey = string.Empty;
string tValue = string.Empty;
int tPos = 0;
foreach (string tPart in tParts){
if (tPart == string.Empty){c ontinue;}
tPos = tPart.IndexOf(' :');
if (tPos == -1){
tKey = tPart;
tValue = string.Empty;
}else{
tKey = tPart.Substring (0,tPos);
tValue = tPart.Substring (tPos+1);
System.Reflecti on.PropertyInfo oPI =
_Type.GetProper ty(tKey,Binding Flags.Instance | BindingFlags.Pu blic |
System.Reflecti on.BindingFlags .IgnoreCase);
if (oPI != null){
oPI.SetValue(o, tValue,null);
}
}
}
return System.Convert. ChangeType(o,_T ype);
}
catch (Exception E){
throw new Exception("MERD E!:::" + E.Message );
}
}
return base.ConvertFro m(context, info, value);
}
public override object ConvertTo(IType DescriptorConte xt context, CultureInfo
culture, object value, Type destType) {
//Works in IDE _Type = context.Propert yDescriptor.Pro pertyType;
object o=null;
try {
o = System.Convert. ChangeType(valu e,_Type);
}catch{}
if ((o !=null) && (destType == typeof(string)) ) {
string tResult = string.Empty;
/*
tResult += "a:" + context.Instanc e.GetType().ToS tring() + "|";
tResult += "b:" + context.GetType ().ToString() + "|";
tResult += "c:" + context.Contain er.ToString() + "|";
tResult += "d:" + context.ToStrin g () + "|";
tResult += "e:" + context.Propert yDescriptor.Con verter.ToString () + "|";
tResult += "f:" + context.Propert yDescriptor.Pro pertyType.ToStr ing() + "|";
a:XAct.Web.Cont rols.LoginPanel |
b:System.Window s.Forms.Propert yGridInternal.P ropertyDescript orGridEntry|
c:Microsoft.Vis ualStudio.Desig ner.Host.Design erHost|
d:System.Window s.Forms.Propert yGridInternal.P ropertyDescript orGridEntry
Captions|
e:XAct.Web.Cont rols.StuffConve rter|
f:XAct.Web.Cont rols.LoginPanel +cCaptions
*/
string tDivChar = string.Empty;
PropertyInfo[] oPIs = _Type.GetProper ties();
foreach(Propert yInfo oPI in oPIs){
string tKey = oPI.Name;
try {
object oVal = oPI.GetValue(o, null);
string tValue = string.Empty;
if (oVal != null){
tValue = oVal.ToString() ;
if (tValue != string.Empty){t Result += tDivChar + tKey + ":" + tValue;}
if (tDivChar == string.Empty){t DivChar = ";";}
}
}
catch{}
}
return tResult;
}
return base.ConvertTo( context, culture, value, destType);
}
public override bool
GetStandardValu esSupported(Sys tem.ComponentMo del.ITypeDescri ptorContext
context){
return false;
}
/// <summary>
/// Split function that only splits if not within brackets or quotes.
/// </summary>
/// <param name="qString"> </param>
/// <param name="qDivChar" ></param>
/// <returns></returns>
public static string[] SplitPlus(strin g qString, string qDivChar) {
if (qDivChar== String.Empty){q DivChar = ",";}
ArrayList tResults = new ArrayList();
string tChar="";
string tWord = "";
bool tEscaped=false;
string tLastChar = "";
System.Collecti ons.Stack tQuotes=new System.Collecti ons.Stack();
for (int i=0;i<qString.L ength;i++) {
tChar = qString[i].ToString();
if (tQuotes.Count == 0) {
//We are outside of quotes, so look for quote beginnings...
if ((tChar == "(") ||
(tChar == "{") ||
(tChar == "[") ||
(tChar == "'") ||
(tChar == "\"")) {
tQuotes.Push(tC har);
tLastChar=tChar ;
}
if ((tChar == qDivChar)) {
tResults.Add(tW ord);
tWord="";
tChar = "";
}
}
else {
//We are within quotes...need to look for close chars:
if (tEscaped ==false) {
if (tChar == "\\") {tEscaped=true; }
else {
tLastChar =(string)tQuote s.Peek();
if ((tChar == "\"") && (tChar == tLastChar)) {
tQuotes.Pop();
}
else if ((tChar == "\'") && (tChar == tLastChar)) {
tQuotes.Pop();
}
else if ((tChar == "]") && (tLastChar == "[")) {
tQuotes.Pop();
}
else if ((tChar == "}") && (tLastChar == "{")) {
tQuotes.Pop();
}
if ((tChar == ")") && (tLastChar == "(")) {
tQuotes.Pop();
}
}
}
else {
tEscaped = false;
}
}
tWord = tWord+tChar;
}
if (tWord!= String.Empty) {tResults.Add(t Word);}
return (string[])tResults.ToArr ay(typeof(strin g));
}
}//Class:End
}