1

我创建了一个自定义DataControlField,用于DetailsView显示可编辑的时间表。这些自定义字段中的每一个都有传入的 DataSourceID 字符串,用于填充用户可以选择的值。

如果 DetailsView 处于编辑模式,它将显示 aDropDownList让用户从来自 a 的项目列表中进行选择SqlDataSource。在ReadOnly模式下,显示所选值的全名。

我在ReadOnly模式下遇到的问题是,我只有传入的 SqlDataSource 的 ID,当尝试将其转换为实际的 SqlDataSource 对象时,它返回 null。

我已将完整的对象放在底部,以防将来对任何人有用,我也尝试这样做。

代码前面看起来像这样

<asp:DetailsView ID="dvPayPeroid1" runat="server"
    AutoGenerateRows="False"
    CssClass="DetailsView"
    DataSourceID="sqlMyScheduleData"
    DefaultMode="ReadOnly"
    GridLines="None">
    <FieldHeaderStyle CssClass="DetailsViewHeader" />
    <Fields>
        <asp:BoundField DataField="FirstDayOfWeek" HeaderText="Week Starting" HtmlEncode="false" DataFormatString="{0:MM/dd/yyyy}" ReadOnly="true" />
        <my:ScheduleField DataField="1" HeaderText="Sunday" DataSourceID="sqlReasonCodes" />
        <my:ScheduleField DataField="2" HeaderText="Monday" DataSourceID="sqlReasonCodes" />
        <my:ScheduleField DataField="3" HeaderText="Tuesday" DataSourceID="sqlReasonCodes" />
        <my:ScheduleField DataField="4" HeaderText="Wednesday" DataSourceID="sqlReasonCodes" />
        <my:ScheduleField DataField="5" HeaderText="Thursday" DataSourceID="sqlReasonCodes" />
        <my:ScheduleField DataField="6" HeaderText="Friday" DataSourceID="sqlReasonCodes" />
        <my:ScheduleField DataField="7" HeaderText="Saturday" DataSourceID="sqlReasonCodes" />
        <asp:BoundField DataField="FirstDayOfSecondWeek" HeaderText="Week Starting" HtmlEncode="false" DataFormatString="{0:MM/dd/yyyy}" ReadOnly="true" />
        <my:ScheduleField DataField="8" HeaderText="Sunday" DataSourceID="sqlReasonCodes" />
        <my:ScheduleField DataField="9" HeaderText="Monday" DataSourceID="sqlReasonCodes" />
        <my:ScheduleField DataField="10" HeaderText="Tuesday" DataSourceID="sqlReasonCodes" />
        <my:ScheduleField DataField="11" HeaderText="Wednesday" DataSourceID="sqlReasonCodes" />
        <my:ScheduleField DataField="12" HeaderText="Thursday" DataSourceID="sqlReasonCodes" />
        <my:ScheduleField DataField="13" HeaderText="Friday" DataSourceID="sqlReasonCodes" />
        <my:ScheduleField DataField="14" HeaderText="Saturday" DataSourceID="sqlReasonCodes" />
    </Fields>
</asp:DetailsView>

<asp:SqlDataSource ID="sqlReasonCodes" runat="server" 
    CacheDuration="500"
    ConnectionString="<%$ ConnectionStrings:MyConnectionString %>"
    EnableCaching="true"
    SelectCommand="ReasonSelectActive" SelectCommandType="StoredProcedure">
</asp:SqlDataSource>

当我将 DetailsView 置于编辑模式时,效果很好。失败的地方是 ReadOnly 模式,它在DataField属性中传递值,例如“P”代表“PTO”,“W”代表“Working”,“R”代表“Requested Day Off”,等等。

我的麻烦是将 DataField 转换为其相应的长名称。目前我正在使用这段代码来获取 SqlDataSource。

Page page = (Page)HttpContext.Current.Handler;
SqlDataSource sds = (SqlDataSource)page.FindControl(this.DataSourceID);
DataView dv = (DataView)sds.Select(DataSourceSelectArguments.Empty);

这里sds对象为空。

我的问题是,如何将控件名称的字符串转换为具有 DataControlField 的对象?

下面的代码供参考,如果有人对改进代码有任何建议,请告诉。

