0

CompositeControl次のように定義された、を拡張する生成されたカスタム コントロールのコレクションがあります。

[PersistChildren(true)]
[ToolboxData("<{0}:ContractControl runat=server></{0}:ContractControl>")]
public class ContractControl : CompositeControl
{
    private int contractID = 0;
    private ContractTileControl tileControl = null;
    private ContractDetailControl detailControl = null;

    private HtmlGenericControl contractMainDiv = null;

    public int ContractID
    {
        get { return this.contractID; }
        set { this.contractID = value; }
    }

    public ContractTileControl TileControl
    {
        get { return this.tileControl; }
        set { this.tileControl = value; }
    }

    public ContractDetailControl DetailControl
    {
        get { return this.detailControl; }
        set { this.detailControl = value; }
    }

    public ContractControl()
    {
        this.contractMainDiv = new HtmlGenericControl("div");
        this.contractMainDiv.ID = "contractMainDiv";
        this.contractMainDiv.Attributes.Add("class", "contractMain");
    }

    #region protected override void OnPreRender(EventArgs e)
    protected override void OnPreRender(EventArgs e)
    {
        base.OnPreRender(e);
        //CreateChildControls();
    }
    #endregion

    #region protected override void CreateChildControls()
    protected override void CreateChildControls()
    {
        base.CreateChildControls();
        if (tileControl != null)
        {
            this.contractMainDiv.Controls.Add(tileControl);
        }

        if (detailControl != null)
        {
            this.contractMainDiv.Controls.Add(detailControl);
        }
        this.Controls.Add(contractMainDiv);
        //base.CreateChildControls();
    }


    #endregion

    protected override void OnLoad(EventArgs e)
    {
        base.OnLoad(e);
        CreateChildControls();
    }

    protected override void OnInit(EventArgs e)
    {
        base.OnLoad(e);
        EnsureChildControls();
    }
}

ContractTileControlとは、 から派生したContractDetailControl別のカスタム コントロールCompositeControlです。

それらをコントロール セットに追加すると、asp:PlaceHolder正常にレンダリングされますが、リピーターを次のように定義すると、次のようになります。

<asp:Repeater ID="myRepeater" runat="server" >
    <HeaderTemplate>
        <table border="0" cellpadding="0" cellspacing="0">
    </HeaderTemplate>

    <ItemTemplate>
        <tr><td><easit:ContractControl ID="contractControl" runat="server" />
        </td></tr>
    </ItemTemplate>
    <FooterTemplate>
        </table>
    </FooterTemplate>
</asp:Repeater>

そしてそれらをそれにバインドします:

private void FillContractPlaceHolder()
    {

        List<ContractControl> controls = new List<ContractControl>();
        foreach(KeyValuePair<Customer, List<TFSContract>> pair in contractList)
        {
            Label customerNameLbl = new Label();
            customerNameLbl.ID = "customerNameLbl";
            customerNameLbl.CssClass = "customerName";
            customerNameLbl.Text = pair.Key.Name;
            contractListPlaceHolder.Controls.Add(customerNameLbl);

            foreach (TFSContract contract in pair.Value)
            {
                ContractStatusBarControl status = new ContractStatusBarControl();
                status.WidthPercent = GetFillPercent(contract.NumberOfTasks, contract.NumberOfFinishedTasks);

                string[] contractNameParts = Regex.Split(contract.Contract.Name, @"[A-Z]{3}-[0-9|A-Z]{2}-[0-9|A-Z]{2}", RegexOptions.IgnoreCase);

                ContractDetailControl detail = new ContractDetailControl();
                detail.ContractName = contractNameParts.Last();
                detail.DateStarted = contract.StartDate;
                detail.DateFinished = contract.FinishDate;
                detail.StatusBar = status;

                ContractTileControl tile = new ContractTileControl();
                Match match = Regex.Match(contract.Contract.Name, @"[A-Z]{3}-[0-9|A-Z]{2}-[0-9|A-Z]{2}", RegexOptions.IgnoreCase);
                if (match.Value.Length != 0)
                {
                    tile.ContractNumber = match.Value;
                }

                tile.ContractTasksFinished = contract.NumberOfFinishedTasks;
                tile.ContractTasksTotal = contract.NumberOfTasks;

                ContractControl contractControl = new ContractControl();
                contractControl.ContractID = contract.Contract.Id;
                contractControl.TileControl = tile;
                contractControl.DetailControl = detail;
                //contractListPlaceHolder.Controls.Add(contractControl);
                controls.Add(contractControl);
            }


        }

        myRepeater.DataSource = controls;
        myRepeater.DataBind();

    }

テーブルは作成されますが、 と の両方がそれぞれの型のインスタンスに適切に設定されていても、Repeater は と の両方が null であると主張するため、 の非複合部分のみがレンダリングされcontractMainDivます。ContractControltileControldetailControl

4

1 に答える 1

2

Repeaterデータ バインドされるとItemTemplate、データ ソース内のアイテムごとに のインスタンスが作成され、そのインスタンスがデータ ソースDataItemのアイテムに設定され、子がデータ バインドされます。

この場合、データ ソースのアイテムは のインスタンスであり、ContractControlデータバインディングがないため、リストに追加した各アイテムItemTemplateの空のインスタンスになります。ContractControl

手っ取り早い解決策は、 のItemDataBoundイベントのハンドラーを追加しRepeater、プロパティを実際のコントロールにコピーすることです。

protected void myRepeater_ItemDataBound(object sender, RepeaterItemEventArgs e)
{
   switch (e.Item.ItemType)
   {
      case ListItemType.Item:
      case ListItemType.AlternatingItem:
      case ListItemType.SelectedItem:
      case ListItemType.EditItem:
      {
         var source = (ContractControl)e.Item.DataItem;
         var destination = (ContractControl)e.Item.FindControl("contractControl");
         destination.ContractID = source.ContractID;
         destination.TileControl = source.TileControl;
         destination.DetailControl = source.DetailControl;
         break;
      }
   }
}

より良い解決策は、をオブジェクトRepeaterのリストにバインドし、コードを移動して をイベント ハンドラーに組み込むことです。TFSContractContractControlItemDataBound

編集
ヘッダー、フッターなどを無視して、実際のアイテムのみを処理するように更新されました。

于 2012-11-29T15:11:06.727 に答える