如何在 WPF 中将 DatePicker 添加到 DataGridTextColumn

Posted

技术标签:

【中文标题】如何在 WPF 中将 DatePicker 添加到 DataGridTextColumn【英文标题】:How to add a DatePicker to DataGridTextColumn in WPF 【发布时间】:2013-09-11 20:53:51 【问题描述】:
<DataGrid Name="myfirstdg"
          Grid.Row="2"
          AutoGenerateColumns="False"
          CanUserSortColumns="False"
          CanUserAddRows="False"
          CanUserDeleteRows="False"
          SelectionUnit="Cell">
    <DataGrid.Columns>
        <DataGridTextColumn Header="Date"
                            Binding="Binding Path=date"
                            Width="SizeToCells"
                            IsReadOnly="True"
                            MinWidth="100"/>
    </DataGrid.Columns>
</DataGrid>

我有一个简单的DataGrid,里面有一个DataGridTextColumn。如何将Datepicker 添加到我的DataGridTextColumn

【问题讨论】:

使用DataGridTemplateColumn 【参考方案1】:

正如 Nitesh 所说,使用 DataGridTemplateColumn

<DataGridTemplateColumn Header="Pick a Date">
    <DataGridTemplateColumn.CellTemplate>
        <DataTemplate>
            <TextBlock Text="Binding myDate" />
        </DataTemplate>
    </DataGridTemplateColumn.CellTemplate>
    <DataGridTemplateColumn.CellEditingTemplate>
        <DataTemplate>
            <DatePicker SelectedDate="Binding myDate" />
        </DataTemplate>
    </DataGridTemplateColumn.CellEditingTemplate>
</DataGridTemplateColumn>

【讨论】:

一点用处都没有。 这可能有效,但它似乎不是复制/粘贴工作,因为myDate 超出范围 - 所有其他列都可以在 DataGrid 绑定的上下文中定义,但是在此模板中,DataContext 发生变化,myDate 无法解析。我想获得正确的绑定上下文是另一个故事 我不知道你的问题出在哪里,但这个答案对我很有用。数据上下文没有问题。【参考方案2】:

我在数据网格的每一列中都放置了一个 DatePicker,这是我在 windows 构造函数中分配给 DataGrid 的辅助方法。此方法还可以取消在 DataGrid 中显示效果不佳的复杂对象的生成。

随心所欲!

public MainWindow()

    InitializeComponent();
    myDataGrid.AutoGeneratingColumn += DataGridUtilities.dataGrid_AutoGeneratingColumn;


public static class DataGridUtilities

    public static void dataGrid_AutoGeneratingColumn(object sender, DataGridAutoGeneratingColumnEventArgs e)
    
        if (!IsTypeOrNullableOfType(e.PropertyType, typeof(string))
            && !IsNullableOfValueType(e.PropertyType))
        
            e.Cancel = true;
        
        else if (IsTypeOrNullableOfType(e.PropertyType, typeof (DateTime)))
        
            DataGridTemplateColumn col = new DataGridTemplateColumn();
            col.Header = e.Column.Header;
            FrameworkElementFactory datePickerFactoryElem = new FrameworkElementFactory(typeof (DatePicker));
            Binding dateBind= new Binding(e.PropertyName);
            dateBind.UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged;
            dateBind.Mode = BindingMode.TwoWay;
            datePickerFactoryElem.SetValue(DatePicker.SelectedDateProperty, dateBind);
            datePickerFactoryElem.SetValue(DatePicker.DisplayDateProperty, dateBind);
            DataTemplate cellTemplate = new DataTemplate();
            cellTemplate.VisualTree = datePickerFactoryElem;
            col.CellTemplate = cellTemplate;
            e.Column = col;//Set the new generated column
        
    


    private static bool IsTypeOrNullableOfType(Type propertyType, Type desiredType)
    
        return (propertyType == desiredType || Nullable.GetUnderlyingType(propertyType) == desiredType);
    

    private static bool IsNullableOfValueType(Type propertyType)
    
        return (propertyType.IsValueType ||
                (Nullable.GetUnderlyingType(propertyType) != null &&
                 Nullable.GetUnderlyingType(propertyType).IsValueType));
    

【讨论】:

【参考方案3】:

这建立在@Guish 的答案之上,但将其封装到一个新的列类中。

private void Grid_AutoGeneratingColumn(object sender, DataGridAutoGeneratingColumnEventArgs e)

    if (e.PropertyType == typeof(DateTime))
    
        e.Column = new DataGridDateTimeColumn((DataGridBoundColumn)e.Column);
    


internal class DataGridDateTimeColumn : DataGridBoundColumn

    public DataGridDateTimeColumn(DataGridBoundColumn column)
    
        Header = column.Header;
        Binding = (Binding)column.Binding;
    

    protected override FrameworkElement GenerateElement(DataGridCell cell, object dataItem)
    
        var control = new TextBlock();
        BindingOperations.SetBinding(control, TextBlock.TextProperty, Binding);
        return control;
    

    protected override FrameworkElement GenerateEditingElement(DataGridCell cell, object dataItem)
    
        var control = new DatePicker();
        control.PreviewKeyDown += Control_PreviewKeyDown;
        BindingOperations.SetBinding(control, DatePicker.SelectedDateProperty, Binding);
        BindingOperations.SetBinding(control, DatePicker.DisplayDateProperty, Binding);
        return control;
    

    private void Control_PreviewKeyDown(object sender, System.Windows.Input.KeyEventArgs e)
    
        if (e.Key == System.Windows.Input.Key.Return)
        
            DataGridOwner.CommitEdit();
        
    

【讨论】:

绝妙的答案,让它真正伟大的是它采用高度可重用的形式!如果我们可以指定是否在 TextBlock 中显示仅“日期”部分(尝试使用日期表字段并获得时间),或者更好的是能够设置绑定的 StringFormat,那将更有价值. 我也注意到了一些其他的事情,如果你去编辑日期,[Enter] 键不再起作用(它不会提交更改),你当然可以关注另一个字段或行,但这对用户来说有点奇怪。 [Tab]/[BackTab] 确实有效。 @Constantine Georgiou,我用 [Enter] 键解决了这个问题。感谢您的报告。

以上是关于如何在 WPF 中将 DatePicker 添加到 DataGridTextColumn的主要内容,如果未能解决你的问题,请参考以下文章

如何在 WPF 中将项目添加到 ListView

如何在 wpf 中将新行添加到数据网格中?

如何在 iOS7 中将 UIDatePicker 添加到 UIALertView

Wpf DatePicker 水印修改为中文

在 vuetify.js 中将 Header 设置为 DatePicker

如何使用 Expression Blend 在 WPF 中编辑 DatePicker 的水印