5

我正在将一些应用程序代码转换为使用 NodaTime 类而不是 System.DateTime。我的应用程序的一部分使用 PropertyGrid 控件来允许用户编辑包含 LocalDate 和 Instant 的类。在不更改任何内容的情况下,PropertyGrid 可以正常显示属性,但它们不再可编辑。允许用户编辑这些字段的最佳方式是什么。

为了说明起见,我们可以使用这个类作为我想要显示和编辑的事物类型的代表:

public class User
{
    public string Name { get; set; }
    public LocalDate BirthDate { get; set; }
    public Instant NextAppointment { get; set; }
}
4

1 回答 1

4

到目前为止我想出的最好的:

第 1 步:创建 TypeConverter,以便 Noda 类可编辑

public class ToAndFromStringTypeConverter : TypeConverter
{
    public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
    {
        if (sourceType == typeof(string))
            return true;
        else
            return base.CanConvertFrom(context, sourceType);
    }
    public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
    {
        if (destinationType == typeof(string))
            return true;
        else
            return base.CanConvertTo(context, destinationType);
    }
}

public class LocalDateTypeConverter : ToAndFromStringTypeConverter
{
    public override object ConvertFrom(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value)
    {
        if (value is string)
        {
            DateTime parsed;
            if (!DateTime.TryParse((string)value, out parsed))
                throw new ArgumentException("Cannot convert '" + (string)value + "' to LocalDate.");
            else
                return new LocalDate(parsed.Year, parsed.Month, parsed.Day);
        }
        else
        {
            return base.ConvertFrom(context, culture, value);
        }
    }

    public override object ConvertTo(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value, Type destinationType)
    {
        if (destinationType == typeof(string))
        {
            var tvalue = (LocalDate)value;                
            try
            {
                var x = tvalue.ToString("yyyy-MM-dd");
                return x;
            }
            catch (NullReferenceException)
            {
                return "1900-1-1";
            }
            catch
            {
                throw new ArgumentException("Could not convert '" + value.ToString() + "' to LocalDate.");
            }                
        } 
        else 
            return base.ConvertTo(context, culture, value, destinationType);
    }

public class InstantTypeConverter : ToAndFromStringTypeConverter
{
    public override object ConvertFrom(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value)
    {
        if (value is string)
        {
            try
            {
                DateTime parsed = DateTime.Parse((string)value);
                LocalDateTime dt = LocalDateTime.FromDateTime(parsed);
                Instant i = dt.InZoneLeniently(DateTimeZoneProviders.Default.GetSystemDefault()).ToInstant();
                return i;
            }
            catch
            {
                throw new ArgumentException("Cannot convert '" + (string)value + "' to Instant.");
            }
        }
        else
        {
            return base.ConvertFrom(context, culture, value);
        }
    }

    public override object ConvertTo(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value, Type destinationType)
    {
        if (destinationType == typeof(string))
        {
            try
            {
                Instant tvalue = (Instant)value;
                LocalDateTime local = tvalue.InZone(DateTimeZoneProviders.Default.GetSystemDefault()).LocalDateTime;
                string output = LocalDateTimePattern.CreateWithInvariantCulture("yyyy-MM-dd HH:mm:ss.FFFFFF").Format(local);
                return output;
            }
            catch
            {
                throw new ArgumentException("Could not convert '" + value.ToString() + "' to LocalDate.");
            }                    
        }
        else
            return base.ConvertTo(context, culture, value, destinationType);
    }
}

第 2 步:注册 TypeConverters

将此代码放在应用程序的顶部:

TypeDescriptor.AddAttributes(typeof(LocalDate), new TypeConverterAttribute(typeof(LocalDateTypeConverter)));
TypeDescriptor.AddAttributes(typeof(Instant), new TypeConverterAttribute(typeof(InstantTypeConverter)));

第 3 步:使用自定义集合编辑器处理列表等内容

public class NodaCollectionEditor : System.ComponentModel.Design.CollectionEditor
{
    public NodaCollectionEditor(Type collection_type) : base(collection_type) { }

    protected override object CreateInstance(Type itemType)
    {
        if (itemType == typeof(LocalDate))
            return LocalDateHelper.MinValue;
        else 
            return base.CreateInstance(itemType);
    }
}

This can be registered by adding this attribute to any appropriate properties:

[System.ComponentModel.Editor(typeof(NodaCollectionEditor),typeof(System.Drawing.Design.UITypeEditor))]
于 2012-12-03T16:36:36.260 回答