Pregunta

Esta cuestión fue originalmente sobre conseguir la unión al trabajo en absoluto en ambos sentidos, pero debido a la falta de respuestas específicas y de otra manera progresar en el camino, he estado actualizando ella - Puede comprobar el historial de edición, pero pensé que este es mejor para mayor claridad.

El listado de código a continuación permite un único objeto de ser de dos vías de enlace de datos a un control de plantilla. Me gustaría extender este ejemplo de la manera más simple posible para permitir la anidación de los controles de manera similar en ambos sentidos de enlace de datos habilitados con plantilla de propiedades de tipo complejo de la raíz objeto situado más. Por ejemplo, SampleFormData tiene una List<string> Items propiedad. Me gustaría ser capaz de unirse a esta lista dentro de la plantilla de la raíz más (de este listado de código), y, o bien visualizar los datos de cadena en una lista editable de cuadros de texto, tal vez, con comandos para insertar, eliminar, entraron revinculación- -cambios (de nuevo a la propiedad de lista del objeto dependiente). Además, si se tratara de una lista de un tipo complejo (SampleFormChildData, en lugar de cadena), un nuevo SampleSpecificEntryForm incrustado podría ser utilizado dentro de la lista, con destino a cada uno de los elementos de la lista, como un repetidor. Y así hasta llegar a las propiedades de hoja simple, si el autor así lo decide. La interfaz de usuario campos no tienen que ser auto-generado, solo disponible para la unión.

Nota: El caso de la List<string> es especial porque incluso la incorporada en fijaciones no pueden manejar cadena como el DataItem directa - la unión a las cadenas directamente como artículos en nuestra lista no es un requisito, pero ciertamente valiosa

Esto es diferente de un FormView porque no se construye a esperar para unirse a uno de una lista de elementos, sólo para un solo elemento como persistido en estado de vista o donde quiera. A diferencia de la FormView, esto sólo tiene un único afín plantilla predeterminada a EditTemplate de FormView. Del mismo modo, la unión a una propiedad de colección como sería también sólo tienen un punto de vista - de edición. No hay una selección de la fila y la edición a continuación. Todo es editable todo el tiempo. El propósito es hacer que las formas unidas de dos vías más fáciles de construir.

Me parece que debe haber dos tipos de unión. SingleEntityBinding y CollectionBinding. SingleEntityBinding toma una sola instancia de objeto como una fuente de datos (como prototipo por SampleSpecificEntryForm) mientras CollectionBinding podría estar unido a él de SingleEntityBinding padre con atributos de DataSourceID="EntryForm1" DataMember="Items" como en el ejemplo de código para DataList1 continuación. Anidación de cualquier tipo debe ser apoyada en cualquier tipo. Lista de manipulación, tales como operaciones de inserción / cambio / tipo de borrado de datos contra el respaldo de objetos son responsabilidad del autor del formulario; sin embargo, tales mecanismos serían relativamente fáciles de implementar.

Aquí hay un código, espero que ayude a alguien. 200 puntos están ahí fuera para las mejores sugerencias para alcanzar esta meta diseñados, ...

using System.ComponentModel;
using System.Collections.Specialized;
using System.Collections.Generic;

namespace System.Web.UI.WebControls.Special
{
    [Serializable]
    public class SampleFormData
    {
        public string SampleString { get; set; }
        public int SampleInt { get; set; }
        public List<string> Items { get; set; }

        public SampleFormData()
        {
            SampleString = "Sample String Data";
            SampleInt = 5;
            Items = new List<string>();
        }
    }

    [ToolboxItem(false)]
    public class SampleSpecificFormDataContainer : WebControl, INamingContainer, IDataItemContainer
    {
        SampleSpecificEntryForm entryForm;

        internal SampleSpecificEntryForm EntryForm
        {
            get { return entryForm; }
        }

        [Bindable(true), Category("Data")]
        public string SampleString
        {
            get { return entryForm.FormData.SampleString; }
            set { entryForm.FormData.SampleString = value; }
        }

        [Bindable(true), Category("Data")]
        public int SampleInt
        {
            get { return entryForm.FormData.SampleInt; }
            set { entryForm.FormData.SampleInt = value; }
        }

