Trim all user input strings in ASP.NET Web Forms - c#

I am looking for a way to trim all user input in ASP.NET without calling Trim() on every string instance. I came across extending the DefaultModelBinder for MVC. Is there a way to do this in web forms? What options are available? As a less desirable option, is there a way to incorporate this into the set method of a class?

You could create a custom TextBox which always returns a trimmed version of the text:
public class CustomTextBox : TextBox
{
public override string Text
{
get { return base.Text.Trim(); }
set { base.Text = value; }
}
}
Then just use this instead of the normal TextBox anywhere you need this behavior.

Here is the utility method to trim all TextBoxes in a page (or a parent control) recursively.
public static void TrimTextBoxesRecursive(Control root)
{
foreach (Control control in root.Controls)
{
if (control is TextBox)
{
var textbox = control as TextBox;
textbox.Text = textbox.Text.Trim();
}
else
{
TrimTextBoxesRecursive(control);
}
}
}
Usage
protected void Button1_Click(object sender, EventArgs e)
{
TrimTextBoxesRecursive(Page);
}

You have to call this extension method from the appropriate parent, e.g. Page.TrimTextControls
public static void TrimTextControls(this Control parent, bool TrimLeading)
{
foreach (TextBox txt in parent.GetAllControls().OfType<TextBox>())
{
if (TrimLeading)
{
txt.Text = txt.Text.Trim();
}
else
{
txt.Text = txt.Text.TrimEnd();
}
}
}

Related

Extended control value is not setting from UI

Hi I'm trying to extend the TextBox use that extends one in my code. in the extended control, By default, it will trim start and end.
the code I have tried
public class TextboxTrimSpaceing : TextBox
{
private string myVar;
new public string Text
{
get { return myVar; }
set { myVar = value.TrimEnd().TrimStart(); }//Control is not coming here
}
}
UI
<local:TextboxTrimSpaceing x:Name="TrimSpaceing" Text=" avi aaa "></local:TextboxTrimSpaceing>
var i = TrimSpaceing.Text; //Getting Null
Here why my control is not going to the setter and why I'm getting Null result
Note: it's displaying proper string in UI and I know I can maintain it in code. but I need like this.
If you want to trim the text, you could override the OnTextChanged method:
public class TextboxTrimSpacing : TextBox
{
private bool _trim = true;
protected override void OnTextChanged(TextChangedEventArgs e)
{
base.OnTextChanged(e);
if(_trim)
{
_trim = false;
Text = Text?.Trim();
_trim = true;
}
}
}
It makes no sense to define a new Text property.

How can I reuse this snippet throughout a project?

I have this code on each form in my app that has textboxes to prevent the textboxes that are ReadOnly from being tabbed to:
private void FrmInventory_Load(object sender, EventArgs e)
{
foreach (var txtbx in Controls.OfType<TextBox>())
{
txtbx.TabStop = (!txtbx.ReadOnly);
}
}
It would be good to only have this code in one place, but how can I do that, as each time that "external" method was called, it would touch TextBoxes on the calling form, which smells a little fishy. Is an extension method the way to go, something like:
public static bool TextboxIsReadOnly(this TextBox txtbx)
{
return txtbx.ReadOnly;
}
...and then call it like this:
foreach (var txtbx in Controls.OfType<TextBox>())
{
txtbx.TabStop = TextboxIsReadOnly(txtbx);
}
?
That doesn't seem like it's of much value - I still would have to put most of the code in each form, just as things stand now. Creating a custom textbox that is both ReadOnly and TabStop = false seems a little overkillish...
Is there a way to have this logic execute for every TextBox-containing form, without reproducing the code all throughout the project?
Having a base class that performs that step and making it the base for all your forms would work, although you would need to be careful about calling the base version of the overloaded methods.
You can create a baseForm and Inherit that form in each of your forms.
Add a new Windows Form to your project(baseForm) and create load event
public class baseForm: Form
{
public baseForm()
{
this.Load += baseForm_Load;
}
void baseForm_Load(object sender, EventArgs e)
{
var t = GetAll<TextBoxX>(this);
foreach (var txtbx in Controls.OfType<TextBox>())
{
txtbx.TabStop = (!txtbx.ReadOnly);
}
}
public static List<T> GetAll<T>(Form f1)
{
List<T> f = new List<T>();
try {
if (f1 != null) {
CheckInner<T>(f1.Controls, ref f);
}
} catch (Exception ex) {
f.Clear();
}
return f;
}
}
And finally in each form you can do like this
public partial class FrmInventory : baseForm
{
}
Just to elaborate on the Extension Method solution you hinted at.
Extension Method
public static partial class MyExtensions
{
public static void UpdateTabStop(this TextBox txtBox)
{
txtBox.TabStop = !(txtBox.ReadOnly);
}
public static void UpdateTabStop(this Form frm)
{
foreach (var txtBox in frm.Controls.OfType<TextBox>())
{
txtBox.UpdateTabStop();
}
}
}
Then, on any Form you would do this.UpdateTabStop()... you should of course do this in an event after the controls are initialized, like Load.

How to create custom TextBox control?

