3

我正在使用 MVVM 在 WPF 中开发一个项目,我想在其中使用虚构的日历。我希望这一年有 100 天长,只需分成 2 个季节而不是几个月。据我所知,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
}

在视图模型中:

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”设置器会触发,但这就是发生的一切。

我想这不是解决这个问题的好方法。如果有人有一种对 MVVM 友好的方式来实现自定义日历样式,我很想学习它。

4

2 回答 2

4

好吧,您看不到显示值更改的原因是因为在 的 getter 中DisplayDate,您根本不使用该_displayDate值。因此,您正在更改_displayDate, 然后引发该属性已更改,但随后它只会检索与之前相同的字符串。

话虽如此,您需要考虑一些基本面:

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

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

  • 如果您尝试实现“日历系统”的概念,还有很多需要考虑的事情。例如,您说一年有 100 天,但您没有在任何地方实现它。你这些年的依据是什么?你在定义一个时代吗?如何从已知日历(例如 ISO8601 或公历系统)转换?天是否会分解为其他大小,例如周?您是否有“时区”或者每个人都使用相同的基准,例如 UTC?我可以从字符串中解析您的格式吗?还有很多其他的。

如果你真的想实现一个自定义的日历系统。你可以走两条路:

于 2013-06-24T18:51:06.113 回答
0

我建议您在内部使用 anint来表示这一天。对于每一天,将值增加 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,则会发生同样的事情。您最好在构造函数中进行所有这些验证。

并不是说你不能有属性设置器,只是我不推荐它。但我认为不可变类型可能会给您带来可观察的麻烦?我对 observable 的了解还不够多。

于 2013-06-24T18:44:13.357 回答