基本上,我想将this helper添加到Razor。我尝试了什么:
public static class Html
{
static Dictionary<string[], int> _cycles;
static Html()
{
_cycles = new Dictionary<string[], int>();
}
public static string Cycle(this HtmlHelper helper, string[] options)
{
if (!_cycles.ContainsKey(options)) _cycles.Add(options, 0);
int index = _cycles[options];
_cycles[options] = (options.Length + 1) % options.Length;
return options[index];
}
用法:
<tr class="@Html.Cycle(new[]{"even","odd"})">
但它只是对每一行说“均匀”......不知道为什么。我不确定这个类何时被实例化.....是每个请求一次,每个服务器运行一次......还是什么?无论如何......我如何解决这个问题,以便提供预期的交替?
public static class Html
{
public static string Cycle(this HtmlHelper helper, params string[] options)
{
if(!helper.ViewContext.HttpContext.Items.Contains("cycles"))
helper.ViewContext.HttpContext.Items["cycles"] = new Dictionary<string[],int>(new ArrayComparer<string>());
var dict = (Dictionary<string[], int>)helper.ViewContext.HttpContext.Items["cycles"];
if (!dict.ContainsKey(options)) dict.Add(options, 0);
int index = dict[options];
dict[options] = (index + 1) % options.Length;
return options[index];
}
}
class ArrayComparer<T> : IEqualityComparer<T[]>
{
public bool Equals(T[] x, T[] y)
{
if (ReferenceEquals(x, y)) return true;
if (x == null || y == null) return false;
if (x.Length != y.Length) return false;
for (int i = 0; i < x.Length; ++i)
if (!x[i].Equals(y[i])) return false;
return true;
}
public int GetHashCode(T[] obj)
{
return obj.Length > 0 ? obj[0].GetHashCode() : 0;
}
}
这有什么问题吗?
答案 0 :(得分:2)
这是失败的原因,是因为你每次都使用一个全新的数组作为字典的关键。
我建议只包括一个额外的参数作为dictonary key。
为了上帝的缘故,请使用私人存储区。 (而不是static
成员,当多个线程点击页面时会爆炸。)
答案 1 :(得分:1)
对Cycle
方法的每次调用都会传递一个新的options
数组,并在字典中添加一个新密钥。
答案 2 :(得分:1)
要解决此问题和线程问题,您可以将字符串本身用作HttpContext中的键:
string key = "Cycle-"+String.Join("|", options);
if (!html.ViewContext.HttpContext.Items.Contains(key))
html.ViewContext.HttpContext.Items.Add(key, 0);
int index = html.ViewContext.HttpContext.Items[key];
html.ViewContext.HttpContext.Items[key] = (index + 1) % options.Length;
return options[index];
请注意,这将分享子操作和部分之间的循环。
答案 3 :(得分:0)
想出我也可以用@function
做到这一点......然后我就不需要将命名空间添加到Web.config
。
@using MvcApplication4.Helpers @* for ArrayComparer *@
@functions {
public static string Cycle(params string[] options)
{
if (!HttpContext.Current.Items.Contains("Html.Cycle"))
HttpContext.Current.Items["Html.Cycle"] = new Dictionary<string[], int>(new ArrayComparer<string>());
var dict = (Dictionary<string[], int>)HttpContext.Current.Items["Html.Cycle"];
if (!dict.ContainsKey(options)) dict.Add(options, 0);
int index = dict[options];
dict[options] = (index + 1) % options.Length;
return options[index];
}
}
也可以用@helper
来做,但我认为它不会那么干净。