How can I dynamically replace portions of text with TextBoxes?
TL;DR:
I need to insert a TextBox into a PlaceHolder wherever I see a token like @token@
, and splitting on @
won't cut it. How can I do this?
Setup:
I have a data开发者_如何学编程base-driven ASP.NET page with merge fields in several places. On one of the admin pages, I want to make the text in the merge fields editable by showing TextBoxes where the merge fields are. The rest of the text needs to stay non-editable.
The input looks like this:
"the quick brown fox @foo@ jumps over @bar@ the lazy @baz@ dog."
The merge fields here would be foo
, bar
, and baz
. I have a Dictionary<string, string>
with the value of the merge fields:
var Tokens = new Dictionary<string, string>
{
{ "foo", "john" },
{ "bar", "george" },
//...etc...
};
Goal:
For each of these text blocks, I have a PlaceHolder. What I'd like to do is dynamically insert a Label for each block of uneditable text, and a TextBox for each editable block. So the results of the above would be as if I had hard-coded something like this:
<asp:Label Text="the quick brown fox" />
<asp:TextBox ID="foo" Text="john" />
<asp:Label Text="jumps over" />
<asp:TextBox ID="bar" Text="george" />
<asp:Label Text="the lazy" />
...etc...
Problem:
Matching the @token@
pattern is easy. The trick is adding the Labels and TextBoxes in the right places. There might be more than one token in a given input, so I have to separate it out into editable and non-editable text, while still keeping track of which merge variable each TextBox corresponds to. As it turns out, this is not as easy as it sounds. I could use regular expressions to convert the input string into HTML, replacing the @token@
pattern with <input>
tags. However, that has a couple of problems:
- I already have a ton of code for the dynamic-server-controls approach.
- I only want to match specific tokens, so
/@[a-zA-Z\d]+@/
isn't strict enough.
Previous Strategy:
Until now, I simply split the input string on @
, then inserted a Label for each odd-numbered substring and a TextBox for each even substring. That worked fine, but the requirements are changing. @
symbols will now be allowed outside of a variable name, so the input string might look like:
blah blah@blah.com @foo@ blah
...in which case only foo
would be a merge field.
Current Strategy:
I feel like I need to iterate through Tokens and build some sort of array of Labels and TextBoxes. The problem is that any number of tokens might be in the input, so once I split out TextBoxes for @foo@
, I need to go through the text again for instances of @bar@
. I think I need some sort of recursion for this, but I can't quite put my finger on it.
you can do it with Regular expressions. The Expression would look something like:
@([a-zA-Z0-9])+@
this would mean that it matches for all patterns which start with @, contain at least one character a-z or A-Z or 0-9 and end with @
Regex.Match
Before fantasticfix's answer was posted, I started working on a recursive method using string manipulation. It seems to be working correctly, so I'm posting it here for anyone else:
private void tokenize(PlaceHolder ph, string str)
{
int index = str.IndexOf('@') + 1;
if (index == 0)
{
ph.Controls.Add(new Label { Text = str });
return;
}
ph.Controls.Add(new Label { Text = str.Substring(0, index - 1) });
if (Tokens.Keys.Any(k => str.Substring(index).StartsWith(k + "@")))
{
int next = str.IndexOf("@", index);
string key = str.Substring(index, next - index);
ph.Controls.Add(new TextBox
{
ID = "txt" + key,
Text = Tokens[key],
TextMode = TextBoxMode.MultiLine,
Rows = 2
});
index = next + 1;
}
tokenize(ph, str.Substring(index));
}
精彩评论