DotVVM - Code only component DataSource 属性 传入collection时为null

DotVVM - Code only component DataSource property is null when collection is passed in

我有自己的 Accordion 纯代码组件

这是我的视图,其中我有加载 list of article sections 的转发器。每个文章部分有 list of articles。因此,我想实现每个文章部分都有自己的手风琴,其中将包含 articles。这就是为什么我把它放在 repeater

<div class="box box-primary">
    <dot:Repeater DataSource="{{value: AccordionList}}">
        <ItemTemplate>
            <coc:Accordion DataSource="{{value: Articles}}"></coc:Accordion>
        </ItemTemplate>
    </dot:Repeater>       
</div>

手风琴代码组件。我的 DataSource 始终为空,即使我清楚地看到 AccordionList 包含永远不会为空的 List of Articles,但从未传递到我的 DataSource 中。当我将 AccordionList 的类型更改为 ArticleListDTO 并将其直接传递到我的 Accordion 组件时,它运行良好,但这不是我想要的。

public class Accordion : HtmlGenericControl
{
    public Accordion() : base("div")
    {
    }
    public static readonly DotvvmProperty DataSourceProperty;
    static Accordion()
    {
           DataSourceProperty = DotvvmProperty.Register<List<ArticleListDTO>, Accordion>(c=>c.DataSource); 
    }
    //DataSource is always null
    public List<ArticleListDTO> DataSource
    {
        get => (List<ArticleListDTO>)GetValue(DataSourceProperty);
        set => SetValue(DataSourceProperty, value);
    } 

    protected override void AddAttributesToRender(IHtmlWriter writer, IDotvvmRequestContext context)
    {
        Attributes.Add("class", "accordion");

        base.AddAttributesToRender(writer, context);
    }

    public void DataBind(IDotvvmRequestContext context)
    {
        Children.Clear();
        foreach (var item in DataSource)
        {
            DataBindItem(this, item, context);
        }
    }....etc

视图模型

public List<ArticleSectionListDTO> AccordionList { get; set; } = new List<ArticleSectionListDTO>();
public List<ArticleSectionListDTO> AccordionListUnsorted { get; set; } = new List<ArticleSectionListDTO>();

protected override void OnItemLoading()
{
    AccordionListUnsorted = Task.Run(() => articleSectionFacade.GetAllNotModifiedArticleSections()).Result;

    AccordionList = Task.Run(() => articleSectionFacade.CreateTree(AccordionListUnsorted, null)).Result.ToList();
}

DTO - 我删除了其余属性以使其清晰

public class ArticleListDTO
{
    public string Name { get; set; }

    public int? ParentArticleId { get; set; }
    public bool HasCategories => AssignedToArticle?.Count > 0;
    public List<ArticleListDTO> AssignedToArticle { get; set; }
    //Can contain sub articles
    public List<ArticleListDTO> Articles { get; set; } = new List<ArticleListDTO>();
}

public class ArticleSectionListDTO : ListDTO
{
    public string Name { get; set; }

    public int? ParentArticleSectionId { get; set; }
    public bool HasCategories => AssignedToMenuItem?.Count > 0;
    public List<ArticleSectionListDTO> AssignedToMenuItem { get; set; }
    public List<ArticleListDTO> Articles { get; set; } = new List<ArticleListDTO>();
}

问题是 Repeater 可能使用客户端呈现模式(这是默认模式)。当它呈现 HTML 时,它呈现如下内容:

<div data-bind="foreach: something">
    <!-- template -->
</div>

呈现模板时,它的 DataContextnull(因为模板不能包含项目的数据 - 它是一个模板)。

所以你有两个选择:

  1. 通过将 RenderSettings.Mode="Server" 添加到 Repeater 打开服务器渲染。
  2. 更新您的控件,使其在 DataContext 为 null 时不调用 DataBind。