Yesterday, we spoke about type converters. We even, built simple generic enum converter. Today, we’ll create more complicated converter, that very missing in Silverlight – ThicknessConverter. During the post, I also explain about tokenizing values in Silverlight
What is Thickness ?
What is thickness in Silverlight? It’s
<Border BorderThickness=”6”/>
or
<Border BorderThickness=”6,4,3,2”/> or <Border BorderThickness=”6, 4, 3,2”/> or, even <Border BorderThickness=”6; 4; 3 ;2”/>
How to handle it?
Tokenizing strings
What you seen here is tokenized strings. We have to split them by known token (one and own for each string) and then we can parse it for converter. How to do this? Complicated – too much cases. But, basically, you have to get string, quote character and separator. Don’t forget to check for empty spaces
private void Initialize(string str, char quoteChar, char separator)
{
this._str = str;
this._strLen = (str == null) ? 0 : str.Length;
this._currentTokenIndex = -1;
this._quoteChar = quoteChar;
this._argSeparator = separator;
while (this._charIndex < this._strLen)
{
if (!char.IsWhiteSpace(this._str, this._charIndex))
{
return;
}
this._charIndex++;
}
}
Then we have to scan string to find tokens
private void ScanToNextToken(char separator)
{
if (this._charIndex < this._strLen)
{
char c = this._str[this._charIndex];
if ((c != separator) && !char.IsWhiteSpace(c))
{
Exceptions.ThrowInvalidOperationException("No Separator Found");
}
int i = 0;
while (this._charIndex < this._strLen)
{
c = this._str[this._charIndex];
if (c == separator)
{
this._foundSeparator = true;
i++;
this._charIndex++;
if (i > 1)
{
Exceptions.ThrowInvalidOperationException("Empty Token Found");
}
}
else
{
if (!char.IsWhiteSpace(c))
{
break;
}
this._charIndex++;
}
}
if ((i > 0) && (this._charIndex >= this._strLen))
{
Exceptions.ThrowInvalidOperationException("Emply Token Found");
}
}
}
why not just split? Because it is not generic solution for strings with empty tokens, which is absolutely invalid. Another reason of using such helper is performance. String operation are not very fast things, thus we’ll check only the number of tokens required for future operations.
Also, we should make sure, that all tokens are required and get rid of unnecessary parts of the string, such as leading spaces, control characters etc. Now, when we have tokenized string, we can start building converter
Building thickness converter
Actually, the most significant part of this converter is tokenization , thus the most important override method for such converter is ConvertFromString
public override object ConvertFromString(string text)
{
Thickness res = new Thickness();
TokenizerHelper helper = new TokenizerHelper(text);
double[] numArray = new double[4];
int index = 0;
while (helper.NextToken())
{
if (index >= 4)
{
index = 5;
break;
}
LengthConverter lc = new LengthConverter();
numArray[index] = (double)lc.ConvertFromString(helper.GetCurrentToken());
index++;
}
switch (index)
{
case 1:
res = new Thickness(numArray[0]); break;
case 2:
res = new Thickness(numArray[0], numArray[1], numArray[0], numArray[1]); break;
case 4:
res = new Thickness(numArray[0], numArray[1], numArray[2], numArray[3]); break;
default:
typeof(Thickness).ThrowConvertFromException(text); break;
}
return res;
}
The only thing to remember is to check whither we can convert from the type received from XAML
public override bool CanConvertFrom(Type sourceType)
{
switch (Type.GetTypeCode(sourceType))
{
case TypeCode.Int16:
case TypeCode.UInt16:
case TypeCode.Int32:
case TypeCode.UInt32:
case TypeCode.Int64:
case TypeCode.UInt64:
case TypeCode.Single:
case TypeCode.Double:
case TypeCode.Decimal:
case TypeCode.String:
return true;
}
return false;
}
Have a nice day and be good people. Stay tuned for future work process items.
No comments:
Post a Comment