Announcement

Collapse
No announcement yet.

textbox: ableitung von usercontrol und erneute ableitung

Collapse
X
  • Filter
  • Time
  • Show
Clear All
new posts

  • textbox: ableitung von usercontrol und erneute ableitung

    hallo zusammen,

    ich habe eine klasse mytextbox diese ist von usercontrol abgeleitet. darin ist die paint und resize methode implementiert. die klasse zeichnet einen rahmen um das textfeld.

    Code:
    public class MyTextbox : UserControl
    {
            private TextBox textbox = new TextBox();
    
            private Color _borderColor;
    
            [Browsable(true)]
            public override String Text
            {
                get { return this.textbox.Text; }
                set { this.textbox.Text = value; }
            }
    
            public override Color BackColor
            {
                get { return this.textbox.BackColor; }
                set { this.textbox.BackColor = value; }
            }
    		
            public Color BorderColor
            {
                get { return this._borderColor; }
                set
                {
                    this._borderColor = value;
                    this.Refresh();
                }
            }
    
            public MyTextbox()
            {
                this.Paint += new PaintEventHandler(this.OnPaint);
                this.Resize += new EventHandler(this.OnResize);
    
                this.Height = this.textbox.Height + 2;
                this.Width = this.textbox.Width + 2;
                this.BorderColor = System.Drawing.SystemColors.Window;
                this.Controls.Add(this.textbox);
            }
    		
            protected void OnResize(object sender, EventArgs e)
            {
                this.textbox.Size = new Size(this.Width - 2, this.Height - 2);
                this.textbox.Location = new Point(1, 1);
            }
    
            protected void OnPaint(object sender, PaintEventArgs e)
            {
                ControlPaint.DrawBorder(e.Graphics, this.ClientRectangle, _borderColor, ButtonBorderStyle.Solid);
            }
    }
    jetzt wollte ich von dieser klasse eine neue klasse ableiten myintegertextbox. dazu habe ich folgendes implementiert:

    Code:
    public class MyIntegerTextbox : MyTextbox
    {
    	private String _allowedChars = "0123456789";
    	private String _lastValidText = "";
    	private int _lastValidSelectionStart = 0;
    	private int _lastValidSelectionLength = 0;
    	private bool _validating = false;
    	
    	public String AllowedChars
    	{
    		get { return _allowedChars; }
    		set
    		{
    			_allowedChars = value;
    			Text = Text; //Text von nun ungültigen Zeichen "bereinigen"
    		}
    	}
    
    	public override String Text
    	{
    		get { return base.Text; }
    		set
    		{
    			StringBuilder onlyValid = new StringBuilder();
    
    			if (value != null)
    			{
    				foreach (char ch in value)
    				{
    					if (_allowedChars.Contains(ch.ToString()))
    					{
    						onlyValid.Append(ch);
    					}
    				}
    			}
    
    			base.Text = onlyValid.ToString();
    		}
    	}
    
    	protected override void OnTextChanged(EventArgs e)
    	{
    		if (_validating)
    		{
    			return;
    		}
    		try
    		{
    			_validating = true;
    
    			foreach (char ch in base.Text)
    			{
    				if (!_allowedChars.Contains(ch.ToString()))
    				{
    					base.Text = _lastValidText;
    					SelectionStart = _lastValidSelectionStart;
    					SelectionLength = _lastValidSelectionLength;
    					return;
    				}
    			}
    
    			_lastValidText = base.Text;
    			_lastValidSelectionStart = SelectionStart;
    			_lastValidSelectionLength = SelectionLength;
    			base.OnTextChanged(e);
    		}
    		finally
    		{
    			_validating = false;
    		}
    	}
    
    	protected override void OnClick(EventArgs e)
    	{
    		_lastValidSelectionStart = SelectionStart;
    		_lastValidSelectionLength = SelectionLength;
    		base.OnClick(e);
    	}
    
    	protected override void OnKeyDown(KeyEventArgs e)
    	{
    		if (base.Text == _lastValidText)
    		{
    			_lastValidSelectionStart = SelectionStart;
    			_lastValidSelectionLength = SelectionLength;
    		}
    		base.OnKeyDown(e);
    	}
    
    	protected override void OnKeyUp(KeyEventArgs e)
    	{
    		if (base.Text == _lastValidText)
    		{
    			_lastValidSelectionStart = SelectionStart;
    			_lastValidSelectionLength = SelectionLength;
    		}
    		base.OnKeyUp(e);
    	}
    
    	private void InitializeComponent()
    	{
    		this.SuspendLayout();
    		this.ResumeLayout(false);
    
    	}
    }
    leider werden die events OnTextChanged, onClick in der klasse MyIntegerTextbox nicht ausgelößt. ich bin nicht so fit mit den events. deshalb würde ich mich freuen wenn ihr mir einen tipp geben könnt. was ich noch versucht hatte war, die events in der mytextbox anzugeben nur ich weiß nicht genau wie. ich kann mir nämlich vorstellen, dass deshalb die events in MyIntegerTextbox nicht ausgeführt wird weil die klasse usercontrol die nicht implementiert.

    vielleicht kann mir jemand helden.

    danke und grüße

  • #2
    Im ersten Beispiel hast Du Dich auf das Event registriert
    Code:
    this.Paint += new PaintEventHandler(this.OnPaint);
    this.Resize += new EventHandler(this.OnResize);
    im zweiten Beispiel überschreibst Du wirklich die Funktion die eigentlich Deinen EventHandler aufrufen würde.

    Code:
    protected override void OnTextChanged(EventArgs e)
    {
      //...
    }
    
    protected override void OnClick(EventArgs e)
    {
      //...
    }
    Diese rufen jetzt natürlich keinen EventHandler mehr auf. Du hast nun 2 Möglichkeiten. Entweder Du benutzt intern wieder nur Events wie im ersten Beispiel oder Du rufst das richtige Event in der überschriebenen Funktion auf:

    Code:
    protected override void OnClick(EventArgs e)
    {
      //...
      if(this.Click != null)
        this.Click(this, new EventArgs());
    }
    Ach mir fällt noch eine 3. Möglichkeit ein: Du könntest auch in der überschriebenen Funktion base.OnClick(e) aufrufen. Das würde die Events wahrscheinlich auch wieder triggern. Kann allerdings sein, dass Du dann Verhalten in Deiner Klasse hast was Du nicht haben willst.

    Comment


    • #3
      Du hast die Events des UserControls überschrieben nicht die der Textbox. Wenn du also in der Textbox editierst werden die Events der Textbox gefeuert und nicht die von dir verdrahteten Events des UserControls.

      HAst du einen speziellen Grund ein UserControl dazwischen zu schalten und nicht einfach von Textbox abzuleiten?

      Edit: Vergiss de Frage. Du willst scheinbar einen Rahmen zeichnen der größer als die Textbox ist. Das kann die Textbox allein nicht.

      Comment


      • #4
        hallo,

        @ralf: ich wollte einen rahmen um die textbox und dazu habe ich das usercontrol unter die textbox gepackt. der rahmen dient dazu diesen zu aktiveiren bei bedarf. dehalb habe ich von usercontrol abgeleitet. bei der ableitung mit textbox wusste ich nicht wie ich einen rahmen außerhalb der box hinbekomme, innerhalb habe ich hinbekommen. hat mir aber nicht gefallen. oder geht das evt doch?

        grüße

        Comment


        • #5
          oder geht das evt doch?
          Nein. Zumindest habe ich da Vorstellungsprobleme.

          Edit : Bitte beim schreiben deiner Postings die Shift-taste auch sinnvoll verwenden. Ist sonst schwer zu lesen.

          Comment


          • #6
            hallo,

            ich versteh jetzt nicht so recht was ich in der MyIntegerTextbox klasser mache muss damit die events gefeuert werden. ich bräuchte noch etwas hilfestellung. wie genau muss ich dort z.b. das event onclick registrieren damit dies gefeuert wird wenn einer die textbox anklickt.

            danke und grüße

            Comment


            • #7
              Hallo,

              ich glaub jetzt verstehe ich ihr meintet. Entweder ich registriere in der MyIntegerTextbox Klasse ein Event mit

              Code:
              this.textbox.Click += new EventHandler(this.OnClick);
              dazu müsste ich aber Zugriff auf die Textbox in der Base Klasse MyTextbox haben. Dann würde auch die Methode

              Code:
              protected void OnClick( EventArgs e)
              aufgerufen werden.

              Die zweite Möglichkeit habe ich aber noch nicht verstanden.

              grüße und Danke
              PS: und dieses mal mit Shift ;-)

              Comment


              • #8
                Das simpelste währe wohl wenn das UserControl die Events der TextBox fängt und der EventHandler virtuell ist.

                Also Im UserControl wenn ich Beispielsweise KeyPress der Textbox überschreibe.

                [Highlight=C#]// Im MyTextbox Constructor Event verdrahten
                textbox.KeyPress += TextBoxKeyPress;

                // und Methode virtuell leer implementieren
                protected virtual void TextBoxKeyPress(object sender, KeyPressEventArgs e)
                { /*nop*/ }[/Highlight]

                und dann in MyIntegerTextbox überschreiben

                [Highlight=C#]protected override void TextBoxKeyPress(object sender, KeyPressEventArgs e)
                {
                if (e.KeyChar == '1') e.KeyChar = '0'; // irgendwas sinnvolles
                }[/Highlight]

                Comment


                • #9
                  Ich habe gerade mal ein paar Alternativen durchprobiert damit man ohne UserControl auskommt und direkt mit einer TextBox arbeiten kann. 2 Wege scheinen gangbar haben aber kleinere Probleme mit dem Designer.

                  1.) Die TextBox einfach auf ihren Parent zeichnen lassen.

                  [Highlight=C#]public class MyTextbox : TextBox
                  {
                  private Control _oldParent = null;
                  private Color _borderColor = Color.Red;
                  public Color BorderColor
                  {
                  get { return this._borderColor; }
                  set
                  {
                  this._borderColor = value;
                  this.Refresh();
                  }
                  }

                  protected override void OnParentChanged(EventArgs e)
                  {
                  if (_oldParent != null)
                  _oldParent.Paint -= Parent_Paint;
                  base.OnParentChanged(e);
                  if (Parent != null)
                  Parent.Paint += Parent_Paint;
                  _oldParent = Parent;
                  }

                  void Parent_Paint(object sender, PaintEventArgs e)
                  {
                  Rectangle rect = new Rectangle(Left -1, Top - 1, Width + 2, Height + 2);
                  ControlPaint.DrawBorder(e.Graphics, rect, _borderColor, ButtonBorderStyle.Solid);
                  }
                  }[/Highlight]

                  2. Zur Laufzeit erst ein Control dazwischenschalten (heißt denn Rahmen siehst du nur zur Laufzeit)

                  [Highlight=C#]public class MyTextBox : TextBox
                  {
                  private Color _borderColor = Color.Red;
                  public Color BorderColor
                  {
                  get { return this._borderColor; }
                  set
                  {
                  this._borderColor = value;
                  this.Refresh();
                  }
                  }

                  private Panel box = new Panel();

                  public MyTextBox()
                  {
                  box.Paint += new PaintEventHandler(box_Paint);
                  }

                  private void box_Paint(object sender, PaintEventArgs e)
                  {
                  ControlPaint.DrawBorder(e.Graphics, box.ClientRectangle, _borderColor, ButtonBorderStyle.Solid);
                  }

                  protected override void OnParentChanged(EventArgs e)
                  {
                  base.OnParentChanged(e);

                  if ((!DesignMode) && (Parent != null) && (Parent != box))
                  {
                  Parent.Controls.Add(box);
                  if (this.Parent != box)
                  box.Controls.Add(this);

                  box.Left = this.Left - 1;
                  box.Top = this.Top - 1;
                  box.Height = this.Height + 2;
                  box.Width = this.Width + 2;

                  this.Left = 1;
                  this.Top = 1;
                  }
                  }
                  }[/Highlight]

                  Comment


                  • #10
                    Variante 3: Spätes Zeichnen

                    [Highlight=C#]public class MeineTextBox : TextBox
                    {
                    private static int WM_NCPAINT = 0x0085;
                    private static int WM_ERASEBKGND = 0x0014;
                    private static int WM_PAINT = 0x000F;

                    public MeineTextBox()
                    {
                    BorderStyle = BorderStyle.FixedSingle;
                    }

                    private Color _borderColor = Color.Red;
                    public Color BorderColor
                    {
                    get { return this._borderColor; }
                    set
                    {
                    this._borderColor = value;
                    this.Refresh();
                    }
                    }

                    [DllImport("user32.dll")]
                    static extern IntPtr GetDC(IntPtr hWnd);

                    [DllImport("user32.dll")]
                    static extern int ReleaseDC(IntPtr hwnd, IntPtr hDC);

                    protected override void WndProc(ref Message m)
                    {
                    base.WndProc(ref m);

                    if (m.Msg == WM_PAINT || m.Msg == WM_ERASEBKGND || m.Msg == WM_NCPAINT)
                    {
                    IntPtr hdc = GetDC(m.HWnd);
                    try
                    {
                    if (hdc != IntPtr.Zero)
                    {
                    Graphics g = Graphics.FromHdc(hdc);
                    ControlPaint.DrawBorder(g, new Rectangle(0, 0, Width, Height), _borderColor, ButtonBorderStyle.Solid);
                    }
                    }
                    finally
                    {
                    ReleaseDC(m.HWnd, hdc);
                    }
                    }
                    }
                    }[/Highlight]

                    Comment


                    • #11
                      hallo ralf,

                      du glaubst gar nicht wie begeistert ich gerade bin :-)
                      so schnell drei lösungen zu präsentieren, dass ist unglaublich!! ich hab mich spontan für die erste entschieden. versuche die morgen in mein projekt einzubauen. mir ist das viel lieber direkt von textbox abzuleiten. das andere hatte ich mir so aus teilen zuzusammen gebaut. so bin ich auf der sicheren seite was die events betriff und ich kann sie besser verwenden.

                      ich geb euch rückemeldung.

                      lieben gruß,

                      ps: wieder alles ohne shift, sorry, ich mach viel auf englisch und bin deshalb das klein schreiben so gewöhnt :-)

                      Comment


                      • #12
                        Hallo Ralf,

                        ich habe deine erste Variante verwendet. Hab sie noch dahingehend angepasst, dass die Farbe erst einmal auf Standard Windows gesetzt wird und dann wenn ich es benötige erst eine Farbe ins Spiel kommt:

                        Code:
                        public class MyTextbox : TextBox
                            {
                                /// <summary>
                                /// 
                                /// </summary>
                                private Control _oldParent = null;
                                /// <summary>
                                /// 
                                /// </summary>
                                private Color _borderColor;
                        
                                /// <summary>
                                /// 
                                /// </summary>
                                public MyTextbox()
                                {
                                    this._borderColor = System.Drawing.SystemColors.Window;
                                }
                        
                                /// <summary>
                                /// 
                                /// </summary>
                                public Color BorderColor
                                {
                                    get { return this._borderColor; }
                                    set
                                    {
                                        this._borderColor = value;
                                        this.Parent.Refresh();
                                    }
                                }
                        
                                /// <summary>
                                /// 
                                /// </summary>
                                /// <param name="e"></param>
                                protected override void OnParentChanged(EventArgs e)
                                {
                                    if (_oldParent != null)
                                        this._oldParent.Paint -= this.Parent_Paint;
                        
                                    base.OnParentChanged(e);
                        
                                    if (Parent != null)
                                        Parent.Paint += this.Parent_Paint;
                        
                                    this._oldParent = Parent;
                                }
                        
                                /// <summary>
                                /// 
                                /// </summary>
                                /// <param name="sender"></param>
                                /// <param name="e"></param>
                                void Parent_Paint(object sender, PaintEventArgs e)
                                {
                                    Rectangle borderRectangle = new Rectangle(this.Left - 1, this.Top - 1, this.Width + 2, this.Height + 2);
                                    ControlPaint.DrawBorder(e.Graphics, borderRectangle, _borderColor, ButtonBorderStyle.Solid);
                                }
                        
                            }
                        Das einzige was falsch war, dass unter der BorderColor Methode im Setter this.refresh() anstatt this.Parent.Refresh(); stand. Dann geht die Farbeaktualisierung auch.


                        Ein Problem habe ich noch. Ich wollte, wenn ich die Farbe setzte, den Style von Fixed3D auf None setzten. Das führt leider dazu das die Box komisch dargestellt wird, ca. um die Hälfte kleiner in der Höhe und der Designer spinnt dann rum und stellt das Form nicht mehr da. Weißt du evt. da auch noch eine Antwort oder einen Erfahrungswert?

                        grüße und gute NAcht!

                        Comment


                        • #13
                          Das sich die Größe bei BorderStyle None ändert ist normal. Denn genauen Grund kenne ich nicht. Ich vermute mal das Border mehr ist als nur der Rand denn du dir (und eigentlich auch ich mir) hier vorstellst. Wenn man den wegnimmt bleibt halt nur dieser scheinbar schmalere Streifen übrig. Das Problem mit dem Form Designer kann ich nicht nachvollziehen. Im Setter von Borderstyle solltest du aber Parent noch auf Null testen.

                          Wenn du nicht 2 Rahmen willst( also den der TextBox und deinen) dann solltest du nochmal einen Blick auf meine 3.Variante werfen. Da dort der Rahmen von BorderStyle FixedSingle übermalt wird hast du a.) nur 1 Rahmen und b.) keine Problem mit der Größe der Textbox wie bei BorderStyle.None.

                          Comment


                          • #14
                            Hallo Ralf,

                            hast du evt. noch eine Idee wie ich die größe der Textbox ändern kann? Ich habe versucht per textbox.height etwas im onResize Event zuzuweisen. das geht aber nicht. Die Box beleibt in der Größe.

                            Grüße und Danke

                            Comment


                            • #15
                              Solange du nicht Multiline auf true setzt wird die Textbox ihre Höhe selbst bestimmen. Ob Multiline für dich noch andere Nebeneffekte hat kann ich gerade nicht beurteilen.

                              Comment

                              Working...
                              X