如何在不重复 C# 代码的情况下在 ViewModel 上创建可变长度下拉列表?
How do I create a variable length dropdown list on a ViewModel without repeating code in c#?
我是新手开发人员,我需要用日期填充下拉列表,以便网站访问者可以选择它们来检索某些数据。
该列表不寻常,因为它必须从上个月到一年前向后填充。因此,上个月将是列表中的第一个条目,然后是之前的每个月。例如,如果今天是 2017 年 7 月 5 日,则下拉列表将如下所示:
Jun 2017
May 2017
Apr 2017
Mar 2017
Feb 2017
Jan 2017
Dec 2016
and so on . . .
列表每个月都会变长,所以我无法为列表编写固定长度的代码。我想出了以下代码,但它无法构建:
[RequireLogin]
public ActionResult Index()
{
bool firstItem = true;
int x = -1;
int y = 1;
int daysFromStartDate = beginDate.Date.Subtract(currentDate).Days;
List<SelectListItem> items = new List<SelectListItem>();
while (daysFromStartDate >= 30)
{
DateTime previousMonth = DateTime.Now.Date.AddMonths(x);
string pMonth = previousMonth.ToString("MMM");
string pYear = previousMonth.ToString("YYYY");
Int32.TryParse(pMonth, out thisMonth);
Int32.TryParse(pYear, out thisYear);
if (firstItem)
firstItem = false;
SelectListItem item[y] = new SelectListItem() { Text = pMonth + " " + pYear, Value = pMonth, Selected = true }; //<- #1
else
SelectListItem item[y]= new SelectListItem() { Text = pMonth + " " + pYear, Value = pMonth, Selected = false }; //<- #2
items.Add(item[y]); //<- #3
x = x--;
y = y++;
}
ViewBag.MonthList = items;
return View();
}
我在“item”变量上遇到了几个构建错误,我不知道如何修复它们:
1 - 错误的数组声明符:要声明托管数组,等级说明符位于变量标识符之前。要声明固定大小的缓冲区字段,请在字段类型之前使用 fixed 关键字。变量声明中不能指定数组大小(尝试用 'new' 表达式初始化)
2 – 在此范围内已经定义了一个名为“item”的局部变量(我知道我需要摆脱重复,但这只是我整体逻辑问题的一个症状)。
3 – 无法将带有 [] 的索引应用于 SelectListItem
类型的表达式
显然,c# 不喜欢我尝试在我的列表项上使用索引,如 "item[y]"。我以为我很聪明,但是这种方法完全是炸弹。
我搜索了这个站点和 Internet,并阅读了我找到的所有示例,但找不到符合我需要的解决方案。任何人都可以就如何修复此逻辑提供一些指导吗?
我相信我已经彻底解释了这个问题,但如果我不够准确或不够清晰,请提前接受我的道歉。我很乐意回应有关更多信息的请求。
*******QUESTION EDIT***********
这是一个粘性的(无论如何对我来说)。然而,Vlad Stryapko 让我走上了正确的轨道,几个星期后,我得到了他的解决方案(我接受了)。还有一个问题,但与我原来的 post 无关,所以我将 post 单独提出一个问题。这是我的最终代码:
我的视图模型
public SelectList MonthList { get; set; }
public SelectList ReverseMonthsLists()
{
var stringViewOfDates = GetDates().Select(_ => _.ToString("MMM yyyy")).ToList();
var list = new List<SelectListItem>();
list.Add(new SelectListItem { Selected = true, Text = stringViewOfDates[0], Value = stringViewOfDates[0] });
for (int i = 1; i < stringViewOfDates.Count(); i++)
{
list.Add(new SelectListItem { Selected = false, Text = stringViewOfDates[i], Value = stringViewOfDates[i] });
}
var selectList = new SelectList(list);
return selectList;
}
public static IEnumerable<DateTime> GetDates()
{
DateTime startDate = new DateTime(2017, 6, 1).Date;
var currentDate = DateTime.Now.Date;
int numberOfMonthsToShow = (currentDate.Year - startDate.Year) * 12 + currentDate.Month - startDate.Month;
if (numberOfMonthsToShow == 0)
numberOfMonthsToShow = 1;
var dates = new List<DateTime>(numberOfMonthsToShow);
for (int i = 0; i < numberOfMonthsToShow; i++)
{
dates.Add(currentDate);
currentDate = currentDate.AddMonths(-1);
}
return dates;
}
我的Html查看
@Html.DropDownList("selectList", Model.ReverseMonthsLists(), "Month Selector")
代码现在可以编译,但我得到的只是下拉列表中的 "System.Web.Mvc.SelectListItem"。我会在另一个线程中提出这个问题,因为我不相信我可以在这里问第二个问题。
我还不太了解您的需要,下面是一个示例,说明如何构建从当前日期开始并包含 12 个月的日期列表。
public static IEnumerable<DateTime> GetDates()
{
var currentDate = DateTime.Now;
var numberOfMonthsToShow = 12;
var dates = new List<DateTime>(numberOfMonthsToShow);
for (int i = 0; i < numberOfMonthsToShow; i++)
{
dates.Add(currentDate);
currentDate = currentDate.AddMonths(-1);
}
return dates;
}
如果要从上个月开始,将currentDate初始化为DateTime.Now.AddMonths(-1)
接下来,您必须构建这些日期的字符串表示形式。对于您的格式,请使用 Y 格式选择器。
var stringViewOfDates = GetDates().Select(_ => _.ToString("MMM yyyy"));
现在您已经有了字符串,可以将它们添加到 SelectList 中。我现在没有 ASP.NET MVC,但它应该很简单。类似于:
var list = new List<SelectListItem>();
list.Add(new SelectListItem { Selected = true, Text = stringViewOfDates[0], Value = stringViewOfDates[0]})
for (int i = 1; i < stringView.Count(); i++)
{
list.Add(new SelectListItem { Selected = false, Text = stringViewOfDates[i], Value = stringViewOfDates[i]);
}
var selectList = new SelectList(list);
您有很多代码对于 'give me previous months' 的任务来说似乎是多余的。请尝试我提供的代码或解释为什么您需要如此复杂的代码。我可能漏掉了你的一些逻辑。
给定一个通用函数来获取日期列表:-
public static IEnumerable<string> ReverseMonthList(string format, DateTime start, int count)
{
return Enumerable.Range(0, count).Select(n => start.AddMonths(-(n + 1)).ToString(format));
}
然后
var from = new DateTime(2016, 7, 5);
var now = new DateTime(2017, 7, 5);
var monthsSinceStart = ((now.Year - @from.Year) * 12) + now.Month - @from.Month;
var dates = ReverseMonthList("MMM yyyy", now, monthsSinceStart);
给予
The list is unusual because it must populate backward from last month up until a year ago.
这很容易做到。首先 - 生成日期。您有开始日期(上个月)和所需的总月数 (12)。然后将每个日期投影到 SelectListItem
:
var today = DateTime.Today;
var startOfMonth = new DateTime(today.Year, today.Month, 1);
var items = from i in Enumerable.Range(1, 12)
let date = startOfMonth.AddMonths(-i)
select new SelectListItem {
Text = date.ToString("MMM yyyy"),
Value = date.ToString("MMM"),
Selected = i == 1
};
ViewBag.MonthList = items.ToList();
备注:
- 您应该计算相对于当月开始的日期。否则,2 月 29 日可能会有问题。
- 使用字符串格式以您想要的格式生成日期。不要格式化日期的部分并将它们连接起来。
- 年份格式字符串为小写
yyyy
SelectListItem item[y] = ...
是不正确的语法。它是赋值和声明的混合体。如果你想在列表中分配一个项目,那么你应该通过索引 item[y] = ...
来引用该项目。但是您应该先检查列表是否包含足够的项目。实际上你真正需要做的是在列表中添加一个项目,这是通过 items.Add(...)
. 实现的
- 考虑学习 LINQ - 它允许您编写查询(以声明方式)以轻松过滤、投影等数据
这是一个控制台应用程序
var startDate = DateTime.Now.Date;
var days = new List<Tuple<string, string>>();
int totalMonths = 12;
for (int i = 1; i < totalMonths; i++)
{
var tempDay = startDate.AddMonths(-i);
days.Add(new Tuple<string, string>($"{tempDay.ToString("MMM")} {tempDay.ToString("yyyy")}", tempDay.ToString("MMM")));
}
foreach (var d in days)
{
Console.WriteLine(d.Item1);
}
输出
2017 年 6 月
2017 年 5 月
2017 年 4 月
2017 年 3 月
2017 年 2 月
2017 年 1 月
2016 年 12 月
2016 年 11 月
2016 年 10 月
2016 年 9 月
2016 年 8 月
出于测试目的,我使用了 tuple。使用列表项 class。对于项目选择,使用单独的循环或在生成方法中使用 if 条件。
使用 LINQ 并倒退:
var ans = Enumerable.Range(1, 12).Select(p => start.AddMonths(-p).ToString("MMM yy")).ToList();
我是新手开发人员,我需要用日期填充下拉列表,以便网站访问者可以选择它们来检索某些数据。
该列表不寻常,因为它必须从上个月到一年前向后填充。因此,上个月将是列表中的第一个条目,然后是之前的每个月。例如,如果今天是 2017 年 7 月 5 日,则下拉列表将如下所示:
Jun 2017
May 2017
Apr 2017
Mar 2017
Feb 2017
Jan 2017
Dec 2016
and so on . . .
列表每个月都会变长,所以我无法为列表编写固定长度的代码。我想出了以下代码,但它无法构建:
[RequireLogin]
public ActionResult Index()
{
bool firstItem = true;
int x = -1;
int y = 1;
int daysFromStartDate = beginDate.Date.Subtract(currentDate).Days;
List<SelectListItem> items = new List<SelectListItem>();
while (daysFromStartDate >= 30)
{
DateTime previousMonth = DateTime.Now.Date.AddMonths(x);
string pMonth = previousMonth.ToString("MMM");
string pYear = previousMonth.ToString("YYYY");
Int32.TryParse(pMonth, out thisMonth);
Int32.TryParse(pYear, out thisYear);
if (firstItem)
firstItem = false;
SelectListItem item[y] = new SelectListItem() { Text = pMonth + " " + pYear, Value = pMonth, Selected = true }; //<- #1
else
SelectListItem item[y]= new SelectListItem() { Text = pMonth + " " + pYear, Value = pMonth, Selected = false }; //<- #2
items.Add(item[y]); //<- #3
x = x--;
y = y++;
}
ViewBag.MonthList = items;
return View();
}
我在“item”变量上遇到了几个构建错误,我不知道如何修复它们:
1 - 错误的数组声明符:要声明托管数组,等级说明符位于变量标识符之前。要声明固定大小的缓冲区字段,请在字段类型之前使用 fixed 关键字。变量声明中不能指定数组大小(尝试用 'new' 表达式初始化)
2 – 在此范围内已经定义了一个名为“item”的局部变量(我知道我需要摆脱重复,但这只是我整体逻辑问题的一个症状)。
3 – 无法将带有 [] 的索引应用于 SelectListItem
类型的表达式显然,c# 不喜欢我尝试在我的列表项上使用索引,如 "item[y]"。我以为我很聪明,但是这种方法完全是炸弹。
我搜索了这个站点和 Internet,并阅读了我找到的所有示例,但找不到符合我需要的解决方案。任何人都可以就如何修复此逻辑提供一些指导吗?
我相信我已经彻底解释了这个问题,但如果我不够准确或不够清晰,请提前接受我的道歉。我很乐意回应有关更多信息的请求。
*******QUESTION EDIT***********
这是一个粘性的(无论如何对我来说)。然而,Vlad Stryapko 让我走上了正确的轨道,几个星期后,我得到了他的解决方案(我接受了)。还有一个问题,但与我原来的 post 无关,所以我将 post 单独提出一个问题。这是我的最终代码:
我的视图模型
public SelectList MonthList { get; set; }
public SelectList ReverseMonthsLists()
{
var stringViewOfDates = GetDates().Select(_ => _.ToString("MMM yyyy")).ToList();
var list = new List<SelectListItem>();
list.Add(new SelectListItem { Selected = true, Text = stringViewOfDates[0], Value = stringViewOfDates[0] });
for (int i = 1; i < stringViewOfDates.Count(); i++)
{
list.Add(new SelectListItem { Selected = false, Text = stringViewOfDates[i], Value = stringViewOfDates[i] });
}
var selectList = new SelectList(list);
return selectList;
}
public static IEnumerable<DateTime> GetDates()
{
DateTime startDate = new DateTime(2017, 6, 1).Date;
var currentDate = DateTime.Now.Date;
int numberOfMonthsToShow = (currentDate.Year - startDate.Year) * 12 + currentDate.Month - startDate.Month;
if (numberOfMonthsToShow == 0)
numberOfMonthsToShow = 1;
var dates = new List<DateTime>(numberOfMonthsToShow);
for (int i = 0; i < numberOfMonthsToShow; i++)
{
dates.Add(currentDate);
currentDate = currentDate.AddMonths(-1);
}
return dates;
}
我的Html查看
@Html.DropDownList("selectList", Model.ReverseMonthsLists(), "Month Selector")
代码现在可以编译,但我得到的只是下拉列表中的 "System.Web.Mvc.SelectListItem"。我会在另一个线程中提出这个问题,因为我不相信我可以在这里问第二个问题。
我还不太了解您的需要,下面是一个示例,说明如何构建从当前日期开始并包含 12 个月的日期列表。
public static IEnumerable<DateTime> GetDates()
{
var currentDate = DateTime.Now;
var numberOfMonthsToShow = 12;
var dates = new List<DateTime>(numberOfMonthsToShow);
for (int i = 0; i < numberOfMonthsToShow; i++)
{
dates.Add(currentDate);
currentDate = currentDate.AddMonths(-1);
}
return dates;
}
如果要从上个月开始,将currentDate初始化为DateTime.Now.AddMonths(-1)
接下来,您必须构建这些日期的字符串表示形式。对于您的格式,请使用 Y 格式选择器。
var stringViewOfDates = GetDates().Select(_ => _.ToString("MMM yyyy"));
现在您已经有了字符串,可以将它们添加到 SelectList 中。我现在没有 ASP.NET MVC,但它应该很简单。类似于:
var list = new List<SelectListItem>();
list.Add(new SelectListItem { Selected = true, Text = stringViewOfDates[0], Value = stringViewOfDates[0]})
for (int i = 1; i < stringView.Count(); i++)
{
list.Add(new SelectListItem { Selected = false, Text = stringViewOfDates[i], Value = stringViewOfDates[i]);
}
var selectList = new SelectList(list);
您有很多代码对于 'give me previous months' 的任务来说似乎是多余的。请尝试我提供的代码或解释为什么您需要如此复杂的代码。我可能漏掉了你的一些逻辑。
给定一个通用函数来获取日期列表:-
public static IEnumerable<string> ReverseMonthList(string format, DateTime start, int count)
{
return Enumerable.Range(0, count).Select(n => start.AddMonths(-(n + 1)).ToString(format));
}
然后
var from = new DateTime(2016, 7, 5);
var now = new DateTime(2017, 7, 5);
var monthsSinceStart = ((now.Year - @from.Year) * 12) + now.Month - @from.Month;
var dates = ReverseMonthList("MMM yyyy", now, monthsSinceStart);
给予
The list is unusual because it must populate backward from last month up until a year ago.
这很容易做到。首先 - 生成日期。您有开始日期(上个月)和所需的总月数 (12)。然后将每个日期投影到 SelectListItem
:
var today = DateTime.Today;
var startOfMonth = new DateTime(today.Year, today.Month, 1);
var items = from i in Enumerable.Range(1, 12)
let date = startOfMonth.AddMonths(-i)
select new SelectListItem {
Text = date.ToString("MMM yyyy"),
Value = date.ToString("MMM"),
Selected = i == 1
};
ViewBag.MonthList = items.ToList();
备注:
- 您应该计算相对于当月开始的日期。否则,2 月 29 日可能会有问题。
- 使用字符串格式以您想要的格式生成日期。不要格式化日期的部分并将它们连接起来。
- 年份格式字符串为小写
yyyy
SelectListItem item[y] = ...
是不正确的语法。它是赋值和声明的混合体。如果你想在列表中分配一个项目,那么你应该通过索引item[y] = ...
来引用该项目。但是您应该先检查列表是否包含足够的项目。实际上你真正需要做的是在列表中添加一个项目,这是通过items.Add(...)
. 实现的
- 考虑学习 LINQ - 它允许您编写查询(以声明方式)以轻松过滤、投影等数据
这是一个控制台应用程序
var startDate = DateTime.Now.Date;
var days = new List<Tuple<string, string>>();
int totalMonths = 12;
for (int i = 1; i < totalMonths; i++)
{
var tempDay = startDate.AddMonths(-i);
days.Add(new Tuple<string, string>($"{tempDay.ToString("MMM")} {tempDay.ToString("yyyy")}", tempDay.ToString("MMM")));
}
foreach (var d in days)
{
Console.WriteLine(d.Item1);
}
输出 2017 年 6 月 2017 年 5 月 2017 年 4 月 2017 年 3 月 2017 年 2 月 2017 年 1 月 2016 年 12 月 2016 年 11 月 2016 年 10 月 2016 年 9 月 2016 年 8 月
出于测试目的,我使用了 tuple。使用列表项 class。对于项目选择,使用单独的循环或在生成方法中使用 if 条件。
使用 LINQ 并倒退:
var ans = Enumerable.Range(1, 12).Select(p => start.AddMonths(-p).ToString("MMM yy")).ToList();