我正在使用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友好的方式来实现自定义日历风格,我很乐意学习它。
答案 0 :(得分:4)
嗯,您没有看到显示值更改的原因是因为在DisplayDate
的getter中,您根本不使用_displayDate
值。所以你要改变_displayDate
,然后提高属性的变化,但之后它只是检索它之前所做的相同的字符串。
话虽如此,有一些基本因素需要考虑:
几乎任何语言或平台,以及.Net中的尤其,日期和时间类型都是作为值类型实现的。它们是不可变的结构。您的实现被设计为可变的,可观察的类。这是一个麻烦,因为你可能会传递它们的值类型语义。
除了只是作为字段的容器之外,值也是可排序的也很重要。这需要实施IComparable
。这也意味着幕后通常只有一个字段。例如,DateTime
只有一个字段,内部是64位整数。
如果您正在尝试实施“日历系统”的概念,还有很多需要考虑的问题。例如,你说一年是100天,但你没有在任何地方实现。你这几年的基础是什么?你在定义一个时代吗?如何从ISO8601或Gregorian日历系统等已知日历转换?几天会分解成其他尺寸,例如几周?你有“时区”还是每个人都使用相同的基础,比如UTC?我可以从字符串中解析您的格式吗?还有很多其他的。
如果您确实想要实施自定义日历系统。您可以选择两条路线:
延长System.Globalization.Calendar
- 一般来说不是很好,但可能会完成工作。
延长NodaTime.CalendarSystem
- 这是一个更好的主意,但你需要学习很多东西才能开始。大多数Noda Time都围绕着ISO日历。您可能需要在the Noda Time mailing list上提问。
答案 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,则会发生同样的情况。您最好在构造函数中执行所有验证。
不是说你不能拥有财产制定者,只是我不推荐它。但我想一个不可变的类型可能会给你带来可观察的麻烦?我不太了解可观察性。