Как я могу создать «циклический» помощник для Razor? - PullRequest
0 голосов
/ 04 декабря 2011

По сути, я хочу добавить этот помощник в 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"})">

Но он просто говорит "даже" для каждого ряда ... не знаю почему.Я не уверен, когда создается экземпляр этого класса ..... это один раз для запроса, один раз для запуска сервера ... или что?Независимо от того ... как бы я исправить это так, чтобы он дал предполагаемое чередование?


Попытка # 2

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;
    }
}

Любая проблема с этим?

Ответы [ 4 ]

2 голосов
/ 04 декабря 2011

Причина, по которой это не удается, заключается в том, что вы каждый раз используете новый массив в качестве ключа к словарю.

Я бы порекомендовал просто включить дополнительный параметр для использования в качестве диктонического ключа.

И ради бога , пожалуйста, используйте личное хранилище. (Вместо элемента static, который будет взорван, когда несколько страниц попадут на страницу.)

1 голос
/ 04 декабря 2011

Чтобы исправить это и проблему с потоками, вы можете использовать сами строки в качестве ключей в 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];

Обратите внимание, что это будет делить циклы между дочерними действиями и разделами.

1 голос
/ 04 декабря 2011

Каждый вызов вашего метода Cycle передает новый массив options, добавляя новый ключ в словарь.

0 голосов
/ 04 декабря 2011

Понял, что я мог бы сделать это и с @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 но я не думаю, что это будет так же чисто.

...