我有很多复选框,目前我想将它们放在包含每列的div的3列中。
然而,我非常反复无常,可能希望明天将它们放在10或20列中,我可能希望将其旋转为行或任何其他类型的div。
3列的示例:
<div class="column-1">
<input type="checkbox" id="foo-1">Checkbox # 1
<input type="checkbox" id="foo-2">Checkbox # 2
<input type="checkbox" id="foo-3">Checkbox # 3
</div>
<div class="column-2">
<input type="checkbox" id="foo-4">Checkbox # 4
<input type="checkbox" id="foo-5">Checkbox # 5
<input type="checkbox" id="foo-6">Checkbox # 6
</div>
<div class="column-3">
<input type="checkbox" id="foo-7">Checkbox # 7
<input type="checkbox" id="foo-8">Checkbox # 8
<input type="checkbox" id="foo-9">Checkbox # 9
</div>
我首先尝试使用3 while循环执行此操作,如下所示:
@{
int i = 0;
IEnumerable<foo> bar = new List<foo>(){foo1,foo2,foo3,foo4,foo5,foo6};
}
<div id="column-1">
while (i < bar.Count() / 3)
{
baz = bar.ElementAt(i);
<input type="checkbox" id="foo-@i" checked='@baz.CheckIt' />@baz.DisplayText
i++;
}
</div>
<div id="column-2">
@while (i < bar.Count() * 2 / 3)
{
baz = bar.ElementAt(i);
<input type="checkbox" id="foo-@i" checked='@baz.CheckIt' />@baz.DisplayText
i++;
}
</div>
<div id="column-3">
@while (i < bar.Count())
{
baz = bar.ElementAt(i);
<input type="checkbox" id="foo-@i" checked='@baz.CheckIt' />@baz.DisplayText
i++;
}
</div>
这样可以正常工作,但如果我想使用超过3列,则会非常难看。老实说,这已经非常丑陋了。它也不允许容易更改列数。它也可以更改为for循环,每个循环以不同的值(分别为0,1,2)开始,并将i
增加3,但这仍然是3个循环。
我也尝试在一个循环中使用一些模数运算符(伪代码)执行此操作:
i = 0
foreach(checkbox in list)
{
if(i % numberOfColumns == 0)
{
createNewRow()
}
placeCheckBox()
i++
}
在我看来,这更加简洁和可读。然而,这会产生大量的行div,这不适合我的目的。还有一个问题,实际上让复选框在div内。上面的两个解决方案可以组合起来创建列而不是行,这看起来更好,但仍然存在与第二个解决方案相同的问题。
我觉得必须有一个更简单,更好的方法来做到这一点,而不必硬编码列的数量,因为没有人想要编写20个基本的while循环。
那么,是否有一种可扩展且简洁的方法来为列表中的每个项目生成html标记,这些列表分成多个div?如果是这样的话是什么?
答案 0 :(得分:4)
这会将一个IE的数量分成T的IEnumerable of Tnumerable。(也许我应该只返回数组。)如果你给它100并将它分成三组,你将获得34组。前33组将有3个元素,最后一组将有一个。
public static IEnumerable<IEnumerable<T>> SplitIntoSetsOfSpecifiedLength<T>
(this IEnumerable<T> source, int itemsPerSet) // naming is hard
{
var sourceArray = source as T[] ?? source.ToArray();
var result = new List<IEnumerable<T>>();
for (var index = 0; index < sourceArray.Length; index += itemsPerSet)
{
result.Add(sourceArray.Skip(index).Take(itemsPerSet));
}
return result;
}
为了说明,给定一个输入,它是1到20之间的数字列表,
var splitIntoThreeLists = oneToTwenty.SplitIntoSetsOfSpecifiedLength(7);
将返回三组:
1 8 15
2 9 16
3 10 17
4 11 18
5 12 19
6 13 20
7 14
单元测试
[TestMethod]
public void splits_20_into_sets_of_seven()
{
var values = Enumerable.Range(1, 20);
var splitValues = values.SplitIntoSetsOfSpecifiedLength(7).ToList();
// three sets
Assert.AreEqual(splitValues.Count(), 3);
// the first set contains the first seven numbers.
Assert.IsTrue(splitValues[0].SequenceEqual(Enumerable.Range(1, 7)));
// the second set contains the next seven numbers
Assert.IsTrue(splitValues[1].SequenceEqual(Enumerable.Range(8, 7)));
// the third set contains the last six
Assert.IsTrue(splitValues[2].SequenceEqual(Enumerable.Range(15, 6)));
}
答案 1 :(得分:3)
使用相当简单的嵌套循环解决它(为了清楚起见,可能应将其更改为while
。
这将按顺序遍历列表并按顺序遍历,每次只达到numberOfColumns
的一小部分时停止。然后它创建一个新列并递增分数以获得下一部分项目。
@{
int numberOfColumns = 3;
int currentItemIndex = 0;
for (int currentColumnIndex = 1; currentColumnIndex <= numberOfColumns; currentColumnIndex++)
{
//Create a new column
<div id="column-@currentColumnIndex">
//Loop populate column with items
@while (currentItemIndex < bar.Count() * currentColumnIndex / numberOfColumns)
{
baz = bar.ElementAt(currentItemIndex);
//Add each item
<input type="checkbox" id="foo-@currentItemIndex" checked='@baz.CheckIt' />@baz.DisplayText
currentItemIndex++;
}
</div>
}
}
两列的分步示例:
如果你创建numberOfColumns = 2
,外部循环将执行两次。在第一次执行时,内部循环一直持续到currentItemIndex
等于bar.Count() * 1 / 2
,或bar.Count()
的一半,这是第一列中我们项目的一半。然后它迭代到外循环的下一个阶段,将内循环的最大计数器增加到bar.Count()
,因为计数器仍然设置为bar.Count()
的一半,这将放置我们项目的后半部分在第二栏。瞧!