Multiline textbox - spaces added to beginning on postback - c#

I have a Textbox added to an .ascx control page as follows:
<asp:TextBox id="txtDescription" runat="server" Width="500" TextMode="MultiLine" Rows="2"></asp:TextBox>
And it would show something like this when first loaded (4 spaces at the start included):
Description goes here
Put simply, it's a Multiline Textbox with 2 lines. However, whenever we do a Postback to the server, when the page reloads, we get this:
Description goes here
Another Postback.
Description goes here
And so on. Basically, every time the page is refreshed after a Postback, it adds 4 spaces to the start of the textbox. On some pages, this isn't an issue, however, if the user is entering a fair bit of data into a Gridview or some other Control, the contents of the Textbox can end up shunted 20 or so characters to the right, sometimes out of the bounds of the Textbox.
Put simply, this is an issue for our company, as it is occurring across all of our pages. One of our clients has several times made a pass "...and could you do something about the spaces at the beginning of the textboxes at some point?"
Now, a temporary fix we have employed is the following code in our PageLoad function, however, we are still left with 4 spaces at the beginning of the Textbox. And rolling it out across 100's of .ascx and .aspx controls/pages isn't really a solution.
if (IsPostBack)
txtDescription.Text = txtDescription.Text;
Now the big question is, does anyone know how to remove these mysterious 4 spaces that keep getting added to the start of a Multiline Textbox?

A typical html textarea (multiline textbox) looks like this:
<textarea>This is some content</textarea>
Now if your output looks like:
<textarea>
This is some content
</textarea>
Then you will introduce your space issue.
When you save this content you gain the 4 spaces at the beginning (the indentation). Now you load those 4 spaces back and suddenly you have 8 spaces: 4 from the markup and 4 from the saved content. This pattern continues each time you save the content.
I am unfamiliar with how you (ASP Web Forms) are generating your content, but this should give you a point of investigation.

I encounter this problem too. May be mono asp.net bug.
This is my found way,
build a custom server control to replace multiline textbox.
It's work with asp.net integrated validation framework.
Somebody have better idea?
[ValidationProperty("Text")]
[ControlValueProperty("Text")]
[DefaultProperty("Text")]
public class TextArea: WebControl, IPostBackDataHandler, IEditableTextControl
{
protected override HtmlTextWriterTag TagKey
{
get { return HtmlTextWriterTag.Textarea; }
}
public bool CausesValidation
{
get
{
if (ViewState["CausesValidation"] == null)
return false;
return (bool)ViewState["CausesValidation"];
}
set
{
ViewState["CausesValidation"] = value;
}
}
public string ValidationGroup
{
get
{
return (string)ViewState["ValidationGroup"] ?? "";
}
set
{
ViewState["ValidationGroup"] = value;
}
}
public string Text
{
get
{
return (string)ViewState["Text"] ?? "";
}
set
{
ViewState["Text"] = value;
}
}
public bool ReadOnly
{
get
{
if (ViewState["Readonly"] == null)
return false;
return (bool)ViewState["Readonly"];
}
set
{
ViewState["Readonly"] = value;
}
}
public int Rows
{
get
{
if (ViewState["Rows"] == null)
return 0;
return (int)ViewState["Rows"];
}
set
{
ViewState["Rows"] = value;
}
}
public int Columns
{
get
{
if (ViewState["Columns"] == null)
return 0;
return (int)ViewState["Columns"];
}
set
{
ViewState["Columns"] = value;
}
}
protected override void AddAttributesToRender(HtmlTextWriter writer)
{
writer.AddAttribute(HtmlTextWriterAttribute.Name, UniqueID);
if (Enabled && !IsEnabled)
writer.AddAttribute(HtmlTextWriterAttribute.Disabled, "disabled");
if (ReadOnly)
writer.AddAttribute(HtmlTextWriterAttribute.ReadOnly, "readonly");
if (Rows != 0)
writer.AddAttribute(HtmlTextWriterAttribute.Rows, Rows.ToString(NumberFormatInfo.InvariantInfo));
if (Columns != 0)
writer.AddAttribute(HtmlTextWriterAttribute.Cols, Columns.ToString(NumberFormatInfo.InvariantInfo));
base.AddAttributesToRender(writer);
}
public override void RenderControl(HtmlTextWriter writer)
{
RenderBeginTag(writer);
writer.WriteEncodedText(Text);
RenderEndTag(writer);
}
public bool LoadPostData(string postDataKey, NameValueCollection postCollection)
{
var strPostBack = postCollection[postDataKey];
if (ReadOnly || Text.Equals(strPostBack, StringComparison.Ordinal))
return false;
Text = strPostBack;
return true;
}
public void RaisePostDataChangedEvent()
{
if (!Page.IsPostBackEventControlRegistered)
{
Page.AutoPostBackControl = this;
if (CausesValidation)
Page.Validate(ValidationGroup);
}
TextChanged(this, EventArgs.Empty);
}
public event EventHandler TextChanged = delegate { };
}

