实现虚构的日历格式

时间:2013-06-24 16:44:54

标签: c# calendar

我正在使用MVVM在WPF中开展一个项目,其中我想使用虚构的日历。我希望这一年有100天的时间,只需要分成两个季节而不是几个月。据我所知,DateTime无法做到这一点,我自己实施它有些麻烦(主要是我认为我的方法远非理想)。任何你可以给我的建议,将有助于使这项工作将不胜感激。

public enum Season { Dry, Rainy }
public class Date : ObservableObject
{
    #region Members

    private int _year;
    private int _dayOfYear;
    private Season _season;
    private string _displayDate;

    #endregion

    #region Properties

    public int Year
    {
        get { return _year; }
        set { _year = value; }
    }

    public int DayOfYear
    {
        get { return _dayOfYear; }
        set 
        {
            if (_dayOfYear == value)
                return;
            _dayOfYear = value;
            RaisePropertyChanged(() => DayOfYear);
        }
    }

    public Season Season
    {
        get
        {
            if (_dayOfYear < 70)
                return Models.Season.Dry;
            else
                return Models.Season.Rainy;
        }
        set { _season = value; }
    }

    public string DisplayDate
    {
        get
        {
            return (_dayOfYear.ToString() + " Season of " + _season.ToString() + " " + _year.ToString());
        }
        set
        {
            if (_displayDate == value)
                return;
            _displayDate = value;
            RaisePropertyChanged(() => DisplayDate);
        }
    }

    #endregion
}

在viewmodel中:

public string Date
{
    get { return DataManager.Data.Date.DisplayDate; }
    set
    {
        if (DataManager.Data.Date.DisplayDate == value)
            return;
        DataManager.Data.Date.DisplayDate = value;
        RaisePropertyChanged(() => Date);
    }
}

UI将显示字符串但从不更新它。当我更新日期时,“DayOfYear”setter会触发,但就是这样。

我认为这不是一个很好的方法。如果有人有MVVM友好的方式来实现自定义日历风格,我很乐意学习它。

2 个答案:

答案 0 :(得分:4)

嗯,您没有看到显示值更改的原因是因为在DisplayDate的getter中,您根本不使用_displayDate值。所以你要改变_displayDate,然后提高属性的变化,但之后它只是检索它之前所做的相同的字符串。

话虽如此,有一些基本因素需要考虑:

  • 几乎任何语言或平台,以及.Net中的尤其,日期和时间类型都是作为值类型实现的。它们是不可变的结构。您的实现被设计为可变的,可观察的类。这是一个麻烦,因为你可能会传递它们的值类型语义。

  • 除了只是作为字段的容器之外,值也是可排序的也很重要。这需要实施IComparable。这也意味着幕后通常只有一个字段。例如,DateTime只有一个字段,内部是64位整数。

  • 如果您正在尝试实施“日历系统”的概念,还有很多需要考虑的问题。例如,你说一年是100天,但你没有在任何地方实现。你这几年的基础是什么?你在定义一个时代吗?如何从ISO8601或Gregorian日历系统等已知日历转换?几天会分解成其他尺寸,例如几周?你有“时区”还是每个人都使用相同的基础,比如UTC?我可以从字符串中解析您的格式吗?还有很多其他的。

如果您确实想要实施自定义日历系统。您可以选择两条路线:

答案 1 :(得分:0)

我建议您在内部使用int代表当天。对于每一天,将值增加1.然后,要计算年份,您有:

int year = day/100;

赛季:

Season season = (day % 100) < 70 ? Season.Dry : Season.Rainy;

它看起来像这样:

public class MyCustomDate
{
    private int _day;

    public int Year
    {
        get { return _day / 100; }
    }

    public Season Season
    {
        get { return (DayOfYear < 70) ? Season.Dry : Season.Rainy; }
    }

    public int DayOfYear
    {
        get { return _day % 100; }
    }

    // Create a date, given the year and the day within the year.
    public MyCustomDate(int year, int day)
    {
        _day = (100 * year) + day;
    }

    public override string ToString()
    {
        return string.Format("{0} {1}, {2}", DayOfYear, Season, Year);
    }
}

您可以添加其他属性和方法来计算两个日期之间的差异,创建日期,季节和年份的日期,将日期添加到日期等。关键是要在几天内完成所有计算。只使用季节和年份进行输入和输出。

我建议您使自定义类不可变。如果你使它变得可变(例如你可以设置Season),那么你必须添加大量的验证码。考虑55 Dry 2012的日期。如果您将季节更改为Rainy,则您的日期无效,因为雨季只有30天。如果您尝试将日期设置为大于99,则会发生同样的情况。您最好在构造函数中执行所有验证。

不是说你不能拥有财产制定者,只是我不推荐它。但我想一个不可变的类型可能会给你带来可观察的麻烦?我不太了解可观察性。