سؤال

كان هذا السؤال في الأصل حول الحصول على ارتباط في اتجاهين للعمل على الإطلاق ، ولكن بسبب عدم وجود إجابات محددة والتقدم على طول الطريق ، كنت أقوم بتحديثه - يمكنك التحقق من تاريخ التحرير ، لكنني اعتقدت أن هذا أفضل ل وضوح.

تتيح قائمة الكود أدناه ككائن واحد أن يكون قاعدة بيانات ثنائية الاتجاه لعنصر تحكم تمثل. أرغب في توسيع هذا المثال بأبسط طريقة ممكنة للسماح بتعشيش عناصر تحكم تمكين في اتجاهين متشابهة في اتجاهين لخصائص معقدة من كائن الجذر الأكثر جذرًا. فمثلا، SampleFormData لديه خاصية List<string> Items. أرغب في أن أكون قادرًا على ربط هذه القائمة ضمن قالب الجذر الأكثر (من قائمة الرمز هذه) ، وإما عرض بيانات السلسلة في قائمة قابلة للتحرير من مربعات النص ، ربما ، مع أوامر لإدراج ، حذف ، معيد للترويج -changes (العودة إلى خاصية قائمة الكائن Bound). أيضًا ، إذا كانت هذه قائمة بنوع معقد (SampleFormChildData, ، بدلا من السلسلة) ، مضمن جديد SampleSpecificEntryForm يمكن استخدامها في القائمة ، مرتبطة بكل من عناصر القائمة ، مثل مكرر. وهكذا إلى الخواص البسيطة للورقة ، إذا اختار المؤلف ذلك. لا يجب أن يتم إنشاء حقول واجهة المستخدم تلقائيًا ، وهي متاحة فقط للربط.

ملاحظة: حالة List<string> أمر خاص لأنه حتى الروابط المدمجة لا يمكنها التعامل مع السلسلة باعتبارها dataitem مباشرة - الربط بالسلاسل مباشرة لأن العناصر الموجودة في قائمتنا ليست مطلبًا ، ولكنها بالتأكيد ذات قيمة.

هذا يختلف عن أ FormView نظرًا لأنه غير مبني على توقع ربط أحد قائمة العناصر ، فقط إلى عنصر واحد كما استمر في عرض العرض أو أي مكان. على عكس FormView ، يحتوي هذا فقط على قالب افتراضي واحد يشبه Edittemplate من FormView. وبالمثل ، فإن ربط خاصية تشبه المجموعة سيكون لها أيضًا عرض واحد - تحرير. لا يوجد اختيار للصف ثم التحرير. كل شيء قابل للتحرير طوال الوقت. والغرض من ذلك هو جعل النماذج المرتبطة في اتجاهين أسهل في البناء.

يبدو لي أنه يجب أن يكون هناك نوعان من الربط. SingleEntityBinding و CollectionBinding. SingleEntityBinding يأخذ مثيل كائن واحد كصاحب بيانات (كنماذج أولية بواسطة SampleSpecificEntryForm) في حين CollectionBinding يمكن أن يكون ملزماً بالوالدين SingleEntityBinding مع سمات DataSourceID="EntryForm1" DataMember="Items" كما في مثال الرمز ل DataList1 أقل. يجب دعم تعشيش من أي نوع من النوعين. معالجة قائمة مثل إدراج/تغيير/حذف عمليات النوع مقابل بيانات الكائن الداعم هي مسؤولية مؤلف النموذج ؛ ومع ذلك ، فإن هذه الميكانيكا ستكون بسيطة نسبيا للتنفيذ.

إليك بعض التعليمات البرمجية ، آمل أن يساعد شخص ما. 200 نقطة موجودة للحصول على أفضل الاقتراحات لتحقيق هذا الهدف المريح ...

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

مع صفحة ASP.NET فيما يلي:

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

لقد قمت بتطبيق idataSource أيضًا ، في محاولة لتكون قادرًا على تعشق مكون قائمة مثل SO (داخل):

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

أي أفكار حول كيفية جعل هذا العمل بطريقة متتالية ستكون رائعة (على خاصية قائمة العناصر ، على سبيل المثال). أحد التحديات هنا هو أن BIND () لا يمكن أن يشير إلى كائن قاعدة البيانات نفسه (سلسلة في هذه الحالة) ولكن على خاصية لهذا العنصر - مما يجعل الربط بقائمة محرجة.

شكرا على اي مساعدة!


الاكتشافات على طول الطريق

نفذت idataiteMcontainer. كنت متفائلاً للغاية أن يصلح هذا الأمر ، لكن لا. لا تغيير ملحوظ. عفوًا ، نفذها على الفصل الخاطئ. الآن هو ملزم ، لكن القيم لا يتم انتعاشها إلى الكائن المربوطة على Postback. أمم...

كما هذه المقالة يقترح ، page.getDataitem () هو مصدر الاستثناء. يتم طرح هذا الاستثناء إذا كان _databindingContext الخاص بالصفحة فارغًا أو فارغًا. تشرح المقال هذا ، لكنه لا يقول كيفية التأكد من ملء _databindingContext الصفحة. سأستمر في البحث.

كما تقول وثائق MSDN ، يجب على DATABONDCONTROL تنفيذ الأداء بدلاً من تجاوز DATABIND (). لقد فعلت ذلك وجعلت العمل الملزم في كل من. هل هذا الرمز ضروري أم يجب أن أستخدم شيئًا مدمجًا؟

هل كانت مفيدة؟

المحلول

هل جربت databinder.eval (Container.dataitem ، ...) بناء الجملة؟

انظر أيضا هذا المقال على ربط().

ملاحظة. تحتاج إلى البيانات على كل Postback إلا إذا كنت تستخدم ViewState للحفاظ على القيم.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top