Двухсторонняя привязка данных пользовательского шаблонного управления asp.net

Этот вопрос был первоначально о том, чтобы заставлять двухстороннюю привязку работать вообще, но из-за отсутствия определенных ответов и иначе прогрессировать по пути, я обновлял его - можно проверить историю редактирования, но я полагал, что это лучше для ясности.

Листинг кода ниже позволяет отдельному объекту быть двухсторонний связанный с данными к шаблонному элементу управления. Я хотел бы расширить этот пример самым простым способом, возможным допускать вложение столь же двухсторонних поддерживающих привязку данных шаблонных элементов управления для введенных комплексом свойств корневого больше всего объекта. Например, SampleFormData имеет свойство List Items. Я хотел бы смочь связать с этим списком в корневом больше всего шаблоне (от этого листинга кода), и любой дисплей строковые данные в доступном для редактирования списке текстовых полей, возможно, с командами для вставки, удалить, rebind-entered-changes (назад к свойству List связанного объекта). Кроме того, если это было списком составного типа (SampleFormChildData, вместо того, чтобы представлять в виде строки), встроенное новое SampleSpecificEntryForm мог использоваться в рамках списка, связанного с каждым из объектов списка, как повторитель. И так далее вниз к простым листом свойствам, если автор так выбирает. Ui-поля не должны быть автоматически сгенерированы, просто доступные для привязки.

Примечание: Случай List является особенным, потому что даже встроенная привязка не может обработать строку как DataItem непосредственно - связывающий со строками непосредственно, поскольку объекты в нашем списке не являются требованием, но конечно ценный.

Это отличается от a 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 Items { get; set; }

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

    [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 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() { "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" %>




    

Welcome to ASP.NET!



(<%# Container.SampleString %>, <%# Container.SampleInt %>) - aka - (<%# DataBinder.Eval(Container, "SampleString")%>, <%# DataBinder.Eval(Container, "SampleInt")%>)




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 также в попытке смочь вложить компонент списка как так (в):


    
        ">
    
    
        
    

Любые мысли о том, как сделать эту работу каскадным способом, были бы потрясающими (на свойстве списка Объектов, например). Одна из проблем здесь, это Связывает (), не может относиться к самому связанному с данными объекту (строка в этом случае), но на свойстве того объекта - делающий связывающий с неловким списком.

Спасибо за любую справку!


Исследования по пути

Реализованный IDataItemContainer. Я очень надеялся, что это зафиксирует его, но нет. Никакое noticable изменение. Ой, реализованный это на неправильном классе. Теперь это Связывает, но значения не являются восстановлением к связанному объекту на обратной передаче. Хм...

Поскольку эта статья предлагает, Page. GetDataItem () является источником исключения. Это исключение выдается, если _dataBindingContext страницы пустой или пустым. Статья действительно объясняет это, но она не говорит, как удостовериться, что _dataBindingContext Page заполняется. Я продолжу смотреть.

Как в документации MSDN говорится, DataBoundControl должен реализовать PerformDataBinding вместо того, чтобы переопределить DataBind (). Я сделал так и заставил both-way-binding работать. Этот код необходим, или я должен использовать что-то встроенное?

6
задан 16 revs 26 May 2010 в 21:54
поделиться

1 ответ

Вы пробовали синтаксис Databinder.Eval (Container.DataItem, ...) ?

Также см. Эту статью о Bind () .

PS. Вам нужно привязать данные при каждой обратной передаче, если вы не используете Viewstate для сохранения значений.

0
ответ дан 18 December 2019 в 04:49
поделиться
Другие вопросы по тегам:

Похожие вопросы: