Reputation: 20210
This is the weirdest thing as it works for me in some code in not other. The following code is in a class that subclasses TextBox (NOTE: I don't know if it matters but I subclass the Text property to set/get from a private field _realText)
In the below code, the first base.Text = this.RealText works fine!!! We also set it inside that method MaskData() as well and it works!!!! so why in the world does it not work in the if(!field.isSecure) section? (look at the logs for what I mean). I tried adding Invalidate(), Update() after base.Text=temp but that didn't help.
Code:
private void SetupTextInBox()
{
if (isInManualMode)
{
this.ReadOnly = false;
base.Text = this.RealText;
}
else
{
this.ReadOnly = true;
if (!field.IsSecure)
{
string temp = this.RealText;
log.Info("This field is not secure so show it. field=" + field.Variable + " real='" + temp+"'");
base.Text = temp;
log.Info("text value='" + base.Text+"'");
return;
}
else
{
MaskData();
}
}
}
Logs
2012-06-30 07:15:51,468 [1] INFO AlpineAccess.Plugins.SecureTalkPlugin.SecureTextControl (null) - This field is not secure so show it. field=1.acc real='2222'
2012-06-30 07:15:51,468 [1] INFO AlpineAccess.Plugins.SecureTalkPlugin.SecureTextControl (null) - text value=''
EDIT: Note that this method is ALWAYS called from the same thread. It comes from server notifications telling us a tone on a phone somewhere else has been pressed, AND then that thread calls a BeginInvoke to put it in the GUI/controls thread or whatnot.
code just upstream from the above method is
public void AppendDTMFDigit(string digit)
{
log.Info("specified="+field.MaxSpecified+" someone appending dtmf digit on field=" + field.Variable+" fieldMax="+field.Max+" len="+RealText.Length);
if (field.MaxSpecified && this.RealText.Length >= field.Max)
return; //shortcut out since we can't exceed max digits
BeginInvoke(new MethodInvoker(delegate()
{
this.RealText = this.RealText + digit;
log.Info("new realtext=" + this.RealText);
SetupTextInBox();
}
));
}
MORE INFO: If I change ALL my client code to stop using Text property and use RealText property, and then stop overriding the Text property, it then works fine. (Obviously I don't want that though as now I can't just change from my control to TextBox and back easily without changing lots of client code referring to the RealText property....ugh, may have to live with that though....seems like some kind of odd bug.
MORE INFO: got debugger stepping into it and this is very odd.
2 very odd things.
grrrrr, why would that be...sounds like a major bug, right? I mean, base.Text should refer to superclass's base, correct? – Dean Hiller just now edit
Adding Text method property code
public override string Text
{
get
{
return RealText;
}
set
{
if (value == null)
throw new ArgumentException("Not allowed to set RealText to null. Set to empty string instead");
RealText = value;
}
}
Upvotes: 1
Views: 4890
Reputation: 14002
Ok you've overridden Text - and you have THIS on one of your lines:
RealText = Text;
This will call the most derived 'Text' property (since you didn't specify base) and will call your overridden 'Text' on the current control
Which means you are setting RealText to itself
e.g.
void SecureTextBox_TextChanged(object sender, EventArgs e)
{
if (isInManualMode) //make sure if in manual mode, we keep changes up to date in realText field
RealText = Text; <---- **THIS CALLS THE OVERIDDEN 'Text' BELOW**
... snip
calls
public override string Text
{
get { return RealText; }
}
Which is a bit...nuts!
Did you mean to do:
void SecureTextBox_TextChanged(object sender, EventArgs e)
{
if (isInManualMode) //make sure if in manual mode, we keep changes up to date in realText field
RealText = base.Text; <--- THIS?
Check your code carefully, I bet this is one of your issues
Also it might be useful to change your naming conventions a little... e.g. I tend to use an underscore for private/protected fields
private string _realText;
instead of caps which is for properties
private string RealText;
Don't usually expose public fields, usually use properties but when I do I tend to use the same casing as I do for properties
This is so that it's easier to differentiate between properties and fields in your code and makes debugging a bit easier
Upvotes: 1
Reputation: 20210
Full source for this user control that doesn't work unless you comment out the Text property is here (You would have to use a RealText property and expose that one to clients instead because base.Text does not appear to work properly).
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using log4net;
using IntraNext.Win32.Config;
namespace AlpineAccess.Plugins.SecureTalkPlugin
{
public partial class SecureTextBox : TextBox
{
private static readonly ILog log = LogManager.GetLogger(typeof(SecureTextControl));
private static readonly Color COLOR_FOCUSED = Color.Yellow;
private static readonly Color COLOR_FOCUSED_MANUALMODE = Color.PaleGreen;
private FocusEvent focusListener;
private Field field;
private bool isInManualMode;
private EventHandler textChanged;
private string RealText;
public SecureTextBox()
{
InitializeComponent();
RealText = "";
}
internal void Initialize(Field field, FocusEvent focusList, EventHandler textChanged)
{
this.focusListener = focusList;
this.textChanged = textChanged;
this.field = field;
this.Enter += new EventHandler(SecureTextBox_Enter);
this.Leave += new EventHandler(SecureTextBox_Leave);
this.TextChanged += new EventHandler(SecureTextBox_TextChanged);
MenuItem mnuItemNew = new MenuItem();
mnuItemNew.Text = "&Clear";
//THIS textbox HAS a context menu ALREADY BUT here we assign a new context menu to
//our text box to replace the old one which had cut, paste etc. that we don't want
//the agent using...
this.ContextMenu = new ContextMenu();
this.ContextMenu.MenuItems.Add(mnuItemNew);
mnuItemNew.Click += new EventHandler(clear_Click);
SwitchModes();
}
void SecureTextBox_TextChanged(object sender, EventArgs e)
{
if(isInManualMode) //make sure if in manual mode, we keep changes up to date in realText field
RealText = Text;
textChanged(sender, e);
}
void clear_Click(object sender, EventArgs e)
{
ClearAll();
}
internal void SetManualMode(bool inManual)
{
if (isInManualMode == inManual)
return; //we don't care if there is no change so return;
isInManualMode = inManual;
SwitchModes();
}
void SecureTextBox_Leave(object sender, EventArgs e)
{
log.Info("exiting=" + field.Variable);
focusListener(field.Variable, false, this.RealText);
BeginInvoke(new MethodInvoker(delegate()
{
ChangeBackground();
}
));
}
void SecureTextBox_Enter(object sender, EventArgs e)
{
log.Info("entering=" + field.Variable );
focusListener(field.Variable, true, this.RealText);
BeginInvoke(new MethodInvoker(delegate()
{
ChangeBackground();
}
));
}
private void SwitchModes()
{
SetupTextInBox();
ChangeBackground();
}
private void SetupTextInBox()
{
if (isInManualMode)
{
this.ReadOnly = false;
base.Text = RealText;
}
else if (!field.IsSecure)
{
this.ReadOnly = true;
string temp = RealText;
base.Text = temp;
Invalidate();
log.Info("txt=" + base.Text + " temp=" + temp);
}
else //not manual mode and IsSecure so mask it and make it readonly
{
this.ReadOnly = true;
MaskData();
}
}
private void MaskData()
{
log.Debug("mask=" + this.field.NumBeginDigitsToMaskSpecified + " num=" + field.NumBeginDigitsToMask + " txtLen=" + RealText.Length);
int numDigitsToMask = RealText.Length;
if (this.field.NumBeginDigitsToMaskSpecified && this.field.NumBeginDigitsToMask < RealText.Length)
{
int numDigits = this.field.NumBeginDigitsToMask;
string maskedPart = "".PadLeft(numDigits, '●');
string unmasked = RealText.Substring(numDigits);
string full = maskedPart + unmasked;
base.Text = full;
}
else
{
log.Debug("masking all digits");
base.Text = "".PadLeft(RealText.Length, '●');
}
}
private void ChangeBackground()
{
if (isInManualMode)
SetManualModeColor();
else
SetNonManualModeColor();
}
private void SetNonManualModeColor()
{
if (this.Focused)
this.BackColor = COLOR_FOCUSED;
else
this.BackColor = Control.DefaultBackColor;
}
private void SetManualModeColor()
{
if (this.Focused)
this.BackColor = COLOR_FOCUSED_MANUALMODE;
else
this.BackColor = Control.DefaultBackColor;
}
public void AppendDTMFDigit(string digit)
{
log.Info("manualmode="+isInManualMode+" specified=" + field.MaxSpecified + " someone appending dtmf digit on field=" + field.Variable + " fieldMax=" + field.Max + " len=" + RealText.Length);
if (isInManualMode)
return;
else if (field.MaxSpecified && RealText.Length >= field.Max)
return; //shortcut out since we can't exceed max digits
BeginInvoke(new MethodInvoker(delegate()
{
RealText = RealText + digit;
SetupTextInBox();
}
));
}
internal void ClearAll()
{
log.Info("Cleared textbox for =" + field.Variable);
base.Text = "";
RealText = "";
SetError("");
}
public override string Text
{
get
{
return RealText;
}
set
{
if (value == null)
throw new ArgumentException("Not allowed to set RealText to null. Set to empty string instead");
RealText = value;
}
}
/**
* Set to "" to clear the error or set anything to make valid
*/
public void SetError(string error)
{
if (!this.IsHandleCreated)
return;
SecureTextBox box = this;
//set to "" to clear the error
BeginInvoke(new MethodInvoker(delegate()
{
errorProvider1.SetError(box, error);
}));
}
}
}
Upvotes: 1