A common technique to avoid having to use a ListBox for entering multiple simple strings is to use a multi-line TextBox where each line represents a distinct value.
One unfortunate Silverlight quirk that doesn’t necessarily rear its head until you start doing something like this. Your user dutifully enters text on separate lines and when your code decides to split the input on Environment.NewLine, you only get a single item in the resulting array!
When I encountered this my first thought was that Environment.NewLine must not be what I thought it was. I set a breakpoint to see if it’s was something other than “\r\n”.
Okay, so if Environment.NewLine is what I thought it was, is it possible that when I press Enter on the TextBox, it’s not inserting Environment.NewLine? I didn’t believe it, so I stepped through the debugger. Lo and behold, every time you press Enter in a Silverlight TextBox, only the \r character is entered. Still not believing, I wrote a simple application to test it:
The code is below, but what the application does is on the TextBox TextChanged event, it counts the number of carriage return (‘\r’) and new line (‘\n’) characters. When the Enter key is pressed, only the ‘\r’ count increases. If the Environment.NewLine button is pressed, both the ‘\r’ and ‘\n’ counts increase. Finally, if the normalize button is pressed, a method is called that ensures all new lines are Environment.NewLine (and the counts update to reflect the text change).
Long story short, if you need to accept multi-line input from a TextBox in Silverlight, be sure to normalize the input because when you write code to handle it, it may not be in the format you expect. There is a bug listed on Microsoft Connect that even describes this as an explicit design choice.
To see this in action, here is the XAML source:
1 | <span style="color:#606060" id="lnum1"> 1:</span> <span style="color:#0000ff"><</span><span style="color:#800000">UserControl</span> <span style="color:#ff0000">x:Class</span><span style="color:#0000ff">="SilverlightApplication3.MainPage"</span> |
1 | <span style="color:#606060" id="lnum2"> 2:</span> <span style="color:#ff0000">xmlns</span><span style="color:#0000ff">="http://schemas.microsoft.com/winfx/2006/xaml/presentation"</span> |
1 | <span style="color:#606060" id="lnum3"> 3:</span> <span style="color:#ff0000">xmlns:x</span><span style="color:#0000ff">="http://schemas.microsoft.com/winfx/2006/xaml"</span> |
1 | <span style="color:#606060" id="lnum4"> 4:</span> <span style="color:#ff0000">xmlns:d</span><span style="color:#0000ff">="http://schemas.microsoft.com/expression/blend/2008"</span> |
1 | <span style="color:#606060" id="lnum5"> 5:</span> <span style="color:#ff0000">xmlns:mc</span><span style="color:#0000ff">="http://schemas.openxmlformats.org/markup-compatibility/2006"</span> |
1 | <span style="color:#606060" id="lnum6"> 6:</span> <span style="color:#ff0000">mc:Ignorable</span><span style="color:#0000ff">="d"</span> |
1 | <span style="color:#606060" id="lnum7"> 7:</span> <span style="color:#ff0000">d:DesignHeight</span><span style="color:#0000ff">="300"</span> <span style="color:#ff0000">d:DesignWidth</span><span style="color:#0000ff">="400"</span><span style="color:#0000ff">></span> |
1 | <span style="color:#606060" id="lnum8"> 8:</span> |
1 | <span style="color:#606060" id="lnum9"> 9:</span> <span style="color:#0000ff"><</span><span style="color:#800000">StackPanel</span> <span style="color:#ff0000">Orientation</span><span style="color:#0000ff">="Vertical"</span><span style="color:#0000ff">></span> |
1 | <span style="color:#606060" id="lnum10"> 10:</span> <span style="color:#0000ff"><</span><span style="color:#800000">TextBox</span> <span style="color:#ff0000">x:Name</span><span style="color:#0000ff">="InputTextBox"</span> |
1 | <span style="color:#606060" id="lnum11"> 11:</span> <span style="color:#ff0000">AcceptsReturn</span><span style="color:#0000ff">="True"</span> <span style="color:#ff0000">Height</span><span style="color:#0000ff">="75"</span> |
1 | <span style="color:#606060" id="lnum12"> 12:</span> <span style="color:#ff0000">VerticalScrollBarVisibility</span><span style="color:#0000ff">="Visible"</span> |
1 | <span style="color:#606060" id="lnum13"> 13:</span> <span style="color:#ff0000">TextChanged</span><span style="color:#0000ff">="TextBox_TextChanged"</span><span style="color:#0000ff">></</span><span style="color:#800000">TextBox</span><span style="color:#0000ff">></span> |
1 | <span style="color:#606060" id="lnum14"> 14:</span> <span style="color:#0000ff"><</span><span style="color:#800000">TextBlock</span><span style="color:#0000ff">></span> |
1 | <span style="color:#606060" id="lnum15"> 15:</span> <span style="color:#0000ff"><</span><span style="color:#800000">Run</span> <span style="color:#ff0000">Text</span><span style="color:#0000ff">="There are "</span><span style="color:#0000ff">></</span><span style="color:#800000">Run</span><span style="color:#0000ff">></span> |
1 | <span style="color:#606060" id="lnum16"> 16:</span> <span style="color:#0000ff"><</span><span style="color:#800000">Run</span> <span style="color:#ff0000">x:Name</span><span style="color:#0000ff">="SlashRCount"</span> <span style="color:#ff0000">Text</span><span style="color:#0000ff">="0"</span><span style="color:#0000ff">></</span><span style="color:#800000">Run</span><span style="color:#0000ff">></span> |
1 | <span style="color:#606060" id="lnum17"> 17:</span> <span style="color:#0000ff"><</span><span style="color:#800000">Run</span> <span style="color:#ff0000">Text</span><span style="color:#0000ff">=" \r in the text box"</span><span style="color:#0000ff">></</span><span style="color:#800000">Run</span><span style="color:#0000ff">></span> |
1 | <span style="color:#606060" id="lnum18"> 18:</span> <span style="color:#0000ff"></</span><span style="color:#800000">TextBlock</span><span style="color:#0000ff">></span> |
1 | <span style="color:#606060" id="lnum19"> 19:</span> |
1 | <span style="color:#606060" id="lnum20"> 20:</span> <span style="color:#0000ff"><</span><span style="color:#800000">TextBlock</span><span style="color:#0000ff">></span> |
1 | <span style="color:#606060" id="lnum21"> 21:</span> <span style="color:#0000ff"><</span><span style="color:#800000">Run</span> <span style="color:#ff0000">Text</span><span style="color:#0000ff">="There are "</span><span style="color:#0000ff">></</span><span style="color:#800000">Run</span><span style="color:#0000ff">></span> |
1 | <span style="color:#606060" id="lnum22"> 22:</span> <span style="color:#0000ff"><</span><span style="color:#800000">Run</span> <span style="color:#ff0000">x:Name</span><span style="color:#0000ff">="SlashNCount"</span> <span style="color:#ff0000">Text</span><span style="color:#0000ff">="0"</span><span style="color:#0000ff">></</span><span style="color:#800000">Run</span><span style="color:#0000ff">></span> |
1 | <span style="color:#606060" id="lnum23"> 23:</span> <span style="color:#0000ff"><</span><span style="color:#800000">Run</span> <span style="color:#ff0000">Text</span><span style="color:#0000ff">=" \n in the text box"</span><span style="color:#0000ff">></</span><span style="color:#800000">Run</span><span style="color:#0000ff">></span> |
1 | <span style="color:#606060" id="lnum24"> 24:</span> <span style="color:#0000ff"></</span><span style="color:#800000">TextBlock</span><span style="color:#0000ff">></span> |
1 | <span style="color:#606060" id="lnum25"> 25:</span> |
1 | <span style="color:#606060" id="lnum26"> 26:</span> <span style="color:#0000ff"><</span><span style="color:#800000">Button</span> <span style="color:#ff0000">Content</span><span style="color:#0000ff">="Add Environment.NewLine"</span> <span style="color:#ff0000">Click</span><span style="color:#0000ff">="Button_Click"</span><span style="color:#0000ff">></</span><span style="color:#800000">Button</span><span style="color:#0000ff">></span> |
1 | <span style="color:#606060" id="lnum27"> 27:</span> <span style="color:#0000ff"><</span><span style="color:#800000">Button</span> <span style="color:#ff0000">Content</span><span style="color:#0000ff">="Normalize New Lines"</span> <span style="color:#ff0000">Click</span><span style="color:#0000ff">="Button_Click_1"</span><span style="color:#0000ff">></</span><span style="color:#800000">Button</span><span style="color:#0000ff">></span> |
1 | <span style="color:#606060" id="lnum28"> 28:</span> <span style="color:#0000ff"></</span><span style="color:#800000">StackPanel</span><span style="color:#0000ff">></span> |
1 | <span style="color:#606060" id="lnum29"> 29:</span> <span style="color:#0000ff"></</span><span style="color:#800000">UserControl</span><span style="color:#0000ff">></span> |
And the XAML codebehind:
1 | <span style="color:#606060" id="lnum1"> 1:</span> <span style="color:#0000ff">using</span> System; |
1 | <span style="color:#606060" id="lnum2"> 2:</span> <span style="color:#0000ff">using</span> System.Windows; |
1 | <span style="color:#606060" id="lnum3"> 3:</span> <span style="color:#0000ff">using</span> System.Windows.Controls; |
1 | <span style="color:#606060" id="lnum4"> 4:</span> |
1 | <span style="color:#606060" id="lnum5"> 5:</span> <span style="color:#0000ff">namespace</span> SilverlightApplication3 { |
1 | <span style="color:#606060" id="lnum6"> 6:</span> <span style="color:#0000ff">public</span> <span style="color:#0000ff">partial</span> <span style="color:#0000ff">class</span> MainPage : UserControl { |
1 | <span style="color:#606060" id="lnum7"> 7:</span> <span style="color:#0000ff">public</span> MainPage() { |
1 | <span style="color:#606060" id="lnum8"> 8:</span> InitializeComponent(); |
1 | <span style="color:#606060" id="lnum9"> 9:</span> } |
1 | <span style="color:#606060" id="lnum10"> 10:</span> |
1 | <span style="color:#606060" id="lnum11"> 11:</span> <span style="color:#0000ff">private</span> <span style="color:#0000ff">void</span> TextBox_TextChanged( <span style="color:#0000ff">object</span> sender, TextChangedEventArgs e ) { |
1 | <span style="color:#606060" id="lnum12"> 12:</span> <span style="color:#0000ff">int</span> slashRCount = <span style="color:#0000ff">this</span>.InputTextBox.Text.CountOf( <span style="color:#006080">'\r'</span> ); |
1 | <span style="color:#606060" id="lnum13"> 13:</span> <span style="color:#0000ff">int</span> slashNCount = <span style="color:#0000ff">this</span>.InputTextBox.Text.CountOf( <span style="color:#006080">'\n'</span> ); |
1 | <span style="color:#606060" id="lnum14"> 14:</span> |
1 | <span style="color:#606060" id="lnum15"> 15:</span> <span style="color:#0000ff">this</span>.SlashRCount.Text = slashRCount.ToString(); |
1 | <span style="color:#606060" id="lnum16"> 16:</span> <span style="color:#0000ff">this</span>.SlashNCount.Text = slashNCount.ToString(); |
1 | <span style="color:#606060" id="lnum17"> 17:</span> } |
1 | <span style="color:#606060" id="lnum18"> 18:</span> |
1 | <span style="color:#606060" id="lnum19"> 19:</span> <span style="color:#0000ff">private</span> <span style="color:#0000ff">void</span> Button_Click( <span style="color:#0000ff">object</span> sender, RoutedEventArgs e ) { |
1 | <span style="color:#606060" id="lnum20"> 20:</span> <span style="color:#0000ff">this</span>.InputTextBox.Text += Environment.NewLine; |
1 | <span style="color:#606060" id="lnum21"> 21:</span> } |
1 | <span style="color:#606060" id="lnum22"> 22:</span> |
1 | <span style="color:#606060" id="lnum23"> 23:</span> <span style="color:#0000ff">private</span> <span style="color:#0000ff">void</span> Button_Click_1( <span style="color:#0000ff">object</span> sender, RoutedEventArgs e ) { |
1 | <span style="color:#606060" id="lnum24"> 24:</span> <span style="color:#0000ff">this</span>.InputTextBox.Text = <span style="color:#0000ff">this</span>.InputTextBox.Text.NormalizeNewLines(); |
1 | <span style="color:#606060" id="lnum25"> 25:</span> } |
1 | <span style="color:#606060" id="lnum26"> 26:</span> } |
1 | <span style="color:#606060" id="lnum27"> 27:</span> } |
And the helper extension functions:
1 | <span style="color:#606060" id="lnum1"> 1:</span> <span style="color:#0000ff">using</span> System; |
1 | <span style="color:#606060" id="lnum2"> 2:</span> <span style="color:#0000ff">using</span> System.Text.RegularExpressions; |
1 | <span style="color:#606060" id="lnum3"> 3:</span> |
1 | <span style="color:#606060" id="lnum4"> 4:</span> <span style="color:#0000ff">namespace</span> SilverlightApplication3 { |
1 | <span style="color:#606060" id="lnum5"> 5:</span> <span style="color:#0000ff">public</span> <span style="color:#0000ff">static</span> <span style="color:#0000ff">class</span> StringExtensions { |
1 | <span style="color:#606060" id="lnum6"> 6:</span> <span style="color:#0000ff">public</span> <span style="color:#0000ff">static</span> <span style="color:#0000ff">string</span> NormalizeNewLines( <span style="color:#0000ff">this</span> <span style="color:#0000ff">string</span> <span style="color:#0000ff">value</span> ) { |
1 | <span style="color:#606060" id="lnum7"> 7:</span> <span style="color:#008000">// From: </span> |
1 | <span style="color:#606060" id="lnum8"> 8:</span> <span style="color:#008000">// http://stackoverflow.com/questions/3022571/how-to-deal-with-the-new-line-character-in-the-silverlight-textbox</span> |
1 | <span style="color:#606060" id="lnum9"> 9:</span> <span style="color:#0000ff">if</span>( <span style="color:#0000ff">value</span> == <span style="color:#0000ff">null</span> ) <span style="color:#0000ff">return</span> <span style="color:#0000ff">value</span>; |
1 | <span style="color:#606060" id="lnum10"> 10:</span> |
1 | <span style="color:#606060" id="lnum11"> 11:</span> <span style="color:#0000ff">return</span> Regex.Replace( <span style="color:#0000ff">value</span>, <span style="color:#006080">@"\r(?!\n)|(?<!\r)\n"</span>, Environment.NewLine ); |
1 | <span style="color:#606060" id="lnum12"> 12:</span> } |
1 | <span style="color:#606060" id="lnum13"> 13:</span> |
1 | <span style="color:#606060" id="lnum14"> 14:</span> <span style="color:#0000ff">public</span> <span style="color:#0000ff">static</span> <span style="color:#0000ff">int</span> CountOf( <span style="color:#0000ff">this</span> <span style="color:#0000ff">string</span> <span style="color:#0000ff">value</span>, <span style="color:#0000ff">char</span> c ) { |
1 | <span style="color:#606060" id="lnum15"> 15:</span> <span style="color:#0000ff">if</span>( <span style="color:#0000ff">value</span> == <span style="color:#0000ff">null</span> ) <span style="color:#0000ff">return</span> 0; |
1 | <span style="color:#606060" id="lnum16"> 16:</span> |
1 | <span style="color:#606060" id="lnum17"> 17:</span> <span style="color:#0000ff">int</span> count = 0; |
1 | <span style="color:#606060" id="lnum18"> 18:</span> <span style="color:#0000ff">for</span>( <span style="color:#0000ff">int</span> i = 0; i < <span style="color:#0000ff">value</span>.Length; i++ ) { |
1 | <span style="color:#606060" id="lnum19"> 19:</span> <span style="color:#0000ff">if</span>( <span style="color:#0000ff">value</span>[i] == c ) |
1 | <span style="color:#606060" id="lnum20"> 20:</span> count++; |
1 | <span style="color:#606060" id="lnum21"> 21:</span> } |
1 | <span style="color:#606060" id="lnum22"> 22:</span> <span style="color:#0000ff">return</span> count; |
1 | <span style="color:#606060" id="lnum23"> 23:</span> } |
1 | <span style="color:#606060" id="lnum24"> 24:</span> } |
1 | <span style="color:#606060" id="lnum25"> 25:</span> } |