【问题标题】:Format TimeSpan in DataGridView column在 DataGridView 列中格式化 TimeSpan
【发布时间】:2010-09-02 14:09:43
【问题描述】:

我见过thesequestions,但两者都涉及在 CellStyle Format 值中不可用的方法。我只想显示小时和分钟部分(16:05);不是秒数(16:05:13)。我尝试将秒值强制为零,但仍然得到类似 16:05:00 的结果。没有使用像提供字符串或 DateTime(并且只显示小时/分钟部分)这样的组合,有什么方法可以让我做我想做的格式化。

【问题讨论】:

    标签: c# winforms datagridview formatting timespan


    【解决方案1】:

    这是我自己发现的。不幸的是,解决方案非常复杂。好消息是它有效。

    首先,您需要一个处理TimeSpan 值的ICustomFormatter 实现。 .NET 框架不包括这种开箱即用的类型;我猜测这是因为 Microsoft 不想处理格式化 TimeSpan 所涉及的歧义(例如,“hh”是指总小时数还是仅表示小时数部分?)和当这些歧义使开发人员感到困惑时,会出现大量支持问题。

    没关系 - 只需实现您自己的即可。下面是我编写的一个示例类,它基本上使用the same custom format strings as DateTime(无论如何都是适用的)*:

    class TimeSpanFormatter : IFormatProvider, ICustomFormatter
    {
        private Regex _formatParser;
    
        public TimeSpanFormatter()
        {
            _formatParser = new Regex("d{1,2}|h{1,2}|m{1,2}|s{1,2}|f{1,7}", RegexOptions.Compiled);
        }
    
        #region IFormatProvider Members
    
        public object GetFormat(Type formatType)
        {
            if (typeof(ICustomFormatter).Equals(formatType))
            {
                return this;
            }
    
            return null;
        }
    
        #endregion
    
        #region ICustomFormatter Members
    
        public string Format(string format, object arg, IFormatProvider formatProvider)
        {
            if (arg is TimeSpan)
            {
                var timeSpan = (TimeSpan)arg;
                return _formatParser.Replace(format, GetMatchEvaluator(timeSpan));
            }
            else
            {
                var formattable = arg as IFormattable;
                if (formattable != null)
                {
                    return formattable.ToString(format, formatProvider);
                }
    
                return arg != null ? arg.ToString() : string.Empty;
            }
        }
    
        #endregion
    
        private MatchEvaluator GetMatchEvaluator(TimeSpan timeSpan)
        {
            return m => EvaluateMatch(m, timeSpan);
        }
    
        private string EvaluateMatch(Match match, TimeSpan timeSpan)
        {
            switch (match.Value)
            {
                case "dd":
                    return timeSpan.Days.ToString("00");
                case "d":
                    return timeSpan.Days.ToString("0");
                case "hh":
                    return timeSpan.Hours.ToString("00");
                case "h":
                    return timeSpan.Hours.ToString("0");
                case "mm":
                    return timeSpan.Minutes.ToString("00");
                case "m":
                    return timeSpan.Minutes.ToString("0");
                case "ss":
                    return timeSpan.Seconds.ToString("00");
                case "s":
                    return timeSpan.Seconds.ToString("0");
                case "fffffff":
                    return (timeSpan.Milliseconds * 10000).ToString("0000000");
                case "ffffff":
                    return (timeSpan.Milliseconds * 1000).ToString("000000");
                case "fffff":
                    return (timeSpan.Milliseconds * 100).ToString("00000");
                case "ffff":
                    return (timeSpan.Milliseconds * 10).ToString("0000");
                case "fff":
                    return (timeSpan.Milliseconds).ToString("000");
                case "ff":
                    return (timeSpan.Milliseconds / 10).ToString("00");
                case "f":
                    return (timeSpan.Milliseconds / 100).ToString("0");
                default:
                    return match.Value;
            }
        }
    }
    

    我们还没有完成。有了这种类型,您就可以为您的 DataGridView 中的列分配一个自定义格式化程序,用于显示您的 TimeSpan 值。

    假设该列名为“时间”;那么你会这样做:

    DataGridViewColumn timeColumn = dataGridView.Columns["Time"];
    timeColumn.DefaultCellStyle.FormatProvider = new TimeSpanFormatter();
    timeColumn.DefaultCellStyle.Format = "hh:mm";
    

    所以现在你已经准备好了,对吧?

    嗯,出于某种奇怪的原因,您仍然没有 100% 完成目标。为什么自定义格式此时无法启动,老实说,我无法告诉您。但我们几乎完成了。最后一步是处理CellFormatting 事件以使我们编写的这个新功能真正生效:

    private void dataGridView_CellFormatting(object sender, DataGridViewCellFormattingEventArgs e)
    {
        var formatter = e.CellStyle.FormatProvider as ICustomFormatter;
        if (formatter != null)
        {
            e.Value = formatter.Format(e.CellStyle.Format, e.Value, e.CellStyle.FormatProvider);
            e.FormattingApplied = true;
        }
    }
    

    终于,我们完成了。设置您希望根据自定义规则格式化的DataGridViewColumn 的DefaultCellStyle.Format 属性现在应该可以按预期工作了。

    *所以,“h”/“hh”代表小时,“m”/“mm”代表分钟。等等

    【讨论】:

    • 您可能对为什么它不在框架中是正确的。这比我想象的要复杂得多,谢谢。
    • 完美运行。一颗心,谢谢。
    • 太棒了!您有使用此自定义格式化程序处理用户编辑的解决方案吗?
    • 从 .NET 4 开始,您可以(并且应该)使用 @David 的解决方案,请参阅 msdn.microsoft.com/en-us/library/ee372287(v=vs.100).aspx。
    【解决方案2】:

    使用CellFormatting事件也可以达到同样的效果。

    private void dataGridView_CellFormatting(object sender,
               DataGridViewCellFormattingEventArgs e)
    {
          if (e.Value != null && e.Value != DBNull.Value)
                e.Value =  ((TimeSpan)e.Value).Hours.ToString("00") + ":" +
                           ((TimeSpan)e.Value).Minutes.ToString("00");
    }
    

    这显然不是一个全面的解决方案,但很快。

    【讨论】:

    • 从 .NET 4 开始,这可以简化为直接格式化:if( e.ColumnIndex == idx && e.Value != null && e.Value != DBNull.Value ) { e.Value = ((TimeSpan) e.Value).ToString( "ddd\\.hh\\:mm\\:ss" ); },或者更好的是,将以下内容添加到 DataGridView 的初始化中:dgv.Columns[ idx ].DefaultCellStyle.Format= "ddd\\.hh\\:mm\\:ss";
    【解决方案3】:

    试试下面的代码

    dataGridView1.Columns["columnName"].DefaultCellStyle.Format = "hh\\:mm";
    

    【讨论】:

      【解决方案4】:

      我不知道如何将单元格的格式设置为仅显示小时和分钟。我建议您将单元格的格式设置为字符串并像这样格式化值:

      String.Format("{0:D2}:{1:D2}",
          DateTime.Now.TimeOfDay.Hours, DateTime.Now.TimeOfDay.Minutes);
      

      【讨论】:

        【解决方案5】:

        使用格式字符串"hh\\:mm"。 例如

        YourGrid.Column[index].DefaultCellStyle.Format = "hh\\:mm"
        

        【讨论】:

        • 发帖前请务必检查格式,以确保整个要点不会因对 Markdown 的误解而丢失。
        【解决方案6】:

        尝试另一种方法。只需添加到您的类绑定到 datagridview 属性,例如 LastPacketAtTimeDelayAsStr。

        假设你有一个拥有它的类...

        public DateTime? LastPacketAtTime { get; set; }
        
        public TimeSpan? LastPacketAtTimeDelay 
        { 
           get 
           {
                 if (LastPacketAtTime.HasValue)
                 {
                      var ts = DateTime.Now - LastPacketAtTime.Value;
                      return ts;
                 }
                 return null;
            }          
        }
        
        public string LastPacketAtTimeDelayAsStr
        {
             get
             {
                 if (LastPacketAtTimeDelay.HasValue)
                 {            
                     var hours = LastPacketAtTimeDelay.Value.Hours.ToString("00");
                     var minutes = LastPacketAtTimeDelay.Value.Minutes.ToString("00");
                     var seconds = LastPacketAtTimeDelay.Value.Seconds.ToString("00");
            
                   return $"{LastPacketAtTimeDelay.Value.Days} days {hours}:{minutes}:{seconds}";
                  }
                  return null;
              }
        }
        

        然后,只需将LastPacketAtTimeDelayAsStr 绑定到您需要的具有String 数据类型的DataGridView 列。

        就是这样!

        【讨论】:

          猜你喜欢
          • 2019-10-23
          • 2013-04-12
          • 1970-01-01
          • 2013-05-06
          • 1970-01-01
          • 2023-03-12
          • 2013-04-04
          • 1970-01-01
          • 2016-07-04
          相关资源
          最近更新 更多