        [Bindable(true), Category("Data")]
        public List<string> Items
        {
            get { return entryForm.FormData.Items; }
            set { entryForm.FormData.Items = value; }
        }

        internal SampleSpecificFormDataContainer(SampleSpecificEntryForm entryForm)
        {
            this.entryForm = entryForm;
        }

        #region IDataItemContainer Members
        public object DataItem { get { return entryForm.FormData; } }

        public int DataItemIndex { get { return 0; } }

        public int DisplayIndex { get { return 0; } }
        #endregion
    }

    public class SampleSpecificEntryForm : DataBoundControl, INamingContainer, IDataSource
    {
        #region Template
        private IBindableTemplate formTemplate = null;

        [Browsable(false), DefaultValue(null),
        TemplateContainer(typeof(SampleSpecificFormDataContainer), ComponentModel.BindingDirection.TwoWay),
        PersistenceMode(PersistenceMode.InnerProperty)]
        public virtual IBindableTemplate FormTemplate
        {
            get { return formTemplate; }
            set { formTemplate = value; }
        }
        #endregion

        public override ControlCollection Controls
        {
            get
            {
                EnsureChildControls();
                return base.Controls;
            }
        }

        private SampleSpecificFormDataContainer formDataContainer = null;

        [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public SampleSpecificFormDataContainer FormDataContainer
        {
            get
            {
                EnsureChildControls();
                return formDataContainer;
            }
        }

        [Bindable(true), Browsable(false)]
        public SampleFormData FormData
        {
            get
            {
                SampleFormData data = ViewState["FormData"] as SampleFormData;

                if (data == null)
                {
                    data = new SampleFormData();
                    ViewState["FormData"] = data;
                }

                return data;
            }
        }

        protected override void CreateChildControls()
        {
            if (!this.ChildControlsCreated)
            {
                this.ChildControlsCreated = true;
                Controls.Clear();
                formDataContainer = new SampleSpecificFormDataContainer(this);

                Controls.Add(formDataContainer);
                FormTemplate.InstantiateIn(formDataContainer);
            }
        }

        protected override void PerformDataBinding(Collections.IEnumerable ignore)
        {
            CreateChildControls();

            if (Page.IsPostBack)
            {
                //OrderedDictionary fields = new OrderedDictionary();

                //ExtractValuesFromBindableControls(fields, formDataContainer); // Don't know what this would be for

                foreach (System.Collections.DictionaryEntry entry in formTemplate.ExtractValues(formDataContainer))
                {
                    if (((string)entry.Key).Equals("SampleString", StringComparison.Ordinal))
                    {
                        FormData.SampleString = (string)entry.Value;
                    }

                    if (((string)entry.Key).Equals("SampleInt", StringComparison.Ordinal))
                    {
                        int i;
                        if (int.TryParse((string)entry.Value, out i))
                        {
                            FormData.SampleInt = i;
                        }
                    }
                }
            }

            formDataContainer.DataBind();
        }

        public SampleSpecificEntryForm()
        {
            this.PreRender += new EventHandler(SampleSpecificEntryForm_PreRender);
        }

        void SampleSpecificEntryForm_PreRender(object sender, EventArgs e)
        {
            SaveViewState();
        }

        #region IDataSource Members

        public event EventHandler DataSourceChanged;

        public DataSourceView GetView(string viewName)
        {
            return new PropertyView(this, viewName);
        }

        public Collections.ICollection GetViewNames()
        {
            return new List<string>() { "SampleString", "SampleInt", "Items" };
        }

        #endregion
    }

    // Not yet used ...
    public class PropertyView : DataSourceView
    {
        SampleSpecificEntryForm owner;
        string viewName;

        protected override Collections.IEnumerable ExecuteSelect(DataSourceSelectArguments arguments)
        {
            if (viewName.Equals("SampleString", StringComparison.Ordinal))
            {
                return new object[] { owner.FormData.SampleString };
            }

            if (viewName.Equals("SampleInt", StringComparison.Ordinal))
            {
                return new object[] { owner.FormData.SampleInt };
            }

            if (viewName.Equals("Items", StringComparison.Ordinal))
            {
                return new object[] { owner.FormData.Items };
            }

            throw new InvalidOperationException();
        }

