Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Hiding DateTimePicker's text and Usercontrol resize

I have a user control which has a DateTimePicker overlaid with the single line text box(Tb)
covering the text part of DateTimePicker. The textbox Tb (green) is anchored (L T R B).

Datepicker  overlaid with textbox

The problem comes when the usercontrol is resized.
The overlaid datetimepicker shows up behind the text Tb.

The overlaid datetimepicker shows up behind the green textbox Tb.

Currently the user control is 242(W) x 20(H) . Problems shows up when control is resized below 100 (Width) .

I tried the blank the text with CustomFormat set to " " but the user control supports many of the datetimepicker functionalities so that was not an option.

I tried to set the minimum size on the user control but that doesn't work too.

Edit:
The control is already in use in few applications.In those applications the minimum size of the control is 90X20 whereas the minimum size which we set now is 97x20.
Will VS designer size the existing controls to 97x20 after making the change?
How to achieve this effect(re-size to 97x20)?

Edit ****code after adding minimum size****

namespace WindowsFormsApplication1
{
    partial class CDatePicker
    {
        private System.ComponentModel.IContainer components = null;


        protected override void Dispose(bool disposing)
        {
            if (disposing && (components != null))
            {
                components.Dispose();
            }
            base.Dispose(disposing);
        }

        #region Component Designer generated code


        private void InitializeComponent()
        {
            this.splitContainer1 = new System.Windows.Forms.SplitContainer();
            this.datepanel = new System.Windows.Forms.Panel();
            this.datetxt = new System.Windows.Forms.TextBox();
            this.dateTimePicker1 = new System.Windows.Forms.DateTimePicker();
            this.timepanel = new System.Windows.Forms.Panel();
            this.timetxt = new System.Windows.Forms.TextBox();
            ((System.ComponentModel.ISupportInitialize)(this.splitContainer1)).BeginInit();
            this.splitContainer1.Panel1.SuspendLayout();
            this.splitContainer1.Panel2.SuspendLayout();
            this.splitContainer1.SuspendLayout();
            this.datepanel.SuspendLayout();
            this.timepanel.SuspendLayout();
            this.SuspendLayout();
            // 
            // splitContainer1
            // 
            this.splitContainer1.Dock = System.Windows.Forms.DockStyle.Fill;
            this.splitContainer1.Location = new System.Drawing.Point(0, 0);
            this.splitContainer1.Name = "splitContainer1";
            // 
            // splitContainer1.Panel1
            // 
            this.splitContainer1.Panel1.Controls.Add(this.datepanel);
            this.splitContainer1.Panel1MinSize = 105;
            // 
            // splitContainer1.Panel2
            // 
            this.splitContainer1.Panel2.Controls.Add(this.timepanel);
            this.splitContainer1.Size = new System.Drawing.Size(236, 20);
            this.splitContainer1.SplitterDistance = 178;
            this.splitContainer1.SplitterWidth = 1;
            this.splitContainer1.TabIndex = 0;
            // 
            // datepanel
            // 
            this.datepanel.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) 
            | System.Windows.Forms.AnchorStyles.Left) 
            | System.Windows.Forms.AnchorStyles.Right)));
            this.datepanel.Controls.Add(this.datetxt);
            this.datepanel.Controls.Add(this.dateTimePicker1);
            this.datepanel.Location = new System.Drawing.Point(0, 0);
            this.datepanel.Margin = new System.Windows.Forms.Padding(0);
            this.datepanel.Name = "datepanel";
            this.datepanel.Size = new System.Drawing.Size(175, 20);
            this.datepanel.TabIndex = 0;
            // 
            // datetxt
            // 
            this.datetxt.BackColor = System.Drawing.Color.Gainsboro;
            this.datetxt.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
            this.datetxt.Location = new System.Drawing.Point(0, 0);
            this.datetxt.MinimumSize = new System.Drawing.Size(60, 20);
            this.datetxt.Name = "datetxt";
            this.datetxt.Size = new System.Drawing.Size(71, 20);
            this.datetxt.TabIndex = 3;
            this.datetxt.Text = "date";
            // 
            // dateTimePicker1
            // 
            this.dateTimePicker1.Dock = System.Windows.Forms.DockStyle.Fill;
            this.dateTimePicker1.Format = System.Windows.Forms.DateTimePickerFormat.Short;
            this.dateTimePicker1.Location = new System.Drawing.Point(0, 0);
            this.dateTimePicker1.Margin = new System.Windows.Forms.Padding(0);
            this.dateTimePicker1.MinimumSize = new System.Drawing.Size(65, 20);
            this.dateTimePicker1.Name = "dateTimePicker1";
            this.dateTimePicker1.Size = new System.Drawing.Size(175, 20);
            this.dateTimePicker1.TabIndex = 2;
            this.dateTimePicker1.Value = new System.DateTime(2012, 11, 15, 0, 0, 0, 0);
            // 
            // timepanel
            // 
            this.timepanel.Controls.Add(this.timetxt);
            this.timepanel.Dock = System.Windows.Forms.DockStyle.Fill;
            this.timepanel.Location = new System.Drawing.Point(0, 0);
            this.timepanel.Margin = new System.Windows.Forms.Padding(0);
            this.timepanel.Name = "timepanel";
            this.timepanel.Size = new System.Drawing.Size(57, 20);
            this.timepanel.TabIndex = 0;
            // 
            // timetxt
            // 
            this.timetxt.Dock = System.Windows.Forms.DockStyle.Fill;
            this.timetxt.Location = new System.Drawing.Point(0, 0);
            this.timetxt.Name = "timetxt";
            this.timetxt.Size = new System.Drawing.Size(57, 20);
            this.timetxt.TabIndex = 1;
            this.timetxt.Text = "time";
            this.timetxt.TextAlign = System.Windows.Forms.HorizontalAlignment.Center;
            // 
            // CDatePicker
            // 
            this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
            this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
            this.AutoSize = true;
            this.Controls.Add(this.splitContainer1);
            this.MaximumSize = new System.Drawing.Size(236, 20);
            this.MinimumSize = new System.Drawing.Size(100, 20);
            this.Name = "CDatePicker";
            this.Size = new System.Drawing.Size(236, 20);
            this.splitContainer1.Panel1.ResumeLayout(false);
            this.splitContainer1.Panel2.ResumeLayout(false);
            ((System.ComponentModel.ISupportInitialize)(this.splitContainer1)).EndInit();
            this.splitContainer1.ResumeLayout(false);
            this.datepanel.ResumeLayout(false);
            this.datepanel.PerformLayout();
            this.timepanel.ResumeLayout(false);
            this.timepanel.PerformLayout();
            this.ResumeLayout(false);

        }

        #endregion

        private System.Windows.Forms.SplitContainer splitContainer1;
        private System.Windows.Forms.Panel datepanel;
        private System.Windows.Forms.TextBox datetxt;
        private System.Windows.Forms.DateTimePicker dateTimePicker1;
        private System.Windows.Forms.Panel timepanel;
        private System.Windows.Forms.TextBox timetxt;
    }
}

