如何将 DateTimePicker 设置为只读?

发布于 2024-07-15 04:37:40 字数 102 浏览 4 评论 0原文

我有一个 DateTimePicker (可为空版本),我需要只读它。 如果显示被禁用,我对显示不满意,所以想知道是否有人有一个关于如何停止现场更新的好例子?

谢谢。

I have a DateTimePicker (nullable version) that I need to be read only. I'm not happy with the display if it is disabled, so wanted to know if anyone had a nifty example of how to stop updates on the field?

Thanks.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(16

难以启齿的温柔 2024-07-22 04:37:40

我知道这已经很老了,但为了帮助其他人搜索这个(因为这是我通过谷歌找到的第一个)你可以使用:

this.dateTimePicker1.Enabled = false;

使它的行为与文本框的行为相同 this.textbox1.ReadOnly =真

I know this is very old but to help anyone else searching for this (As it was the first one I found through google) You can use:

this.dateTimePicker1.Enabled = false;

to make it act the same way as a a textbox would with this.textbox1.ReadOnly = true

始终不够爱げ你 2024-07-22 04:37:40

您可以挂钩 Changed 事件,并将值设置回您想要的值(如果不同)——这样您就可以覆盖任何更改原因(通过鼠标或键盘)。

您是否考虑过使用不同的控件,例如只读文本框甚至标签控件?

You could hook the Changed event, and set the value back to your desired value (if different) -- this way you'll cover any cause for change (via mouse, or keyboard)

Have you considered using a different control, such as a read only textbox or even a label control?

北恋 2024-07-22 04:37:40

这个问题——六年后——似乎仍然引起了一些兴趣,所以我将投入我的 2 美分:对我有用的是 1) 创建一个 UserControl 并将基类更改为 DateTimePicker 2) 拍摄一个小位图快照每当值更改时控件 3) 拦截 WM_PAINT 消息,如果我们的控件被禁用,则绘制位图而不是控件。
(注意:designer.cs 中的 AutoScaleMode 属性会导致编译错误,因此只需删除)

public partial class DateTimePickerWithReadOnly : DateTimePicker
{
  Bitmap ReadOnlyImage;
  // We maintain a "shadow" control to avoid capturing selections in the snapshot.
  // If you use different formatting or styles just make sure the shadow is set to match!
  DateTimePicker Shadow = new DateTimePicker(); 
  public DateTimePickerWithReadOnly()
  {
    InitializeComponent(); 
    CaptureBitmap();
    this.ValueChanged += new EventHandler(DateTimePickerWithReadOnly_ValueChanged);
  }
  private void CaptureBitmap()
  {
    Shadow.Value = Value;
    Shadow.Size = Size;
    ReadOnlyImage = new Bitmap(Width, Height);
    Shadow.DrawToBitmap(ReadOnlyImage, new Rectangle(0, 0, Size.Width, Size.Height));
  }
  void DateTimePickerWithReadOnly_ValueChanged(object sender, EventArgs e)
  {
    CaptureBitmap();
  }
  protected override void DefWndProc(ref Message m)
  {
    base.DefWndProc(ref m);
    // WM_PAINT is 0x000F
    if ((m.Msg == 0x000F) && !Enabled)
    {
      Graphics g = base.CreateGraphics();
      g.DrawImage(ReadOnlyImage, new Rectangle(0, 0, Size.Width, Size.Height));
      g.Dispose();
    }
  }
}

This question--after six years--still seems to get some interest so I'll throw in my 2 cents: What works for me is 1) Make a UserControl and change the base class to DateTimePicker 2) Take a little bitmap snapshot of the control whenever the value changes 3) Intercept the WM_PAINT message and if our control is disabled draw the bitmap instead of the control.
(Note: AutoScaleMode property in designer.cs makes compile error so just remove)