        public PropertyView(SampleSpecificEntryForm owner, string viewName)
            : base(owner, viewName)
        {
            this.owner = owner;
            this.viewName = viewName;
        }
    }
}

Con una página ASP.NET lo siguiente:

<%@ Page Title="Home Page" Language="C#" MasterPageFile="~/Site.master" AutoEventWireup="true"
    CodeBehind="Default2.aspx.cs" Inherits="EntryFormTest._Default2" EnableEventValidation="false" %>

<%@ Register Assembly="EntryForm" Namespace="System.Web.UI.WebControls.Special" TagPrefix="cc1" %>

<asp:Content ID="HeaderContent" runat="server" ContentPlaceHolderID="HeadContent">
</asp:Content>
<asp:Content ID="BodyContent" runat="server" ContentPlaceHolderID="MainContent">
    <h2>
        Welcome to ASP.NET!
    </h2>
        <cc1:SampleSpecificEntryForm ID="EntryForm1" runat="server">
    <FormTemplate>
        <asp:TextBox ID="txtSampleString" runat="server" Text='<%# Bind("SampleString") %>'></asp:TextBox><br />
        <asp:TextBox ID="txtSampleInt" runat="server" Text='<%# Bind("SampleInt") %>'></asp:TextBox><br />
        <h3>
            (<%# Container.SampleString %>, <%# Container.SampleInt %>) - aka - 
            (<%# DataBinder.Eval(Container, "SampleString")%>, <%# DataBinder.Eval(Container, "SampleInt")%>)</h3>
        <br />
        <asp:Button ID="btnUpdate" runat="server" Text="Update" /><br />
        <br />
    </FormTemplate>
</cc1:SampleSpecificEntryForm>
</asp:Content>

Default2.aspx.cs:

using System;

namespace EntryFormTest
{
    public partial class _Default2 : System.Web.UI.Page
    {
        protected void Page_Load(object sender, EventArgs e)
        {
            EntryForm1.DataBind();
        }
    }
}

He implementado IDataSource así, en un intento de ser capaz de anidar un componente de lista como tal (en el):

<asp:DataList ID="DataList1" runat="server" DataSourceID="EntryForm1" DataMember="Items">
    <EditItemTemplate>
        <asp:TextBox ID="TextBox3" runat="server" Text="<%# Bind(".") %>"></asp:TextBox>
    </EditItemTemplate>
    <FooterTemplate>
        <asp:Button ID="Button2" runat="server" Text="Add" CommandName="Add" />
    </FooterTemplate>
</asp:DataList>

¿Alguna idea sobre cómo hacer este trabajo de una manera en cascada sería impresionante (en la propiedad lista Elementos, por ejemplo). Uno de los retos es que bind () no puede referirse a la propia (una cadena en este caso) de objetos de enlace de datos, pero en una propiedad de ese tema -. Hacer la unión a una lista incómoda

Gracias por cualquier ayuda!


Descubrimientos lo largo del camino

Implementado IDataItemContainer. Tenía muchas esperanzas de que esto solucionarlo, pero no. Ningún cambio notable. Vaya, implementado en la clase equivocada. Ahora es vinculante, pero los valores no están siendo rebote al objeto dependiente en la devolución de datos. Hmmm ...

Como este artículo sugiere, Page.GetDataItem () es el fuente de la excepción. esta excepción se produce si la página _dataBindingContext es nulo o vacío. el artículo no explicar esto, pero no dice cómo asegurar que _dataBindingContext de la página está poblada. voy a seguir buscando.

Como dice la documentación de MSDN, DataBoundControl debe aplicar PerformDataBinding en lugar de anular DataBind (). He hecho lo que hice y en ambos sentidos vinculante trabajo. Es el código necesario o debería estar usando algo incorporada?

¿Fue útil?

Solución

¿Ha tratado DataBinder.Eval (Container.DataItem, ...) sintaxis?

También ver este artículo en bind () .

PS. Es necesario que databind en cada devolución de datos a menos que esté utilizando Viewstate para preservar los valores.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top