Frage

Diese Frage wurde ursprünglich darum, Zwei-Wege überhaupt Arbeit zu binden, aber wegen des Mangels an konkreten Antworten und sonst auf dem Weg fortschreiten, ich habe es zu aktualisieren - Sie können den Bearbeitungsverlauf überprüfen, aber ich dachte, diese besser für Klarheit ist.

Der folgende Code Eintrag ermöglicht ein einzelnes Objekt Zwei-Wege-Databound zu einem Templat Kontrolle. Ich möchte dieses Beispiel auf einfachste Weise erweitern möglich, ähnlich Zwei-Wege-Datenbindung-fähige Templat Steuerungen für komplexe typisierte Eigenschaften der Wurzel meisten Objekte Verschachtelung zu ermöglichen. Zum Beispiel hat SampleFormData eine Eigenschaft List<string> Items. Ich möchte auf diese Liste zu binden können, in der Wurzel meisten Template (aus diesem Code Listing) und entweder in einer editierbaren Liste der Textfelder, die String-Daten angezeigt werden, vielleicht mit Befehlen für Einfügen, Löschen, rebind eingegeben -Änderungen (zurück zur gebundenen Objekt List-Eigenschaft). Auch wenn dieses eine Liste eines komplexen Typs (SampleFormChildData, anstatt string) ist, ein neues eingebettetes SampleSpecificEntryForm könnte in der Liste verwendet werden, gebunden an jeden der Liste der Elemente, wie ein Repeater. Und so weiter bis zu dem Blatt einfacher Eigenschaften, wenn der Autor so wählt. Die ui-Felder müssen nicht automatisch generiert werden, nur verfügbar für die Bindung.

Hinweis: Der Fall der List<string> Sonder ist denn auch die Einbau-Bindungen nicht String behandeln wie die DataItem direkt - in Strings direkt als Elemente in unserer Liste Bindung nicht erforderlich ist, aber sicherlich wertvoll

Dies unterscheidet sich von einem FormView, weil es nicht gebaut wird, binden an eine aus einer Liste von Elementen zu erwarten, nur auf ein einzelnes Element als beharrte in Ansichtszustand oder wo auch immer. Im Gegensatz zu dem Formview, das nur eine einzige Standard-Vorlage verwandt mit der Formview EditTemplate. Ebenso hat auch nur eine Ansicht würde zu einer Sammelstelle ähnlicher Eigenschaft Bindung - bearbeiten. Es gibt keine Auswahl der Zeile und dann Bearbeiten. Alles ist editierbar die ganze Zeit. Der Zweck ist, Zwei-Wege-gebundene Formen leichter zu bauen zu machen.

Es scheint mir, dass es sollte zwei Arten sein, zu binden. SingleEntityBinding und CollectionBinding. SingleEntityBinding nimmt eine einzelne Objektinstanz als Datenquelle (wie durch SampleSpecificEntryForm prototypisiert) während CollectionBinding um es mit der Mutter SingleEntityBinding Attribute DataSourceID="EntryForm1" DataMember="Items" wie im Codebeispiel für DataList1 unten gebunden werden konnte. Verschachtelung beiden Typen soll in beiden Typen unterstützt werden. Liste Manipulation wie Einfügen / Ändern / Löschen Art Operationen gegen die Gegen-Objektdaten liegen in der Verantwortung des Autors Form; Allerdings ist eine solche Mechanik wäre relativ einfach zu implementieren sein.

Hier ist ein Code, hoffen, dass es jemand hilft. 200 Punkte sind da draußen für die besten Vorschläge zu diesem ausgelegtem Ziel ...

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;
        }
    }
}

Mit einer ASP.NET-Seite folgenden:

<%@ 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();
        }
    }
}

habe ich IDataSource als gut umgesetzt, in einem Versuch, Nest wie so eine Liste Komponente in der Lage sein (in der):

<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>

Alle Gedanken darüber, wie diese Arbeit in einer Kaskadierung Art und Weise machen würde (auf der Liste Elemente Eigenschaft, zum Beispiel) genial. Einer der hier Herausforderungen besteht darin, dass Bind () nicht an das Databound-Objekt selbst (eine Zeichenfolge in diesem Fall) bezieht, sondern auf einer Eigenschaft dieses Elements -. Herstellung umständlich auf eine Liste Bindung

Vielen Dank für jede Hilfe!


Entdeckungen auf dem Weg

Implementiert IDataItemContainer. Ich war sehr zuversichtlich, dass dies würde es beheben, aber nein. Keine wahrnehmbare Veränderung. Oops, setzte sie auf der falschen Klasse. Nun ist es Bindung, aber die Werte sind nicht auf das gebundene Objekt auf Postbacks ist Rebound. Hmmm ...

dieser Artikel schon sagt, ist Page.GetDataItem () die null oder leer Quelle der Ausnahme. diese Ausnahme, wenn die _dataBindingContext Seite geworfen wird. der Artikel dies nicht erklären, aber es sagt nicht, wie, dass die _dataBindingContext bevölkerte Seite zu gewährleisten. ich werde weiter suchen.

Wie die MSDN-Dokumentation sagt, sollte Databound implementieren Perform statt zwingende DataBind (). Ich habe sowohl-Wege-Bindung Arbeit so und machte getan. Ist dieser Code notwendig oder soll ich Built-in mit so etwas sein?

War es hilfreich?

Lösung

Haben Sie versucht, DataBinder.Eval (Container.DataItem, ...) Syntax?

Siehe auch diesen Artikel auf Bind () .

PS. Sie müssen sich auf jedem Postback Databind, wenn Sie Viewstate verwenden Werte zu bewahren.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top