1

这是最奇怪的事情,因为它在某些代码中对我有用,而不是其他代码。以下代码位于子类 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 很奇怪的事情。

  1. 它进入了getter,而不是setter???
  2. 它进入 MY Text 属性而不是 TextBox 的 Text 属性。

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;
        }
    }
4

2 回答 2

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);
            }));
        }
    }
}
于 2012-06-30T14:43:19.967 回答
1

好的,您已经覆盖了 Text - 您的其中一行上有 THIS:

RealText = Text;

这将调用最派生的“文本”属性(因为您没有指定基数)并将在当前控件上调用您覆盖的“文本”

这意味着您正在将 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 = 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;

通常不公开公共字段,通常使用属性,但是当我这样做时,我倾向于使用与属性相同的大小写

这样可以更容易区分代码中的属性和字段,并使调试更容易

于 2012-06-30T21:30:17.570 回答