Edit : After adding min sizes, it looks better but the calender drop down disappears
when the control is resized to min and the project is rebuilt..
Also the text box doesn't remain anchored near the calender button..

edit: pic added for above..calender disappears.

date calender disappears

Edit : Oh i missed one more thing both the date field and time field are collapsible.thats why the split container is there. Minimum size calculations must also be aware of this.(i guess 2 different min. sizes depending on visibility of time field.)

Questions:

a) How can i prevent the usercontrol from resizing beyond certain min limit to avoid above problem? (pic1 seems to be idea size)

b) Can i draw the datetimepicker such that the text is blanked out and we only see the
calender dropdown button? If so will i still need to handle resize events?

c) How can i keep resizing the textbox so that it always covers the date text part of DTP.

like image 309
Amitd Avatar asked Apr 05 '12 05:04

Amitd


1 Answers

You have a simple problem and a hard problem. The simple problem is evident from the screenshots. The DateTimePicker is not resizing correctly, note how the dropdown button is getting clipped on the right-hand side. The UserControl is too strange to really pinpoint the problem but I think it is the datePanel. You are using Anchor.Right instead of Dock.Fill.

The hard problem is that the dropdown button resizes itself dynamically, based on the amount of space that's available to render the DTP content. At least on Windows 7, earlier versions use a different rendering strategy. Sadly, the VisualStyles api doesn't return the actual size of the button. The only decent way to deal with it is to make sure the textbox is large enough to cover the icon so only the dropdown arrow is visible.

I can't do much with the UserControl, I'll propose a much simpler solution that just derives from the DateTimePicker class and embeds a TextBox inside of it. Also a lot cheaper at runtime:

using System;
using System.Drawing;
using System.Windows.Forms;
using System.Windows.Forms.VisualStyles;
using System.Runtime.InteropServices;

class MyDateTimePicker : DateTimePicker {
    private TextBox editbox;
    private int buttonWidth;

    public MyDateTimePicker() {
        editbox = new TextBox();
        editbox.BorderStyle = BorderStyle.None;
        editbox.BackColor = Color.Gold;   // debugging
        this.Controls.Add(editbox);
    }

    public override Font Font {
        get { return base.Font; }
        set { base.Font = editbox.Font = value; }
    }

    protected override void OnResize(EventArgs e) {
        if (buttonWidth == 0) measureButtonWidth();
        var margin = (this.ClientSize.Height - editbox.PreferredHeight) / 2;
        editbox.Location = new Point(margin, margin);
        editbox.Width = this.ClientSize.Width - margin - buttonWidth;
        base.OnResize(e);
    }

    private void measureButtonWidth() {
        if (!Application.RenderWithVisualStyles) buttonWidth = 21;   // TODO: measure
        else {
            var renderer = new VisualStyleRenderer("DATEPICKER", 3, 1);
            using (var gr = CreateGraphics()) {
                buttonWidth = renderer.GetPartSize(gr, ThemeSizeType.True).Height;
            }
        }
    }

    protected override void Dispose(bool disposing) {
        if (disposing) editbox.Dispose();
        base.Dispose(disposing);
    }
}

The OnResize override takes care of keeping the TextBox the right size. Add whatever code you have to process the editbox.Text property. The only detail not taken care of is the size of the dropdown button when visual styles are disabled. Uncommon these days but still possible. Turn off theming on your machine and tweak the hard-coded size so it matches the appearance.

like image 93
Hans Passant Avatar answered Sep 22 '22 05:09

Hans Passant