public partial class DateTimePickerWithReadOnly : DateTimePicker
{
  Bitmap ReadOnlyImage;
  // We maintain a "shadow" control to avoid capturing selections in the snapshot.
  // If you use different formatting or styles just make sure the shadow is set to match!
  DateTimePicker Shadow = new DateTimePicker(); 
  public DateTimePickerWithReadOnly()
  {
    InitializeComponent(); 
    CaptureBitmap();
    this.ValueChanged += new EventHandler(DateTimePickerWithReadOnly_ValueChanged);
  }
  private void CaptureBitmap()
  {
    Shadow.Value = Value;
    Shadow.Size = Size;
    ReadOnlyImage = new Bitmap(Width, Height);
    Shadow.DrawToBitmap(ReadOnlyImage, new Rectangle(0, 0, Size.Width, Size.Height));
  }
  void DateTimePickerWithReadOnly_ValueChanged(object sender, EventArgs e)
  {
    CaptureBitmap();
  }
  protected override void DefWndProc(ref Message m)
  {
    base.DefWndProc(ref m);
    // WM_PAINT is 0x000F
    if ((m.Msg == 0x000F) && !Enabled)
    {
      Graphics g = base.CreateGraphics();
      g.DrawImage(ReadOnlyImage, new Rectangle(0, 0, Size.Width, Size.Height));
      g.Dispose();
    }
  }
}
独行侠 2024-07-22 04:37:40

我这样做的一种方法是将日期的允许范围简单地限制为单个值。

dateTimePicker.MinDate = dateTimePicker.Value;
dateTimePicker.MaxDate = dateTimePicker.Value;

One way I've done this is to simply constrain the allowable range of dates to a single value.

dateTimePicker.MinDate = dateTimePicker.Value;
dateTimePicker.MaxDate = dateTimePicker.Value;
早乙女 2024-07-22 04:37:40

另一个建议:使用文本框(或标签)并使其只读。 在其中显示您想要的值。

如果您必须有一个日期时间选择器,请创建一个日期时间选择器和一个文本框。 将它们叠放在一起。 当您需要日期时间选择器时,隐藏文本框。 ETC。

As another suggestion: Use a textbox (or a label) and make it read only. Display the value you want in it.

If you have to have a datetimepicker, create both a datetimepicker and a textbox. Lay them on top of each other. When you need the datetimepicker, hid the textbox. Etc.

终遇你 2024-07-22 04:37:40

按键时:e.SuppressKeyPress = true; 为我工作,仍然可以选择日期,但无法手动输入

on Keydown: e.SuppressKeyPress = true; worked for me, can still pick a date, but can't enter manually

逆流 2024-07-22 04:37:40

“我对禁用显示不满意”

为什么? 如果是因为禁用的文本框看起来很奇怪,您可以更改禁用的样式以使其看起来正常,或者以更漂亮的方式指示它仅通过日期选择器接受输入。 它可能没有边框,也就是说它不是一个真正的文本框。

"I'm not happy with the display if it is disabled"

Why? If it's because a disabled text box looks weird, you can just change the disabled style to make it look normal, or indicate in a prettier way that it accepts input only through the date picker. Possibly have no borders on it, to say it's not really a text box.

仅冇旳回忆 2024-07-22 04:37:40

我知道它已经过时了很多年,但我讨厌发现仍然相关但没有解决方案的问题。 顺便说一句,您可能不想禁用它的原因是您无法轻松显示工具提示和自定义背景色(尽管这可以更轻松地解决)

无论如何,我找到了解决方案(感谢其他地方的其他人)我相信这个问题是这样问的。 我已经有一个 DateTimePicker 的自定义控件。

然后我添加了一个只读属性。 我的问题是在 VB.Net 项目中,

如果 Readonly = True,则覆盖 KeyDown 事件并标记为已处理。

Protected Overrides Sub OnKeyDown(e As KeyEventArgs)
  If mReadOnly Then
    e.Handled = True
  Else
    MyBase.OnKeyDown(e)
  End If
End Sub

这将处理箭头键和 F4 下拉键。

然后要禁用下拉列表,请覆盖 WndProc 方法:

Protected Overrides Sub WndProc(ByRef m As Message)
  '   m.Msg = 0x201 / &H201 = WM_LBUTTONDOWN
  '   m.Msg = 0x203 / &H203 = WM_LBUTTONDBLCLK
  If ReadOnly And (m.Msg = &H201 Or m.Msg = &H203) Then
    Return
  End If
  MyBase.WndProc(m)
End Sub