I also had same issue. To remove extra spaces use textbox_TextChanged event and bind it to textbox.
protected void txtDescription_TextChanged(object sender, EventArgs e)
{
String strReplace = Regex.Replace(txtDescription.Text.Trim(),#"\t|\n|\r","");
txtDescription.Text = strReplace;
}
Bind TextChanged event to textbox:
<asp:TextBox id="txtDescription" runat="server" Width="500" TextMode="MultiLine" Rows="2" OnTextChanged="txtDescription_TextChanged"></asp:TextBox>
Note: It won't remove the first space, but will work with subsequent spaces of postback.

Your only option is to breakpoint the code and see where they are appearing from.

Related

Prevent saving an invalid field value in Sitecore

I have a custom validator class, which checks the following:
The value of the text field should have a length 5 characters.
The
first 2 chars. should be numbers.
The last 3 chars. should be
alphabets.
When setting the Standard Value of the template (eg: 12a), the indicator shows Red and the appropriate message. But after pressing Ctrl + S, it shows a dialog asking to save even when there is an error. After clicking OK, there is a similar dialog. Clicking on OK, saves 12a as the standard value for the field. When I refresh the content editor the value is 12a.
Is this normal Sitecore behavior. I'm expecting that the value shouldn't be saved at all, if it is invalid.
namespace CustomValidators
{
[Serializable]
public class testValidator : StandardValidator
{
private readonly Regex numbersRegex = new Regex(#"^\d+$");
private readonly Regex lettersRegexnew = new Regex(#"^[A-Za-z]+$");
protected override ValidatorResult Evaluate()
{
string value = base.GetControlValidationValue();
if (!string.IsNullOrEmpty(value) && value.Length == 5)
{
string firstPart = value.Substring(0, 2);
string secondPart = value.Substring(3, 3);
if (numbersRegex.IsMatch(firstPart) && lettersRegexnew.IsMatch(secondPart))
{
return ValidatorResult.Valid;
}
}
base.Text = "invalid value";
return base.GetFailedResult(ValidatorResult.FatalError);
}
protected override ValidatorResult GetMaxValidatorResult()
{
return base.GetFailedResult(ValidatorResult.FatalError);
}
public override string Name
{
get { return "testValidator"; }
}
}
}
Only people in certain roles, even get the option of forcing a save. Admins and I think people in the "Sitecore Developer" role.
As such, you are given the option of forcing a save through. This is normal behaviour.
Your regular editor users would not be able to save.

Visual Studio Extension : Changing the visible text of collapsed blocks

I'm writing a Visual Studio Extension to customize my editor. I would like to change the text that is displayed when a block of code is collapsed.
I have tried the following code :
ITagAggregator<IntraTextAdornmentTag> aggregator;
[...]
aggregator.BatchedTagsChanged += OnBatchedTagsChanged;
[...]
public void OnBatchedTagsChanged(object sender, BatchedTagsChangedEventArgs e)
{
string newText;
bool textCreated;
NormalizedSnapshotSpanCollection list = new NormalizedSnapshotSpanCollection(e.Spans.SelectMany(x => x.GetSpans(textView.TextBuffer)));
if (list.Count != 0)
{
IEnumerable<IMappingTagSpan<IntraTextAdornmentTag>> tags = aggregator.GetTags(list);
foreach (IMappingTagSpan<IntraTextAdornmentTag> tag in tags)
{
if (tag.Tag.Adornment is OutliningCollapsedAdornmentControl)
{
NormalizedSnapshotSpanCollection spans = tag.Span.GetSpans(textView.TextSnapshot);
if (spans.Count == 0) continue;
OutliningCollapsedAdornmentControl adornmentControl = (OutliningCollapsedAdornmentControl)tag.Tag.Adornment;
TextBlock textBlock = adornmentControl.GetChild<TextBlock>();
textCreated = TryCreateText(spans[0], out newText);
if (textCreated)
{
adornmentControl.Content = newText;
textBlock.Text = newText;
}
}
}
}
}
I does change the text, but when it's scrolled out of the the screen and back in, the text reverts back to the default value.
Edit :
I also tried MSDN's walkthrough.
I works fine if I collapse blocks by clicking on the "+" sign, but the blocks don't collapse when I use Ctrl+M+O.
I guess the problem comes from the fact that I'm creating regions that already exist.
Could someone please tell me what I could do?
(Tested both in VS2010 and VS2013 with the same result)

Cannot find instance of dynamically added UserControl .Net

I have a UserControl which I am loading into a div which is inside an UpdatePanel. Here is my code for loading it:
controls.IDLControl IdlControl = LoadControl(#"~/controls/IDLControl.ascx") as controls.IDLControl;
IdlControl.ClientIDMode = ClientIDMode.Static;
IdlControl.ID = "IDLControl";
spGroup.Controls.Clear();
spGroup.Controls.Add(IdlControl);
And here is my code for trying to retrieve an instance of it:
controls.IDLControl IdlControl = RecursiveFindControl(this, "IDLControl") as controls.IDLControl;
private Control RecursiveFindControl(Control targetControl, string findControlId) {
if (targetControl.HasControls()) {
foreach (Control childControl in targetControl.Controls) {
if (childControl.ID == findControlId) {
return childControl;
}
RecursiveFindControl(childControl, findControlId);
}
}
return null;
}
But, all I get is null. I need help on figuring this out.
AFAIK, I need to re-add the control to the page on pre-init but it is one of the controls that can be added depending on which option is selected from a drop down list (which also is filled dynamically). I am stuck trying to figure out how to make this work.
You can try something like this to add your control back in the Page_Init based on the option selected in your DropDownList.
protected void Page_Init(Object sender, EventArgs e)
{
if (IsPostBack)
{
if (drpYourDropDown.Items.Count > 0 && drpYourDropDown.SelectedItem.Text == "yourOption")
{
AddIDLControl();
}
}
}
private void AddIDLControl()
{
controls.IDLControl IdlControl = LoadControl(#"~/controls/IDLControl.ascx") as controls.IDLControl;
IdlControl.ClientIDMode = ClientIDMode.Static;
IdlControl.ID = "IDLControl";
spGroup.Controls.Clear();
spGroup.Controls.Add(IdlControl);
}

Why can't I leave a TextBox using tab?

I have this code:
public static void AddDefaultTextFromTag(params TextBox[] textBoxes)
{
foreach (TextBox oTextBox in textBoxes)
{
bool isPasswordChar = oTextBox.UseSystemPasswordChar;
oTextBox.Enter += (sndr, evnt) =>
{
if (((TextBox)sndr).Text == ((TextBox)sndr).Tag.ToString())
{
((TextBox)sndr).Text = "";
((TextBox)sndr).UseSystemPasswordChar = isPasswordChar;
((TextBox)sndr).ForeColor = SystemColors.WindowText;
}
};
oTextBox.Leave += (sndr, evnt) =>
{
if (((TextBox)sndr).Text.Trim().Count() == 0)
{
((TextBox)sndr).UseSystemPasswordChar = false;
((TextBox)sndr).CharacterCasing = CharacterCasing.Normal;
((TextBox)sndr).Text = ((TextBox)sndr).Tag.ToString();
((TextBox)sndr).ForeColor = SystemColors.GrayText;
}
};
if (oTextBox.Text.Trim().Count() == 0)
{
oTextBox.UseSystemPasswordChar = false;
oTextBox.CharacterCasing = CharacterCasing.Normal;
oTextBox.Text = oTextBox.Tag.ToString();
oTextBox.ForeColor = SystemColors.GrayText;
}
}
}
But when the TextBox.UseSystemPasswordChar I input in this method's parameter is true and it's TextBox.Text property is empty, the TextBox can't leave using a Tab button on the keyboard, only a MouseClick can be used to lose the focus of that TextBox.
Why is this happening?
My code is in C#, framework 4, build in VS2010 Pro, project is in WinForms.
I use a TextBox from the VS ToolBox.
Please help. Thanks in advance.
The reason you can't leave the textbox is because you are changing the CharacterCasing property in the textbox.
Not sure why it works like this, but it has happened to me before, what I ended up doing was capture the keypress event, and if it was a letter I'd switch it to it's uppercase value. It's not optimal, but it works
I did something similar to this (writing it from the top of my head, but it should work):
void YourTextbox_KeyPress(object sender, KeyPressEventArgs e)
{
if (char.IsLetter(e.KeyChar))
{
if (this.CharacterCasing == CharacterCasing.Upper && char.IsLower(e.KeyChar))
{
this.Text = this.Text.Insert(this.SelectionStart, char.ToUpper(e.KeyChar) + string.Empty);
this.SelectionStart++;
e.Handled = true;
}
else if (this.CharacterCasing == System.Windows.Forms.CharacterCasing.Lower && char.IsUpper(e.KeyChar))
{
this.Text = this.Text.Insert(this.SelectionStart, char.ToLower(e.KeyChar) + string.Empty);
this.SelectionStart++;
e.Handled = true;
}
}
}
You also should use the new keyword to "override" (I know that's not the right term here) the Character casing, so it doesn't do it's own thing
public new CharacterCasing CharacterCasing { get; set; }
The code basically checks if the pressed key is a letter, then, if it's marked as Upper, and the char is lower, replaces it with it's upper version (in the position of the cursor) then moves the cursor to the next part, and Viceversa (toLower)
NOTE:
This code will have may (should) have some trouble if the user has more than one character selected (SelectionLenght > 0), if you want to keep the normal Textbox functionality, you should delete all the selected characters
So I set up a WinForms app, drew two textboxes, set one to UseSystemPasswordChar=true then set it up like so:
private void Form1_Load(object sender, EventArgs e)
{
textBox2.Tag = "test2";
textBox1.Tag = "test1";
TextBox[] tb = { textBox1, textBox2 };
AddDefaultTextFromTag(tb);
}
Your function works fine and I have no problems tabbing through the controls on the form no matter what the textboxes contain. (added a button also that does nothing for tabbing test) so... no repro unless my test setup is not valid
What I found in the answer of this post was the solution for me. Instead of setting UseSystemPasswordChar to true and then to false, you can set PasswordChar to '●' and then to '\0' to have normal text. You should not set the UseSystemPasswordChar because it has precedence over PasswordChar.

TreeView Nodes appear to be caching

I'm creating a custom web user control in c#. It is intended to interact with a permission hierarchy. We have different "sites" and each site has many "apps" and each app has many "permissions"
So, We have a TabPanel that loads a tab for each site. Then in each tab we have a TreeView where the parent nodes are the apps and the inner nodes are the permissions.
The Permissions show check boxes based on some criteria and are checked based on whether or not the HasPermission function returns true.
All of this code works...but only for the first user selected. For any subsequent user chosen, a step through the debugger shows all the correct logic being executed, but the page displays the same information as that of the first user selected.
So basically, it's saving the display somewhere...and I'm at a loss to find out where.
public partial class Permissions : System.Web.UI.UserControl
{
string _NTLogin;
CoreUser _User;
bool _IsAdmin;
public string NTLogin
{
get
{
return _NTLogin;
}
set
{
ViewState["NTLogin"] = value;
_NTLogin = value;
}
}
public bool IsAdmin
{
get
{
return _IsAdmin;
}
set
{
ViewState["IsAdmin"] = value;
_IsAdmin = value;
}
}
protected void Page_Load(object sender, EventArgs e)
{
}
public void LoadTabs()
{
string [] sites = MISCore.BusinessLayer.CorePermission.GetSites();
foreach (string site in sites)
{
TabPanel tp = new TabPanel();
tp.HeaderText = site;
TabContainer1.Tabs.Add(tp);
}
}
public void LoadTrees()
{
if(_User == null)
return;
TabPanelCollection tabs = TabContainer1.Tabs;
foreach (TabPanel tab in tabs)
{
string site = tab.HeaderText;
string[] apps = MISCore.BusinessLayer.CorePermission.GetApplications(site);
TreeView tv1 = new TreeView();
tv1.EnableViewState = false;
foreach (string app in apps)
{
TreeNode tn1 = new TreeNode(app);
tn1.SelectAction = TreeNodeSelectAction.None;
string[] perms = MISCore.BusinessLayer.CorePermission.GetPermissions(site, app);
foreach (string perm in perms)
{
TreeNode tcn1 = new TreeNode(perm);
tcn1.SelectAction = TreeNodeSelectAction.None;
if (IsAdmin || _User.Manager.HasPermission(site, app, perm))
{
tcn1.ShowCheckBox = true;
if (_User.HasPermission(site, app, perm))
{
tcn1.Checked = true;
}
else
{
tcn1.Checked = false;
}
}
else
{
tcn1.ShowCheckBox = false;
}
tn1.ChildNodes.Add(tcn1);
}
tv1.Nodes.Add(tn1);
}
tab.Controls.Add(tv1);
}
}
protected override void LoadViewState(object savedState)
{
base.LoadViewState(savedState);
_NTLogin = (string)ViewState["NTLogin"];
_IsAdmin = (bool)ViewState["IsAdmin"];
if(_NTLogin != null)
_User = new CoreUser(_NTLogin);
TabContainer1.Tabs.Clear();
LoadTabs();
LoadTrees();
}
}
[UPDATE]
I iterate through the treeview after all the above code, it correctly stores their correct status. This is an issue with displaying. I can successfully change any other property, tooltip, text, etc to display their state, but the checkboxes are not updating...
I would use Fiddler to see who is caching the results. By looking at the requests you'll be able to tell if it's the browser or the server causing the problem.
Or if its okay with your client, you can put in a small link button that says refresh, and either you or the user can force this refresh treeview method, whenever required.
Should be pretty simple, in the paramters for the tab just add EnableViewState = false. Let me know if this works for you.

Categories

Resources