这是最奇怪的事情,因为它在某些代码中对我不起作用。下面的代码位于一个子类TextBox的类中(注意:我不知道它是否重要,但我将Text属性子类化为从私有字段_realText设置/获取)
在下面的代码中,第一个base.Text = this.RealText工作正常!我们也在它的方法MaskData()中设置它,它的工作原理!那么为什么世界上它在if(!field.isSecure)部分不起作用? (看看我的意思的日志)。我尝试在base.Text = temp之后添加Invalidate(),Update(),但这没有帮助。
代码:
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();
}
}
}
日志
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=''
编辑:请注意,此方法始终从同一个线程调用。它来自服务器通知,告诉我们按下其他地方的电话铃声,然后该线程调用BeginInvoke将其放入GUI /控制线程等等。
上面方法上游的代码是
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();
}
));
}
更多信息:如果我更改所有客户端代码以停止使用Text属性并使用RealText属性,然后停止覆盖Text属性,那么它可以正常工作。 (显然我不希望这样,虽然现在我不能只是从我的控件更改为TextBox并且很容易返回,而不会更改许多指向RealText属性的客户端代码....唉,可能不得不忍受这一点。 ......似乎是某种奇怪的错误。
更多信息:让调试器踩到它,这很奇怪。
2件很奇怪的事情。
grrrrr,为什么会......听起来像是一个主要的错误,对吧?我的意思是,base.Text应该引用超类的基础,对吗? - Dean Hiller刚刚编辑
添加Text方法属性代码
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;
}
}
答案 0 :(得分:1)
除非您注释掉Text属性,否则此用户控件的完整源代码不起作用(您必须使用RealText属性并将其公开给客户端,因为base.Text似乎不起作用正确)。
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);
}));
}
}
}
答案 1 :(得分:1)
好的,你已经覆盖了文本 - 你可以在其中一行上找到它:
RealText = Text;
这将调用派生最多的'Text'属性(因为你没有指定base)并且会在当前控件上调用你被覆盖的'Text'
这意味着您将RealText设置为自身
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
来电
public override string Text
{
get { return RealText; }
}
哪一点......坚果!
你的意思是:
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?
仔细检查您的代码,我敢打赌这是您的问题之一
另外,稍微更改一下命名约定可能会有用......例如我倾向于使用下划线表示私有/受保护字段
private string _realText;
而不是属性的大写
private string RealText;
通常不公开公共字段,通常使用属性但是当我这样做时,我倾向于使用与属性相同的外壳
这样可以更容易区分代码中的属性和字段,并使调试更容易