Extending LightSwitch TextBox : Walk-Through
***** WISH YOU A HAPPY NEW YEAR *****

In this post, we’ll create a simple, LightSwitch ‘Character Casing” TextBox. This extension will allow us to set following ‘case’
- Normal
- Upper Case
- Lower Case
- Proper Case
- Title Case
- Sentence Case
For this walk-through we are creating a “VALUE” control. So you have to follow this MSDN article to create your start-up project. You also will follow several steps from the same article. Keep that tab open.
Steps:
01. Create a LS Extensible project. Follow the above article. Name your project as “XTextBoxExtension“. And name your control as “XTextBoxControl“.
02. Update the Control Icon. Follow the article
03. Specify Supported Data Types. Our control needs to support just “STRING” property. So just update this line in your LSML file.
<Control.SupportedDataTypes>
<SupportedDataType DataType=":String" />
</Control.SupportedDataTypes>
04. Bind to LightSwitch Data.
05. Allow User Code to Access the Control
06. Add Read-Only Support. Follow the article.
07. Alright. We done following that article. Now we need to create a “CharacterCasing” Property. Go back to your XTextBoxControl.LSML file and add this. This section creates a CharacterCasing property, its ENUM values and also a default value. LightSwitch will automatically create a DropDown list with below values.
<Control.Properties>
<ControlProperty
Name="CharacterCasing"
PropertyType=":String"
CategoryName="Appearance"
EditorVisibility="PropertySheet">
<ControlProperty.Attributes>
<DisplayName Value="Character Casing" />
<Description Value="Character Casing" />
<SupportedValuesExclusive />
<SupportedValue DisplayName="Normal" Value="Normal"/>
<SupportedValue DisplayName="Upper Case" Value="Upper"/>
<SupportedValue DisplayName="Lower Case" Value="Lower"/>
<SupportedValue DisplayName="Proper Case" Value="ProperCase"/>
<SupportedValue DisplayName="Title Case" Value="TitleCase"/>
<SupportedValue DisplayName="Sentence Case" Value="SentenceCase"/>
</ControlProperty.Attributes>
<ControlProperty.DefaultValueSource>
<ScreenExpressionTree>
<ConstantExpression ResultType=":String" Value="Normal"/>
</ScreenExpressionTree>
</ControlProperty.DefaultValueSource>
</ControlProperty>
</Control.Properties>
When we deal with String Formats, such as “Proper Case”, “Title Case”, or “Sentence Case”, we don’t have proper rules to follow. Each one of our requirements might be unique. So for a greater flexibility, lets add three more Control Properties.
WordSeperators : We supply a series of “chars” as a one single string (no comma delimiters) to determine what might be our word separators.
SentenceSeperators : Same as above, but this time we declare it for sentences with “Comma Delimited Values.
ExceptionWords : This is for Title Case Property. Title Cases are different from Proper Cases. For example,
- Title Case : This is a Sample Title Case.
- Proper Case : This Is A Sample Proper Case
On the above, “is” & “a” need to still maintain their lower case, when it comes to Title Case. The list might vary for what you need. With ExceptionWords property, we can build our own Exception Dictionary, of course with Comma Delimiters. Here is the xaml code those three properties. Just add them under “Dictionary” property. These properties also declared few default values.
<ControlProperty
Name="WordBreakers"
PropertyType=":String"
CategoryName="Appearance"
EditorVisibility="PropertySheet">
<ControlProperty.Attributes>
<DisplayName Value="Word Breakers List" />
<Description Value="Word Breakers List" />
</ControlProperty.Attributes>
<ControlProperty.DefaultValueSource>
<ScreenExpressionTree>
<ConstantExpression ResultType=":String" Value=" .!?"/>
</ScreenExpressionTree>
</ControlProperty.DefaultValueSource>
</ControlProperty>
<ControlProperty
Name="SentenceBreakers"
PropertyType=":String"
CategoryName="Appearance"
EditorVisibility="PropertySheet">
<ControlProperty.Attributes>
<DisplayName Value="Sentence Breakers List (Use Comma)" />
<Description Value="Sentence Breakers List (Use Comma)" />
</ControlProperty.Attributes>
<ControlProperty.DefaultValueSource>
<ScreenExpressionTree>
<ConstantExpression ResultType=":String" Value=" ,. ,! ,? "/>
</ScreenExpressionTree>
</ControlProperty.DefaultValueSource>
</ControlProperty>
<ControlProperty
Name="ExceptionWords"
PropertyType=":String"
CategoryName="Appearance"
EditorVisibility="PropertySheet">
<ControlProperty.Attributes>
<DisplayName Value="Exception Words (Use Comma)" />
<Description Value="Exception Words (Use Comma)" />
</ControlProperty.Attributes>
<ControlProperty.DefaultValueSource>
<ScreenExpressionTree>
<ConstantExpression ResultType=":String" Value="a,is,was,are,were,been"/>
</ScreenExpressionTree>
</ControlProperty.DefaultValueSource>
</ControlProperty>
08. Almost done. Now go to your XTextBoxControl.xaml file. Select the textbox and wire-up its “TextChanged” event. Your updated XAML should be like this now.
<framework:StatesControl HorizontalAlignment="Stretch">
<TextBox x:Name="TextBox"
Text="{Binding StringValue, Mode=TwoWay}"
IsReadOnly="{Binding IsReadOnly}"
TextAlignment="{Binding Properties[Microsoft.LightSwitch:RootControl/TextAlignment]}"
HorizontalAlignment="Stretch"
ToolTipService.ToolTip="{Binding Description}"
TextChanged="TextBox_TextChanged" >
</TextBox>
</framework:StatesControl>
09. Now Right Click on the “TextBox_TextChanged” text, and click “Navigate to Event Handler“. That’ll open the Code Behind file. Update the “TextBox_TextChanged” event with below code.
private void TextBox_TextChanged(object sender, TextChangedEventArgs e)
{
OnTextChanged();
}
private void OnTextChanged()
{
TextBox _textBox = this.TextBox;
int selectionStart = _textBox.SelectionStart;
if (this.CharacterCasing == "Upper")
_textBox.Text = CultureInfo.CurrentCulture.TextInfo.ToUpper(_textBox.Text);
else if (this.CharacterCasing == "Lower")
_textBox.Text = CultureInfo.CurrentCulture.TextInfo.ToLower(_textBox.Text);
else if (this.CharacterCasing == "ProperCase")
_textBox.Text = ProperCase(_textBox.Text);
else if (this.CharacterCasing == "TitleCase")
_textBox.Text = TitleCase(_textBox.Text);
else if (this.CharacterCasing == "SentenceCase")
_textBox.Text = SentenceCase(_textBox.Text);
_textBox.SelectionStart = selectionStart;
}
10. We’ll use ToUpper & ToLower inbuilt functions, but we need to create the other methods. Remember, none of these below methods will satisfy 100% of your desire and far from perfect. So you need to work on the code to make it perfect for ur needs.
#region Character Case Helpers
public string ProperCase(string txt)
{
string properCaseStr = String.Empty;
bool isCaps = true;
foreach (char c in txt.ToCharArray())
{
properCaseStr += isCaps ? c.ToString().ToUpper() : c.ToString();
isCaps = this.WordBreakers.Contains(c.ToString());
}
return properCaseStr;
}
public string TitleCase(string txt)
{
txt = ProperCase(txt);
string titleCaseStr = String.Empty;
foreach (string sentenceBreaker in this.SentenceBreakers.Split(','))
{
foreach (string titleCaseException in this.ExceptionWords.Split(','))
{
string findWord = String.Empty;
//SPACE is not a Sentence Breaker. So change the Non Noun word to lowercase
if (sentenceBreaker == " ")
{
findWord = sentenceBreaker + ProperCase(titleCaseException);
txt = txt.Replace(findWord, sentenceBreaker + titleCaseException.ToLower());
}
else
{
findWord = sentenceBreaker + titleCaseException.ToLower();
txt = txt.Replace(findWord, sentenceBreaker + ProperCase(titleCaseException));
}
}
}
return txt;
}
public string SentenceCase(string txt)
{
string sentenceCaseStr = String.Empty;
bool isCaps = true;
char prevChar = char.MinValue;
foreach (char c in txt.ToCharArray())
{
sentenceCaseStr += isCaps ? c.ToString().ToUpper() : c.ToString();
isCaps = (c == ' ' && this.WordBreakers.Contains(prevChar));
prevChar = c;
}
return sentenceCaseStr;
}
#endregion
11. Now we need to create a Local Properties and register them to listen if there is any change on appropriate properties.
#region Properties
public string CharacterCasing
{
get { return (string)GetValue(CharacterCasingProperty); }
set { SetValue(CharacterCasingProperty, value); }
}
public string WordBreakers
{
get { return (string)GetValue(WordBreakersProperty); }
set { SetValue(WordBreakersProperty, value); }
}
public string SentenceBreakers
{
get { return (string)GetValue(SentenceBreakersProperty); }
set { SetValue(SentenceBreakersProperty, value); }
}
public string ExceptionWords
{
get { return (string)GetValue(ExceptionWordsProperty); }
set { SetValue(ExceptionWordsProperty, value); }
}
#endregion
#region Dependency Properties
public static readonly DependencyProperty CharacterCasingProperty =
DependencyProperty.Register("CharacterCasingProperty",
typeof(string), typeof(XTextBoxControl),
new PropertyMetadata(OnCharacterCasingPropertyChanged));
public static readonly DependencyProperty WordBreakersProperty =
DependencyProperty.Register("WordBreakersProperty",
typeof(string), typeof(XTextBoxControl),
new PropertyMetadata(OnWordBreakersPropertyChanged));
public static readonly DependencyProperty SentenceBreakersProperty =
DependencyProperty.Register("SentenceBreakersProperty",
typeof(string), typeof(XTextBoxControl),
new PropertyMetadata(OnSentenceBreakersPropertyChanged));
public static readonly DependencyProperty ExceptionWordsProperty =
DependencyProperty.Register("ExceptionWordsProperty",
typeof(string), typeof(XTextBoxControl),
new PropertyMetadata(OnExceptionWordsPropertyChanged));
#endregion
#region Metadata
private static void OnCharacterCasingPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
//Do what you want
}
private static void OnWordBreakersPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
//Do what you want
}
private static void OnSentenceBreakersPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
//Do what you want
}
private static void OnExceptionWordsPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
//Do what you want
}
#endregion
12. And finally, bind the Dependency property from the control’s constructor.
public XTextBoxControl()
{
InitializeComponent();
this.SetBinding(CharacterCasingProperty, new Binding("Properties[XTextBoxExtension:XTextBoxControl/CharacterCasing]"));
this.SetBinding(WordBreakersProperty, new Binding("Properties[XTextBoxExtension:XTextBoxControl/WordBreakers]"));
this.SetBinding(SentenceBreakersProperty, new Binding("Properties[XTextBoxExtension:XTextBoxControl/SentenceBreakers]"));
this.SetBinding(ExceptionWordsProperty, new Binding("Properties[XTextBoxExtension:XTextBoxControl/ExceptionWords]"));
}
THATS IT!!!!!!!! Now test your control.

This is great. Thanks a bunch!
Thanks Paul.
Verry good !
I was just looking for some example to teach me how to set my own stuff for a control.
great stuff Bala! keep rockin!