简体   繁体   English

在 DataGridView 列中格式化 TimeSpan

[英]Format TimeSpan in DataGridView column

I've seen these questions but both involve methods that aren't available in the CellStyle Format value.我见过 这些问题,但都涉及在 CellStyle Format 值中不可用的方法。 I only want to show the hours and minutes portion (16:05);我只想显示小时和分钟部分(16:05); not the seconds as well (16:05:13).也不是秒 (16:05:13)。 I tried forcing the seconds value to zero but still got something like 16:05:00.我尝试将秒值强制为零,但仍然得到类似 16:05:00 的结果。 Short of using a kludge like providing a string or a DateTime (and only showing the hour/minutes part) is there any way I can get the formatting to do what I want.没有使用像提供字符串或日期时间这样的混搭(并且只显示小时/分钟部分),有什么方法可以让我按照我想要的方式进行格式化。

I just discovered this myself.这是我自己才发现的。 Unfortunately, the solution is pretty involved.不幸的是,解决方案非常复杂。 The good news is that it works.好消息是它有效。

Firstly, you need an ICustomFormatter implementation that deals with TimeSpan values.首先,您需要一个处理TimeSpan值的ICustomFormatter实现。 The .NET framework does not include such a type out-of-the-box; .NET 框架不包括这种开箱即用的类型; I am guessing this is because Microsoft didn't want to have to deal with the ambiguity involved in formatting a TimeSpan (eg, does "hh" mean total hours or only the hour component?) and the ensuing onslaught of support issues that would arise when these ambiguities confused developers.这是因为 Microsoft 不想处理格式化TimeSpan涉及的歧义(例如,“hh”是指总小时数还是仅指小时数?)以及随之而来的大量支持问题当这些歧义使开发人员感到困惑时。

That's OK -- just implement your own.没关系 - 只需实现您自己的。 Below is a sample class I wrote that uses basically the same custom format strings as DateTime (those that were applicable, anyway)*:下面是我编写的一个示例类,它使用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;
        }
    }
}

We're not finished yet.我们还没有完成。 With this type in place, you are equipped to assign a custom formatter to the column in your DataGridView that you want to use for displaying your TimeSpan values.有了这种类型,您就可以将自定义格式化程序分配给DataGridView中要用于显示TimeSpan值的列。

Let's say that column is called "Time";假设该列称为“时间”; then you would do this:那么你会这样做:

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

So now you're set up, right?所以现在你设置好了,对吧?

Well, for some odd reason, you're still not 100% of the way there.好吧,出于某种奇怪的原因,您仍然没有 100% 到达那里。 Why custom formatting can't kick in at this point, I honestly couldn't tell you.为什么此时自定义格式无法启动,老实说,我无法告诉您。 But we're almost done.但我们完成了。 The one final step is to handle the CellFormatting event to get this new functionality we've written to actually take effect:最后一步是处理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;
    }
}

At last, we're finished.最后,我们完成了。 Setting the DefaultCellStyle.Format property of the DataGridViewColumn you want formatted according to your custom rules should now work as expected.设置要根据自定义规则格式化的DataGridViewColumnDefaultCellStyle.Format属性现在应该可以按预期工作。

*So, "h"/"hh" for hours, "m"/"mm" for minutes. *因此,“h”/“hh”表示小时,“m”/“mm”表示分钟。 etc.等。

It is possible to achieve the effect same by just using the CellFormatting event.仅使用 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");
}

This obviously is not as comprehensive a solution, but quite quick.这显然不是一个全面的解决方案,但相当快。

试试下面的代码

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

I don't know how to set the format of the cell to show only hours and minutes.我不知道如何将单元格的格式设置为仅显示小时和分钟。 I'd suggest you set the format of the cell to string and format the value like this:我建议您将单元格的格式设置为字符串并设置如下格式的值:

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

Use format string "hh\\\\:mm" .使用格式字符串"hh\\\\:mm" eg例如

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

Try another approach.尝试另一种方法。 Just add to your class binding to the datagridview properties like for instance LastPacketAtTimeDelayAsStr .只需添加到您的类绑定到 datagridview 属性,例如LastPacketAtTimeDelayAsStr

Let's say you have some class that has it...假设你有一些课程有它......

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;
      }
}

And after that just bind the LastPacketAtTimeDelayAsStr to the DataGridView column you need which has String datatype.之后,只需将LastPacketAtTimeDelayAsStr绑定到您需要的具有String数据类型的DataGridView列。

And that's it!就是这样!

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM