WPF数据表格中的日期格式化

75

我想要改变的是日期列的格式,从"DD/MM/YYYY HH:MM:SS"改为"DD.MM.YYYY"。

  <DataGrid Name="dgBuchung" AutoGenerateColumns="True" 
            ItemsSource="{Binding}" Grid.ColumnSpan="3" >
  <ab:DataGridTextColumn Header="Fecha Entrada" Width="110"  
       Binding="{Binding date, StringFormat={}{0:dd/MM/yyyy}}" IsReadOnly="True" />
                        
</DataGrid>
                                      

不幸的是,该代码会抛出XMLParseException异常。

首先,如果使用AutoGenerateColumns,这种解决方法是否可行?如果不行,我还能尝试什么其他方式来处理?

如果可以,那么上面的代码有什么问题?

7个回答

141

不要忘记使用DataGrid.Columns,所有列都必须在该集合内。 在我的项目中,我对日期进行了略微不同的格式化:

<tk:DataGrid>
    <tk:DataGrid.Columns>
        <tk:DataGridTextColumn Binding="{Binding StartDate, StringFormat=\{0:dd.MM.yy HH:mm:ss\}}" />
    </tk:DataGrid.Columns>
</tk:DataGrid>

使用AutoGenerateColumns,您将无法控制格式,因为DataGrid将添加其自己的列。


1
@Harald,不,你不能直接绑定到数据库字段,首先你必须创建或生成一些对象(例如,使用Entity Framework)。如果你已经有了这样的对象集合,那么你可以像你在代码中所做的那样将其绑定到DataGrid.ItemsSource属性。 - icebat
如果StringFormat取决于文化吗?例如,En-US:dd.MM.yy,FR:dd-MM-yyyy,ES-es:dd/MM/yyyy等。 - Kiquenet
1
@Kiquenet,如果您对每个文化都有一些自定义格式,则最好将该逻辑移动到转换器或属性获取器中。否则,可以查看一些更多的选项,使用自定义日期格式 - icebat
这个字符串格式中的零字符是干什么用的?它是必需的,但我真的搞不清楚为什么。在C#中格式化普通字符串时,我通常会使用*dateTime.ToString("dd MMM")*来获取"08 Jul"。但在这里似乎有所不同,我不确定该搜索什么... - Konrad Viltersten
1
@KonradViltersten,这是一个索引,用于在应用StringFormat时使用string.Format - icebat
显示剩余4条评论

115

虽然来晚了,但如果有人偶然发现这个页面,我想说...

你可以通过在XAML中设置AutoGeneratingColumn处理程序来实现:

<DataGrid AutoGeneratingColumn="OnAutoGeneratingColumn"  ..etc.. />

然后在代码后端做如下操作:

private void OnAutoGeneratingColumn(object sender, DataGridAutoGeneratingColumnEventArgs e)
{
    if (e.PropertyType == typeof(System.DateTime))
        (e.Column as DataGridTextColumn).Binding.StringFormat = "dd/MM/yyyy";
}

3
太好了!如果你需要VB.NET版本:Private Sub MyGrid_AutoGeneratingColumn(sender As Object, e As DataGridAutoGeneratingColumnEventArgs) handles MyGrid.AutoGeneratingColumn 如果e.PropertyType = GetType(System.DateTime) Then TryCast(e.Column, DataGridTextColumn).Binding.StringFormat = "dd/MM/yyyy" End If End Sub - Andrea Antonangeli
(e.Column as DataGridTextColumn).Binding.StringFormat = "d"; // 使用短日期格式 - Gordon Bell
使用 e.PropertyName 以不同的格式设置日期列:如果 (e.PropertyName == "Open_Date") { (e.Column as DataGridTextColumn).Binding.StringFormat = "d"; } - Gordon Bell
你是一个英雄 :) 这正是我正在寻找的。虽然你不必添加带绑定的单个列。 - LuckyLikey
3
为了更通用,我建议您使用DataGridBoundColumn而不是DataGridTextColumn - JohnyL
显示剩余2条评论

18
如果您的绑定属性是DateTime,那么您所需要的只有:

Binding={Property, StringFormat=d}

运行得非常好。需要格式化,但不会干扰系统格式。 - Kshitij

8
Binding="{Binding YourColumn ,StringFormat='yyyy-MM-dd'}"

5
请添加代码的说明,这将极大地提高答案的质量。 - Nic3500

2

首先选择数据网格,然后进入属性找到“Datagrid_AutoGeneratingColumn”,双击打开。接着使用以下代码:

   Datagrid_AutoGeneratingColumn(object sender, DataGridAutoGeneratingColumnEventArgs e)
            {
                if (e.PropertyName == "Your column name")
                    (e.Column as DataGridTextColumn).Binding.StringFormat = "dd/MMMMMMMMM/yyyy";
                if (e.PropertyName == "Your column name")
                    (e.Column as DataGridTextColumn).Binding.StringFormat = "dd/MMMMMMMMM/yyyy";
            }

我尝试在WPF上使用它,结果成功了。


虽然我在我的项目中使用Mark Feldman,但是你的解决方案非常有用,特别是当你有不同类型的属性并且想要为每个属性设置不同的格式时。 - Antonio Rodríguez

1
我知道被接受的答案相当老旧,但是有一种方法可以通过AutoGeneratColumns控制格式:
首先创建一个函数,在生成列时会触发:
<DataGrid x:Name="dataGrid" AutoGeneratedColumns="dataGrid_AutoGeneratedColumns" Margin="116,62,10,10"/>

然后检查生成的列的类型是否为 DateTime,只需将其字符串格式更改为“d”,以删除时间部分:
private void DataGrid_AutoGeneratingColumn(object sender, DataGridAutoGeneratingColumnEventArgs e)
        {
            if(YourColumn == typeof(DateTime))
            {
                e.Column.ClipboardContentBinding.StringFormat = "d";
            }
        }

2
那就是Mark Feldman已经回答过的。 - Antonio Rodríguez

1

这是一个很老的问题,但我找到了一个新的解决方案,所以我写了一篇文章介绍它。

首先,使用AutoGenerateColumns的情况下,这种解决方法可行吗?

是的,可以使用AttachedProperty来实现。

<DataGrid AutoGenerateColumns="True" 
   local:DataGridOperation.DateTimeFormatAutoGenerate="yy-MM-dd"
   ItemsSource="{Binding}" />

附加属性

有两个定义的附加属性允许您指定两个格式。 DateTimeFormatAutoGenerate 用于 DateTimeTimeSpanFormatAutoGenerate 用于 TimeSpan

class DataGridOperation
{
    public static string GetDateTimeFormatAutoGenerate(DependencyObject obj) => (string)obj.GetValue(DateTimeFormatAutoGenerateProperty);
    public static void SetDateTimeFormatAutoGenerate(DependencyObject obj, string value) => obj.SetValue(DateTimeFormatAutoGenerateProperty, value);
    public static readonly DependencyProperty DateTimeFormatAutoGenerateProperty =
        DependencyProperty.RegisterAttached("DateTimeFormatAutoGenerate", typeof(string), typeof(DataGridOperation),
            new PropertyMetadata(null, (d, e) => AddEventHandlerOnGenerating<DateTime>(d, e)));

    public static string GetTimeSpanFormatAutoGenerate(DependencyObject obj) => (string)obj.GetValue(TimeSpanFormatAutoGenerateProperty);
    public static void SetTimeSpanFormatAutoGenerate(DependencyObject obj, string value) => obj.SetValue(TimeSpanFormatAutoGenerateProperty, value);
    public static readonly DependencyProperty TimeSpanFormatAutoGenerateProperty =
        DependencyProperty.RegisterAttached("TimeSpanFormatAutoGenerate", typeof(string), typeof(DataGridOperation),
            new PropertyMetadata(null, (d, e) => AddEventHandlerOnGenerating<TimeSpan>(d, e)));

    private static void AddEventHandlerOnGenerating<T>(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        if (!(d is DataGrid dGrid))
            return;

        if ((e.NewValue is string format))
            dGrid.AutoGeneratingColumn += (o, e) => AddFormat_OnGenerating<T>(e, format);
    }

    private static void AddFormat_OnGenerating<T>(DataGridAutoGeneratingColumnEventArgs e, string format)
    {
        if (e.PropertyType == typeof(T))
            (e.Column as DataGridTextColumn).Binding.StringFormat = format;
    }
}

如何使用
查看
<Window
   x:Class="DataGridAutogenerateCustom.MainWindow"
   xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
   xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
   xmlns:local="clr-namespace:DataGridAutogenerateCustom"
   Width="400" Height="250">
   <Window.DataContext>
      <local:MainWindowViewModel />
   </Window.DataContext>
   <StackPanel>
      <TextBlock Text="DEFAULT FORMAT" />
      <DataGrid ItemsSource="{Binding Dates}" />

      <TextBlock Margin="0,30,0,0" Text="CUSTOM FORMAT" />
      <DataGrid
         local:DataGridOperation.DateTimeFormatAutoGenerate="yy-MM-dd"
         local:DataGridOperation.TimeSpanFormatAutoGenerate="dd\-hh\-mm\-ss"
         ItemsSource="{Binding Dates}" />
   </StackPanel>
</Window>

视图模型

public class MainWindowViewModel
{
    public DatePairs[] Dates { get; } = new DatePairs[]
    {
        new (){StartDate= new (2011,1,1), EndDate= new (2011,2,1) },
        new (){StartDate= new (2020,1,1), EndDate= new (2021,1,1) },
    };
}

public class DatePairs
{
    public DateTime StartDate { get; set; }
    public DateTime EndDate { get; set; }
    public TimeSpan Span => EndDate - StartDate;
}

{{链接1:演示_wpf_datagrid}}


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接