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 プロパティのオーバーライドを停止すると、問題なく動作します。(明らかに、私はそれを望んでいませんが、RealText プロパティを参照する多くのクライアント コードを変更せずに、コントロールから TextBox に簡単に変更したり、元に戻したりすることはできません。 ...奇妙なバグのようです。

詳細情報: デバッガーがそれにステップインしましたが、これは非常に奇妙です。

2 非常に奇妙なこと。

  1. セッターではなく、ゲッターにステップします???
  2. TextBox の Text プロパティではなく、MY Text プロパティにステップインします。

grrrrr、なぜそれが...重大なバグのように聞こえますか? つまり、base.Text はスーパークラスのベースを参照する必要がありますね。– ディーン・ヒラー 編集中

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

OK、あなたは Text を上書きしました - そして、あなたの行の 1 つにこれがあります:

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?

コードを注意深く確認してください。これはあなたの問題の1つだと思います

また、命名規則を少し変更すると役立つ場合があります...たとえば、私はプライベート/保護されたフィールドにアンダースコアを使用する傾向があります

private string _realText;

プロパティ用のキャップの代わりに

private string RealText;

通常はパブリック フィールドを公開せず、通常はプロパティを使用しますが、公開する場合はプロパティと同じ大文字小文字を使用する傾向があります

これは、コード内のプロパティとフィールドを区別しやすくし、デバッグを少し簡単にするためです。

于 2012-06-30T21:30:17.570 に答える
1

このユーザー コントロールの完全なソースは、Text プロパティをコメント アウトしない限り機能しません (base.Text が適切に機能していないように見えるため、代わりに RealText プロパティを使用してクライアントに公開する必要があります)。

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 に答える