Использование LINQ для построения иерархической навигации для ретранслятора

#c# #asp.net #linq #repeater

#c# #asp.net #linq #repeater

Вопрос:

Я пытаюсь вывести список элементов иерархической навигации из моей CMS следующим образом:

 YEAR
- MONTH
- - ARTICLE 1
- - ARTICLE 2
  

Страница оформлена так, что если вы находитесь на странице year, вы увидите:

 MONTH
- ARTICLE 1
- ARTICLE 2
  

Очевидно, что если вы находитесь на странице месяца, вы просто увидите ссылку на статьи

Я пытаюсь создать запрос LINQ для обработки логики, а затем встроить его в DataTable, который будет обрабатываться Repeater. Я действительно изо всех сил пытаюсь понять логику, чтобы я мог построить это правильным образом. Логически LINQ оказался самым простым способом смоделировать это, хотя сейчас у меня возникли другие мысли. Это код, который я придумал, чтобы получить годы и необходимые данные на данный момент.

 var linqYears = from year in contextItem.Children
                select new
                {
                    Name = year.Fields["page title"],
                    URI = Sitecore.Links.LinkManager.GetItemUrl(year)
                };
  

Что мне нужно сейчас, так это получить все месяцы за выбранный год, а затем все статьи и встроить их в repeater; Я предполагаю, что самый простой способ сделать это — с помощью DataTable / DataSet?

Буду признателен за любую помощь.

РЕДАКТИРОВАТЬ: Чтобы прояснить мою позицию:

Элемент contextItem — это страница, на которой я сейчас нахожусь. Если я нахожусь на корневой странице, а страница года находится подо мной, тогда contextItem.Дочерние элементы вернут всех дочерних элементов под ним. Например, учитывая эту навигацию, если я нахожусь в ROOT:

 ROOT
- YEAR
- - MONTH
- - - ARTICLE 1
- - - ARTICLE 2
  

Затем contextItem.Дочерними элементами будет коллекция, состоящая исключительно из YEAR

Комментарии:

1. Не могли бы вы предоставить общую структуру классов Year , Month и contextItem.Children ?

2. Я добавил еще немного, чтобы прояснить, что я делаю с кодом. Достаточно ли этого?

3. Вы имеете в виду, что хотите, чтобы LINQ-query динамически обрабатывал текущую позицию независимо от уровня в иерархии?

4. @Emil Badh: Да. Ваш код работает в корневом каталоге, и я верю, что он сработает, если я использую его в любом из подпунктов, но динамическое позиционирование определенно было бы полезно в коде, чтобы я не проверял элементы, которые, как я знаю, не будут существовать.

5. Я расширил свой ответ. Посмотрите, то ли это, что вам нужно и / или понятно.

Ответ №1:

Я не знаком с вашей структурой, но я предполагаю, что здесь это year тот же тип, что и contextItem . Если да, то это сработало бы:

 var linqYears = from year in contextItem.Children
                select new
                {
                    Name = year.Fields["page title"],
                    URI = Sitecore.Links.LinkManager.GetItemUrl(year),
                    Months = from month in year.Children
                             select new
                             {
                                 Name = month.Fields["page title"],
                                 URI = Sitecore.Links.LinkManager.GetItemUrl(month),
                                 Articles = from article in month.Children
                                            select new
                                            {
                                                Name = article.Fields["page title"],
                                                URI = Sitecore.Links.LinkManager.GetItemUrl(article)
                                            }
                             }
                };
  

Я не уверен насчет repeater, но рассматривали ли вы возможность использования ListView вместо этого? Если я не ошибаюсь, вы можете привязать это непосредственно к вашим анонимным типам. Это работает, только если вы, конечно, делаете этот выбор встроенным. В противном случае я бы рекомендовал создать класс, содержащий Name, URI и дочерние элементы, и заменить Months и Articles соответственно в приведенном выше коде на Children .

Надеюсь, это поможет.

РЕДАКТИРОВАТЬ: Чтобы заставить это решение работать независимо от вашего текущего положения в иерархии, вы могли бы сделать что-то вроде этого:

Сначала создайте класс для своих страниц.

 public class PageNode
{
    public string Name { get; set; }
    public Uri URI { get; set; }
    public List<PageNode> Children { get; set; } // This should be done with a private setter, but you get that...
}
  

Тогда вам нужны методы, подобные этому:

 public IEnumerable<PageNode> GetChildNodes(IEnumerable<ContextItem> children)
{
    return from c in children
           select new PageNode()
           {
               Name = c.Fields["page name"],
               URI = Sitecore.Links.LinkManager.GetItemUrl(c),
               Children = c.Children.Any() ? GetChildNodes(c.Children) : null
           };
}

public PageNode LoadNode(ContextItem item)
{
    return new PageNode()
           {
               Name = item.Fields["page name"],
               URI = Sitecore.Links.LinkManager.GetItemUrl(item),
               Children = item.Children.Any() ? GetChildNodes(item.Children) : null
           };
}
  

Комментарии:

1. Будь ты проклят, Эмиль, ты меня опередил 🙂

2. Оценка! 😛 Я сам часто это понимаю. Это сообщество чертовски полезно. 🙂

3. Спасибо за помощь; Я оставил для вас комментарий к комментариям к вопросу.