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

StackOverflow https://stackoverflow.com/questions/2854234

Вопрос

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

Ниже приведен список кодов позволяет одному объекту использовать двустороннюю посылку в управление шаблоном. Я хотел бы продлить этот пример в прошедшем способе, возможно, чтобы обеспечить вложение аналогично двусторонней обработке шаблонов с поддержкой с поддержкой данных для сложных свойств корневого объекта. Например, SampleFormData имеет свойство List<string> Items. Отказ Я хотел бы иметь возможность привязать к этому списку в пределах корневого шаблона (из этого списка кода) и либо отображать данные строки в редактируемый список текстовых ящиков, возможно, с командами для вставки, удаления, Rebind введен -Чейзы (обратно в свойство списка связанного объекта). Кроме того, если это был список сложного типа (SampleFormChildData, а не строка), новый встроенный SampleSpecificEntryForm Можно использовать в списке, связанных с каждым из элементов списка, как ретранслятор. И так далеко до простых свойств листьев, если автор так выбирает. UI-поля не должны быть автоматически сгенерированными, просто доступными для привязки.

Примечание: случай List<string> Особется, потому что даже встроенные привязки не могут обрабатывать строку в качестве непосредственно - привязки к строкам непосредственно в виде предметов в нашем списке, не является требованием, но, безусловно, ценным.

Это отличается от 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, в попытке быть в состоянии найти компонент списка, как так (в пределах):

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

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

Спасибо за любую помощь!


Открытия по пути

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

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

По словам документации MSDN MSDN, databoundcontrol должен реализовать выполнение данных, а не переопределить databind (). Я сделал это и сделал обеими способами. Это необходим этот код или я должен использовать что-то встроенное?

Это было полезно?

Решение

Ты пытался Databilder.eval (Container.dataitem, ...) синтаксис?

Также см. Эту статью на Связывать().

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top