为了使其在我的 OnPaint 覆盖中看起来为只读,我有以下内容:

Protected Overrides Sub OnPaint(ByVal e As System.Windows.Forms.PaintEventArgs)

Dim g As Graphics = Me.CreateGraphics()

Dim dropDownIcon As Rectangle = New Rectangle(ClientRectangle.Width - 17, 0, 17, ClientRectangle.Height)
Dim b As Brush
Dim v As VisualStyles.ComboBoxState
Dim vn As ButtonState

b = New SolidBrush(Me.BackColor)

If Me.IsReadOnly Then
  v = VisualStyles.ComboBoxState.Disabled
  vn = ButtonState.Inactive
Else
  b = New SolidBrush(Me.BackColor)
    v = VisualStyles.ComboBoxState.Normal
    vn = ButtonState.Normal
  End If

'changed to only do this if the control is visible
If Me.Visible = True Then

  'colour rectangle
  g.FillRectangle(b, 0, 0, ClientRectangle.Width, ClientRectangle.Height)

  'for border 
  g.DrawRectangle(System.Drawing.SystemPens.ActiveBorder, 0, 0, ClientRectangle.Width - 1, ClientRectangle.Height - 1)

  'for text
  g.DrawString(Me.Text, Me.Font, New SolidBrush(Me.ForeColor), 0, 2)


  'we need to render the dropdown when visual styles is not turned on
  If ComboBoxRenderer.IsSupported Then
    ComboBoxRenderer.DrawDropDownButton(g, dropDownIcon, v)
  Else
    ControlPaint.DrawComboButton(g, dropDownIcon, vn)
  End If
End If

g.Dispose()
b.Dispose()
End Sub

I know it's years out of date but i hate finding problems that are still relevant with no solution. By the way, the reason you might not want to have it disabled is that you cannot easily display tooltips and custom backcolour (although this can be more easily worked around)

Anyway, I found the solution to this (thanks to others on here elsewhere) that i believe the question asks. I already had a custom control for DateTimePicker.

I then added a Readonly property. My problem was in a VB.Net proj

Override the KeyDown event and mark as handled if Readonly = True.

Protected Overrides Sub OnKeyDown(e As KeyEventArgs)
  If mReadOnly Then
    e.Handled = True
  Else
    MyBase.OnKeyDown(e)
  End If
End Sub

This takes care of the arrow keys and the F4 drop down key.

Then to disable the dropdown, override the WndProc method:

Protected Overrides Sub WndProc(ByRef m As Message)
  '   m.Msg = 0x201 / &H201 = WM_LBUTTONDOWN
  '   m.Msg = 0x203 / &H203 = WM_LBUTTONDBLCLK
  If ReadOnly And (m.Msg = &H201 Or m.Msg = &H203) Then
    Return
  End If
  MyBase.WndProc(m)
End Sub

To make it look Readonly in my OnPaint override, i have the following:

Protected Overrides Sub OnPaint(ByVal e As System.Windows.Forms.PaintEventArgs)

Dim g As Graphics = Me.CreateGraphics()

Dim dropDownIcon As Rectangle = New Rectangle(ClientRectangle.Width - 17, 0, 17, ClientRectangle.Height)
Dim b As Brush
Dim v As VisualStyles.ComboBoxState
Dim vn As ButtonState

b = New SolidBrush(Me.BackColor)

If Me.IsReadOnly Then
  v = VisualStyles.ComboBoxState.Disabled
  vn = ButtonState.Inactive
Else
  b = New SolidBrush(Me.BackColor)
    v = VisualStyles.ComboBoxState.Normal
    vn = ButtonState.Normal
  End If

'changed to only do this if the control is visible
If Me.Visible = True Then

  'colour rectangle
  g.FillRectangle(b, 0, 0, ClientRectangle.Width, ClientRectangle.Height)

  'for border 
  g.DrawRectangle(System.Drawing.SystemPens.ActiveBorder, 0, 0, ClientRectangle.Width - 1, ClientRectangle.Height - 1)

  'for text
  g.DrawString(Me.Text, Me.Font, New SolidBrush(Me.ForeColor), 0, 2)


  'we need to render the dropdown when visual styles is not turned on
  If ComboBoxRenderer.IsSupported Then
    ComboBoxRenderer.DrawDropDownButton(g, dropDownIcon, v)
  Else
    ControlPaint.DrawComboButton(g, dropDownIcon, vn)
  End If