I want to perform Trim() method on each TexBox control on my page, before value is returned. I dont' want to hard-code the same code for each TexBox control, I want to do it in more elegant way.
I've found made the following class
namespace System.Web.UI.WebControls
{
public partial class TrimmedTextBuox : TextBox
{
private string text;
public override string Text
{
get { return string.IsNullOrEmpty(text) ? text : text.Trim(); }
set { text = value; }
}
}
}
but it fails, while debuggind the compiler doesn't get inside get{} and set{}.
After that, I created a UserControl item, but it must be deriverd from System.Web.UI.UserControl, not System.Web.UI.WebControls.TextBox to get it work (there's an exception which points to that)
So, how can I do that ?
First you have to register your control in your .aspx page like that:
<%# Register TagPrefix="customControls" Namespace="WebApplication.Custom.Controls" Assembly="WebApplication"%>
Then you can call it using the markup
<customControls:TrimmedTextBuox ID="txtTrim" runat="server"/>
Plus you don't have to create another "text" property in your custom TextBox. Instead, it can be done like that:
namespace WebApplication.Custom.Controls
{
public class TrimmedTextBuox : TextBox
{
public override string Text
{
get
{
return base.Text;
}
set
{
if (!String.IsNullOrEmpty(value))
base.Text = value.Trim();
}
}
}
}
This will trim recursively all text boxes before inserting.
public static void trimRecursive(Control root)
{
foreach (Control control in root.Controls)
{
if (control is TextBox)
{
var textbox = control as TextBox;
textbox.Text = textbox.Text.Trim();
}
else
{
trimRecursive(control);
}
}
}
protected void Button1_Click(object sender, EventArgs e)
{
trimRecursive(Page);
}
Simple Solution to your problem is to hide the Text property of your base class by using new keyword. sample code...
public class TrimmedTextBox : TextBox
{
public new string Text
{
get
{
var t = (string) GetValue(TextProperty);
return t != null ? t.Trim() : string.Empty;
}
}
}
For more info about how new keyword with property works refrer to this SO Question

How to determine if Control has Text property

When I iterate over a bunch of different controls on a Form, instead of trying to access the Text property:
String text = String.Empty;
foreach(Control control in this.Controls)
{
try
{
text = control.Text;
}
catch(Exception exception)
{
// This control probably doesn't have the Text property.
Debug.WriteLine(exception.Message);
}
}
Is there a way to just determine whether or not a given control has a Text property? Something like this:
String text = String.Empty;
foreach(Control control in this.Controls)
{
if(control has Text property)
{
text = control.Text;
}
}
I absolutely despise the Try/Catch blocks (unless there is no better alternative, of-course).
All Control objects have a Text property, so there is no point in using reflection to determine that. It will always return true.
Your problem actually is that some controls throw an exception from their Text property because they don't support it.
If you also want to be able to use custom controls that you don't know in advance, you should stick to your current solution and catch the exceptions. However, you should catch the specific exception thrown, for example NotSupportedException.
If you only ever encounter controls that you know in advance, you can select the controls that you know have a working Text property. For example:
public static bool HasWorkingTextProperty(Control control)
{
return control is Label
|| control is TextBox
|| control is ComboBox;
}
var controlsWithText = from c in this.Controls
where HasWorkingTextProperty(c)
select c;
foreach(var control in controlsWithText)
{
string text = control.Text;
// Do something with it.
}
And if you implement your own custom controls that may or may not have a Text property, then you can derive them from a base class that indicates this:
public abstract class CustomControlBase : Control
{
public virtual bool HasText
{
get { return false; }
}
}
public class MyCustomControl : CustomControlBase
{
public override bool HasText
{
get { return true; }
}
public override string Text
{
get { /* Do something. */ }
set { /* Do something. */ }
}
}
public static bool HasWorkingTextProperty(Control control)
{
return (control is CustomControlBase && ((CustomControlBase)control).HasText)
|| control is Label
|| control is TextBox
|| control is ComboBox;
}
Your question is How to determine if Control has Text property, so here is how you can do it using Reflection:
control.GetType().GetProperties().Any(x => x.Name == "Text");
Edit: If you take a look at the Control class, you will see it has a Text property.
Now, if some custom control that overrides the Control class throws an exception when accessing to the Text property, it is violating the Liskov substitution principle. In that case, I suggest you identifying those controls, although what you're doing seems to be fine.
Check this out:
private void Form1_Load(object sender, EventArgs e)
{
foreach (Control ctrl in this.Controls)
{
PropertyInfo[] properties = ctrl.GetType().GetProperties();
foreach(PropertyInfo pi in properties)
if (pi.Name == "Text")
{
//has text
}
}
}

Linking a Text Box to a variable?

I would like to have direct access to the text inside a textbox on another form, so I added a public variable _txt to a form and added an event like so:
private void richTextBox1_TextChanged(object sender, EventArgs e)
{
_txt = richTextBox1.Text;
}
But the form is loaded like this:
public FrmTextChild(string text)
{
InitializeComponent();
_txt = text;
richTextBox1.Text = _txt;
Text = "Untitled.txt";
}
Is there a better way to directly link the two?
You could use a property instead to read directly from your TextBox. That way you don't need an extra variable at all.
public string Text
{
get
{
return richTextBox1.Text;
}
}
Add a setter if you also want to be able to change the text.
I don't think you should ever have forms reference each other's controls: when you change the lay out of one you will have to rewrite the code for the other. It is much better IMHO to store shared values in a separate class and have both forms reference that. Like so:
public class DataContainer
{
public string SomeData{get;set;}
}
public class Form1:Form
{
private DataContainer _container;
public Form1(DataContainer container)
{
_container=container;
}
private void richTextBox1_TextChanged(object sender, EventArgs e)
{
_container.SomeData = richTextBox1.Text;
}
private void SpawnForm2()
{
var form2=new Form2(_container);
form2.Show();
}
public class Form2:Form
{
private DataContainer _container;
public Form2(DataContainer container)
{
_container=container;
}
}
Another way to do it would be setting the Modifiers property for the TextBox (or any other control you want to access) to Protected Internal and then open the second form, the Owner being the first form.
This way, you can later on access the control and its properties with something like this:
((Form1)this.Owner).textBox1.Text = "This is a message from the second form";

Categories