5

System.DateTime の代わりに NodaTime クラスを使用するように一部のアプリケーション コードを変換しています。私のアプリケーションの一部では、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: Noda クラスが編集可能になるように TypeConverter を作成する

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: カスタム コレクション エディターを使用して List などを処理する

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

これは、この属性を適切なプロパティに追加することで登録できます。

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