End If

g.Dispose()
b.Dispose()
End Sub
橙幽之幻 2024-07-22 04:37:40

处理 DateTimePicker.MouseClick 事件并将 event.handled 设置为 true

handle the DateTimePicker.MouseClick Event and set the event.handled to true

无尽的现实 2024-07-22 04:37:40

只获取 Changed 事件并设置 e.Cancel = true 怎么样?

How about just picking up the Changed event and setting e.Cancel = true?

深空失忆 2024-07-22 04:37:40

这不是最好的方法,但这确实会阻止 keyUp 更新日期时间

public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();
    }

    private void Form1_Load(object sender, EventArgs e)
    {
    }

    private DateTime originalValue;

    private void dateTimePicker1_PreviewKeyDown(object sender, PreviewKeyDownEventArgs e)
    {
        originalValue = dateTimePicker1.Value;
    }

    private void dateTimePicker1_ValueChanged(object sender, EventArgs e)
    {
        dateTimePicker1.Value = originalValue;
    }
}

Not the nicest way to do it but this does stop the update of datetime by keyUp

public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();
    }

    private void Form1_Load(object sender, EventArgs e)
    {
    }

    private DateTime originalValue;

    private void dateTimePicker1_PreviewKeyDown(object sender, PreviewKeyDownEventArgs e)
    {
        originalValue = dateTimePicker1.Value;
    }

    private void dateTimePicker1_ValueChanged(object sender, EventArgs e)
    {
        dateTimePicker1.Value = originalValue;
    }
}
哆兒滾 2024-07-22 04:37:40
  1. 我们必须首先记住原始日期时间。

    过程 TForm1.dtpDateEnter(发件人: TObject); 
      开始 
        oldDtpDate := dtpDate.DateTime; 
      结尾; 
      
  2. 过程 TForm1.dtpDateClick(发件人: TObject);
    开始
    dtpDate.DateTime := oldDtpDate;
    结束;

    过程 TForm1.dtpDateExit(Sender: TObject); 
      开始 
        dtpDate.DateTime := oldDtpDate; 
      结尾; 
      
  1. We have to remember original datetime firstly.

    procedure TForm1.dtpDateEnter(Sender: TObject);
    begin
      oldDtpDate := dtpDate.DateTime;
    end;
    
  2. procedure TForm1.dtpDateClick(Sender: TObject);
    begin
    dtpDate.DateTime := oldDtpDate;
    end;

    procedure TForm1.dtpDateExit(Sender: TObject);
    begin
      dtpDate.DateTime :=  oldDtpDate;
    end;
    
原来分手还会想你 2024-07-22 04:37:40
this.dateTimePicker1.Enabled = false;

这是简单而完美的解决方案之一。

this.dateTimePicker1.Enabled = false;

It is one of the simple and perfect solutions.

℡寂寞咖啡 2024-07-22 04:37:40

继承自 DateTimePicker,您可以在必要时重写 WndProc 以将日期文本绘制为只读。

通过以下实现,您可以绑定到 ReadOnly,也可以选择绑定到 HasValue 以显示 (No date),在我看来,这是比内置 CheckBox 的默认行为更好。

using System.ComponentModel;
using System.Drawing;
using System.Runtime.InteropServices;
using System.Security.Permissions;

namespace System.Windows.Forms
{
    using SystemColors = System.Drawing.SystemColors;