public class ScheduleField : DataControlField
{
    #region Properties
    public string CssClass
    {
        get
        {
            object value = ViewState["CssClass"];

            if (value != null)
                return value.ToString();

            return "MetricStatus";
        }

        set
        {
            ViewState["CssClass"] = value;
            OnFieldChanged();
        }
    }

    public string DataSourceID
    {
        get
        {
            object value = ViewState["DataSourceID"];

            if (value != null)
                return Convert.ToString(value);

            return "";
        }

        set
        {
            ViewState["DataSourceID"] = value;
            OnFieldChanged();
        }
    }

    public string DataField
    {
        get
        {
            object value = ViewState["DataField"];

            if (value != null)
                return Convert.ToString(value);

            return "";
        }

        set
        {
            ViewState["DataField"] = value;
            OnFieldChanged();
        }
    }
    #endregion

    #region Constructors
    public ScheduleField()
    {

    }

    #endregion

    #region Abstract / Override Implementations
    protected override DataControlField CreateField()
    {
        return new BoundField();
    }

    public override void InitializeCell(DataControlFieldCell cell, DataControlCellType cellType, DataControlRowState rowState, int rowIndex)
    {
        base.InitializeCell(cell, cellType, rowState, rowIndex);

        // add controls to the cell here.

        if (cellType == DataControlCellType.DataCell)
        {
            if ((rowState & DataControlRowState.Edit) > 0)
                cell.DataBinding += new EventHandler(cell_DataBinding_Edit);
            else if (rowState == DataControlRowState.Normal || rowState == DataControlRowState.Alternate)
                cell.DataBinding += new EventHandler(cell_DataBinding_Normal);
            else
                throw new Exception("Unhandled rowState: " + rowState.ToString());
        }
    }

    #endregion

    #region Events
    private void cell_DataBinding_Edit(object sender, EventArgs e)
    {
        DataControlFieldCell cell = (DataControlFieldCell)sender;
        object dataItem = DataBinder.GetDataItem(cell.NamingContainer);
        string sDataField = DataBinder.GetPropertyValue(dataItem, DataField).ToString();

        DropDownList ddlReason = new DropDownList();
        ddlReason.Items.Add(new ListItem("<none>", ""));
        ddlReason.AppendDataBoundItems = true;
        ddlReason.DataSourceID = this.DataSourceID;
        ddlReason.DataTextField = "Name";
        ddlReason.DataValueField = "Short";
        ddlReason.SelectedValue = sDataField;

        cell.Controls.Add(ddlReason);
    }

    private void cell_DataBinding_Normal(object sender, EventArgs e)
    {
        DataControlFieldCell cell = (DataControlFieldCell)sender;
        object dataItem = DataBinder.GetDataItem(cell.NamingContainer);
        string sDataField = DataBinder.GetPropertyValue(dataItem, DataField).ToString();

        Page page = (Page)HttpContext.Current.Handler;
        SqlDataSource sds = (SqlDataSource)page.FindControl(this.DataSourceID);
        DataView dv = (DataView)sds.Select(DataSourceSelectArguments.Empty);
        DataTable dt = dv.ToTable();

        foreach (DataRow dr in dt.Rows)
        {
            if (dr["Short"].ToString() == sDataField)
                sDataField = dr["Name"].ToString();
        }

        Label lblReason = new Label();
        lblReason.Text = sDataField;

        cell.Controls.Add(lblReason);
    }

    #endregion

    #region Methods

    // no methods

    #endregion
}
4

2 回答 2

3

而不是.parent.parent... 使用:

ContentPlaceHolder cph = (ContentPlaceHolder)this.Page.Master.FindControl("ContentPlaceHolderID");
于 2012-10-23T18:18:13.210 回答
0

好吧,这似乎是一个完整的 hack,但这是我能够引用SqlDataSource.

ContentPlaceHolder cph = (ContentPlaceHolder)cell.Parent.Parent.Parent.Parent;
SqlDataSource sds = (SqlDataSource)cph.FindControl("sqlReasonCodes");
DataView dv = (DataView)sds.Select(DataSourceSelectArguments.Empty);

看来,由于我使用的MasterPage是普通的 Page 对象,因此在其他区域中并不存在您所期望的。

我愿意接受比整件事更好的想法.Parent.Parent.Parent.Parent

于 2012-08-09T17:44:08.573 回答