Двусторонние привязки данных пользовательского шаблонного контроля ASP.NET
-
27-09-2019 - |
Вопрос
Этот вопрос был изначально о том, чтобы вообще получать двустороннее привязку, но из-за отсутствия конкретных ответов и в противном случае прогресс по пути я его обновил - вы можете проверить историю редактирования, но я понял, что это лучше для ясность.
Ниже приведен список кодов позволяет одному объекту использовать двустороннюю посылку в управление шаблоном. Я хотел бы продлить этот пример в прошедшем способе, возможно, чтобы обеспечить вложение аналогично двусторонней обработке шаблонов с поддержкой с поддержкой данных для сложных свойств корневого объекта. Например, 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 для сохранения значений.