    public class CtlDateTimePicker
        : DateTimePicker
    {
        bool m_hasValue = true;
        bool m_readOnly = false;

        public CtlDateTimePicker()
        {
            SetStyle(ControlStyles.ResizeRedraw | ControlStyles.OptimizedDoubleBuffer, true);
        }

        static CtlDateTimePicker()
        {
        }

        const int  WM_PAINT           = 0xF;
        const int  WM_REFLECT         = 0x2000;
        const int  WM_NOTIFY          = 0x004E;
        const uint DTN_DATETIMECHANGE = 0xFFFFFD09;

        [StructLayout(LayoutKind.Sequential)]
        private struct NMHDR
        {
            public IntPtr hwndFrom;
            public IntPtr idFrom;
            public uint   code;
        }

        [PermissionSet(SecurityAction.Demand, Name = "FullTrust")]
        protected override void WndProc(ref Message m)
        {
            base.WndProc(ref m);

            if (!DesignMode)
            {
                switch (m.Msg)
                {
                    case WM_PAINT:
                        PaintBorder();

                        break;

                    case WM_REFLECT + WM_NOTIFY:
                        NMHDR nm = (NMHDR)m.GetLParam(typeof(NMHDR));

                        if (nm.code == DTN_DATETIMECHANGE)
                            OnValueOrCheckedChanged();

                        break;
                }
            }
        }

        public event EventHandler ValueOrCheckedChanged;

        protected virtual void OnValueOrCheckedChanged()
        {
            if (ValueOrCheckedChanged != null)
                ValueOrCheckedChanged(this, EventArgs.Empty);
        }

        protected override void OnPaint(PaintEventArgs e)
        {
            base.OnPaint(e);

            var graphics        = e.Graphics;
            var clientRectangle = ClientRectangle;
            var font            = Font;
            var text            = m_hasValue ? Value.ToString("D") : "(No date)";
            var textSize        = TextRenderer.MeasureText(text, font);
            var textBounds      = DrawingHelper.AlignInRectangle(clientRectangle, textSize, ContentAlignment.MiddleLeft);

            graphics.FillRectangle(new SolidBrush(SystemColors.Control), ClientRectangle);

            PaintBorder(graphics);

            TextRenderer.DrawText(graphics, text, font, textBounds, GetTextColour());
        }

        private void PaintBorder(Graphics graphics = null)
        {
            var disposeGraphics = false;

            if (graphics == null)
            {
                graphics        = Graphics.FromHwndInternal(Handle);

                disposeGraphics = true;
            }

            var colour = Focused ? SystemColors.Highlight : SystemColors.ControlDark;

            ControlPaint.DrawBorder(graphics, ClientRectangle, colour, ButtonBorderStyle.Solid);

            if (disposeGraphics)
                graphics.Dispose();
        }

        private Color GetTextColour()
        {
            if (Enabled)
                return ForeColor;

            return SystemColors.GrayText;
        }

        [Category("Behavior")]
        [Bindable(true)]
        [DefaultValue(true)]
        public bool HasValue
        {
            get { return m_hasValue; }
            set
            {
                if (m_hasValue == value)
                    return;

                m_hasValue = value;

                SetStyle();
            }
        }

        [Category("Behavior")]
        [Bindable(true)]
        [DefaultValue(false)]
        public bool ReadOnly
        {
            get { return m_readOnly; }
            set
            {
                if (m_readOnly == value)
                    return;

                m_readOnly = value;

                SetStyle();
            }
        }

        private bool IsUserPaint
        {
            get
            {
                if (!m_hasValue)
                    return true;

                if (m_readOnly)
                    return true;

                return false;
            }
        }

        public void SetStyle()
        {
            if (DesignMode)
                return;

            var isUserPaint = IsUserPaint;

            if (GetStyle(ControlStyles.UserPaint) == isUserPaint)
                return;

            SetStyle(ControlStyles.UserPaint, isUserPaint);

            Invalidate();
        }
    }
}

Inheriting from DateTimePicker you can override WndProc to draw the date text read-only when necessary.

With the following implementation you can bind to ReadOnly, and optionally also bind to HasValue to show (No date) which, in my opinion, is better than the default behaviour with the built-in CheckBox.

Read-only date; Optional date unchecked; Optional date checked

using System.ComponentModel;
using System.Drawing;
using System.Runtime.InteropServices;
using System.Security.Permissions;

namespace System.Windows.Forms
{
    using SystemColors = System.Drawing.SystemColors;

