Episerver:将父页面文件夹/媒体文件夹合并为单个Content Reference属性
通用解决方案:支持页面/媒体文件夹的单一ContentReference属性
要实现单一属性支持选择页面文件夹或媒体文件夹,同时兼容两者的子项展示,可以按以下步骤改造现有代码:
1. 修改ContentReference属性定义
将原有ParentPage属性改为通用的文件夹选择属性,通过AllowedTypes限制仅允许选择文件夹类型(Episerver中PageFolder和MediaFolder均实现IContentFolder接口):
[CultureSpecific] [Display( Name = "Parent Folder", Description = "Select a page or media folder to display links to its child items.", GroupName = SystemTabNames.Content, Order = 10)] [AllowedTypes(typeof(IContentFolder))] // 允许选择所有文件夹类型 public virtual ContentReference ParentFolder { get; set; }
这样在编辑界面中,用户可以直接切换页面树和媒体树选择对应文件夹,无需额外新增属性。
2. 重构MenuItem类以支持通用内容
原有MenuItem仅绑定PageData,需改为支持IContent以兼容页面和媒体:
public class MenuItem { public IContent Content { get; set; } public string Target { get; set; } // 保留原有属性(如IsActive、HasChildren等),按需调整逻辑 }
3. 改造MenuList辅助方法
修改方法逻辑,使其能够根据文件夹类型获取对应子项,并分别处理页面和媒体的过滤规则:
public static IHtmlString MenuList(this HtmlHelper helper, ContentReference rootLink, Func<List<MenuItem>, IHtmlString> itemTemplate, bool requireVisibleInMenu = true, bool requirePageTemplate = true) { rootLink = rootLink ?? ContentReference.StartPage; var currentContentLink = helper.ViewContext.RequestContext.GetContentLink(); var pagePath = _contentLoader.Service.GetAncestors(currentContentLink) .Reverse() .Select(x => x.ContentLink) .SkipWhile(x => !x.CompareToIgnoreWorkID(rootLink)) .ToList(); // 获取文件夹下的所有子内容(兼容页面和媒体) var children = _contentLoader.Service.GetChildren<IContent>(rootLink); // 根据内容类型过滤:页面沿用原有规则,媒体可自定义规则 var filteredChildren = children.Where(content => { if (content is PageData page) { return page.FilterForDisplay(requirePageTemplate, requireVisibleInMenu); } else if (content is MediaData media) { // 示例:允许所有媒体显示,可按需添加过滤(如自定义可见性属性) return true; } return false; }).ToList(); // 生成MenuItem列表 var menuItems = filteredChildren .Select((content, index) => CreateMenuItem(content, currentContentLink, pagePath, requirePageTemplate, requireVisibleInMenu, index)) .ToList(); return itemTemplate(menuItems); }
4. 更新CreateMenuItem方法
调整该方法以处理PageData和MediaData两种类型:
private static MenuItem CreateMenuItem(IContent content, ContentReference currentContentLink, List<ContentReference> pagePath, bool requirePageTemplate, bool requireVisibleInMenu, int index) { var menuItem = new MenuItem { Content = content }; if (content is PageData page) { // 沿用原有页面逻辑:设置目标、判断活跃状态等 menuItem.Target = page.LinkTarget; menuItem.IsActive = pagePath.Contains(page.ContentLink.CompareToIgnoreWorkID); } else if (content is MediaData media) { // 媒体专属逻辑:默认新窗口打开,无需判断活跃状态(当前请求为页面) menuItem.Target = "_blank"; menuItem.IsActive = false; } return menuItem; }
5. 调整视图代码
在视图中根据内容类型渲染对应的链接:
@if (Model.ParentFolder != null) { @Html.MenuList(Model.ParentFolder, @<text> @foreach (var menuItem in item) { <li class="link-list__item"> @if (menuItem.Content is PageData page) { <a class="link-list__link" href="@Url.ContentUrl(page.ContentLink)" target="@menuItem.Target">@page.Name</a> } else if (menuItem.Content is MediaData media) { <a class="link-list__link" href="@Url.ContentUrl(media.ContentLink)" target="@menuItem.Target">@media.Name</a> } </li> } </text>) }
额外优化建议
- 编辑器体验:默认ContentReference选择器已支持切换页面/媒体树,若需更直观操作可自定义编辑器添加快速切换按钮,但多数场景下默认编辑器足够使用。
- 媒体过滤规则:可给MediaData添加
VisibleInList自定义属性,在过滤时判断该值实现精细控制。 - 权限校验:可在过滤逻辑中添加权限检查,确保当前用户能读取所选文件夹的子项。
内容的提问来源于stack exchange,提问作者Farhin Shaikh
相关产品推荐
相关产品推荐