    public class CtlDateTimePicker
        : DateTimePicker
    {
        bool m_hasValue = true;
        bool m_readOnly = false;

        public CtlDateTimePicker()
        {
            SetStyle(ControlStyles.ResizeRedraw | ControlStyles.OptimizedDoubleBuffer, true);
        }

        static CtlDateTimePicker()
        {
        }

        const int  WM_PAINT           = 0xF;
        const int  WM_REFLECT         = 0x2000;
        const int  WM_NOTIFY          = 0x004E;
        const uint DTN_DATETIMECHANGE = 0xFFFFFD09;

        [StructLayout(LayoutKind.Sequential)]
        private struct NMHDR
        {
            public IntPtr hwndFrom;
            public IntPtr idFrom;
            public uint   code;
        }

        [PermissionSet(SecurityAction.Demand, Name = "FullTrust")]
        protected override void WndProc(ref Message m)
        {
            base.WndProc(ref m);

            if (!DesignMode)
            {
                switch (m.Msg)
                {
                    case WM_PAINT:
                        PaintBorder();

                        break;

                    case WM_REFLECT + WM_NOTIFY:
                        NMHDR nm = (NMHDR)m.GetLParam(typeof(NMHDR));

                        if (nm.code == DTN_DATETIMECHANGE)
                            OnValueOrCheckedChanged();

                        break;
                }
            }
        }

        public event EventHandler ValueOrCheckedChanged;

        protected virtual void OnValueOrCheckedChanged()
        {
            if (ValueOrCheckedChanged != null)
                ValueOrCheckedChanged(this, EventArgs.Empty);
        }

        protected override void OnPaint(PaintEventArgs e)
        {
            base.OnPaint(e);

            var graphics        = e.Graphics;
            var clientRectangle = ClientRectangle;
            var font            = Font;
            var text            = m_hasValue ? Value.ToString("D") : "(No date)";
            var textSize        = TextRenderer.MeasureText(text, font);
            var textBounds      = DrawingHelper.AlignInRectangle(clientRectangle, textSize, ContentAlignment.MiddleLeft);

            graphics.FillRectangle(new SolidBrush(SystemColors.Control), ClientRectangle);

            PaintBorder(graphics);

            TextRenderer.DrawText(graphics, text, font, textBounds, GetTextColour());
        }

        private void PaintBorder(Graphics graphics = null)
        {
            var disposeGraphics = false;

            if (graphics == null)
            {
                graphics        = Graphics.FromHwndInternal(Handle);

                disposeGraphics = true;
            }

            var colour = Focused ? SystemColors.Highlight : SystemColors.ControlDark;

            ControlPaint.DrawBorder(graphics, ClientRectangle, colour, ButtonBorderStyle.Solid);

            if (disposeGraphics)
                graphics.Dispose();
        }

        private Color GetTextColour()
        {
            if (Enabled)
                return ForeColor;

            return SystemColors.GrayText;
        }

        [Category("Behavior")]
        [Bindable(true)]
        [DefaultValue(true)]
        public bool HasValue
        {
            get { return m_hasValue; }
            set
            {
                if (m_hasValue == value)
                    return;

                m_hasValue = value;

                SetStyle();
            }
        }

        [Category("Behavior")]
        [Bindable(true)]
        [DefaultValue(false)]
        public bool ReadOnly
        {
            get { return m_readOnly; }
            set
            {
                if (m_readOnly == value)
                    return;

                m_readOnly = value;

                SetStyle();
            }
        }

        private bool IsUserPaint
        {
            get
            {
                if (!m_hasValue)
                    return true;

                if (m_readOnly)
                    return true;

                return false;
            }
        }

        public void SetStyle()
        {
            if (DesignMode)
                return;

            var isUserPaint = IsUserPaint;

            if (GetStyle(ControlStyles.UserPaint) == isUserPaint)
                return;

            SetStyle(ControlStyles.UserPaint, isUserPaint);

            Invalidate();
        }
    }
}

绝不放开 2024-07-22 04:37:40

dateTimePicker2.Enabled = false;

dateTimePicker2.Enabled = false;

孤城病女 2024-07-22 04:37:40

尝试这个:

private void dateTimePicker1_ValueChanged(object sender, EventArgs e)
    {
        dateTimePicker1.Value = DateTime.Now;
    }

Try this:

private void dateTimePicker1_ValueChanged(object sender, EventArgs e)
    {
        dateTimePicker1.Value = DateTime.Now;
    }
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文