动态用户控件在回发后获取并维护值

我有一个我构建的页面,它动态生成用户控件。 例如,用户控件有两个可以编辑的字段:SomeId和SomeData。 我希望能够基于UserControlObject设置这些值。 当我之后读取控件时,我希望能够从控件返回UserControlObject并将数据库值设置为该值。 我在使值保持最新状态时遇到一些麻烦。

 //Page public class SomePage { private List _MyUserControls; private void InitControls() { var controlsToBuild = SomeDatabaseCallToGetControlObjects(); foreach(MyUserControl control in controlsToBuild) { MyUserControl control = this.Page.LoadControl("MyControl.ascx") as MyUserControl; UserControlPlaceHolder.Controls.Add(myControl); _MyUserControls.Add(myControl); } } protected void Page_Init(object sender, EventArgs e) { InitControls(); } protected void SaveButton_Click(object sender, EventArgs e) { if (this.IsValid) { ListlistObj = new List(); foreach(MyUserControl control in _MyUserControls) { MyUserObject obj = control.GetObjectFromControl(); listObjs.Add(obj); } SaveToDatabase(listObjs); //Clear placeholder in case number of controls has changed based on the save UserControlPlaceHolder.Clear(); InitControls(); GetObjectFromDatabase(); } } } //Object to put in control public class UserControlObject { public string DataForUser { get;set;} public double MoreDataForUser { get;set;} public int HiddenIdFromUser { get; set;} } //User control public class MyUserControl : UserControl { public MyUserControlObject GetObjectFromControl() { UserControlObject obj = new UserControlObject(); obj.DataForUser = textBoxOnTheControl.Text; obj.MoreDataForUser = anotherBoxOnTheControl.Text; obj.HiddenIdFromUser = hiddenField.Value; return obj; } public void SetUserControlObject(UserControlObject obj) { textBoxOnTheControl.Text = obj.DataForUser; anotherBoxOnTheControl.Text = obj.MoreDataForUser; hiddenField.Value = obj.HiddenIdFromUser; } } 

基本上,我想用数据库中的值加载每个MyUserControl 。 用户应该能够更改这些字段中的大多数(但不是全部)。 用户不应该能够更改ID,但我需要它来更新数据库中的记录。

我在获取信息以保存并正确保存方面遇到一些麻烦,因为我正在重新创建MyUserControl的集合。 它似乎在初始回发上运行良好,但在后续回发后,我仍然得到其中一个字段的旧值。 我怎样才能确保:

1)信息正确设置到用户控件。 我是否需要在UserControl的每个属性上放置一个引用viewstate的公共属性?

2)单击保存事件后,在回发后,重建控件不会导致我保留初始加载中的任何“旧”值? 我该如何处理视图状态? 我希望数据反映用户已更改的内容。

要使视图状态/控件状态正常工作,您的控件必须具有相同的ID。 由于您没有明确地分配ID,因此必须生成它,并且存在与存在多个用户控件的冲突。 我会建议你有一些逻辑来通过post-back生成相同的ID集。 例如,

 private void InitControls() { var numControlsToBuild = SomeDatabaseCallToGetNumControls(); int idCounter = 1; foreach(var controlData in numControlsToBuild) { var control = this.Page.LoadControl("MyControl.ascx") as MyUserControl; control.ID = "MyControl" + idCounter.ToString(); idCounter++; UserControlPlaceHolder.Controls.Add(myControl); _MyUserControls.Add(control); // probably code load control data into control } } 

正如VinayC所指出的,这里的根本问题是,当您动态地向页面添加控件时,如果您没有为这些控件分配ID,则会为它们提供生成的ID。 如果动态生成的控件的数量发生更改,或者创建它们的顺序发生更改,则动态创建的Web控件与视图状态中这些对象的状态信息之间将不匹配。 同样,动态创建的Web控件的ID与POST头中的查询参数的ID不匹配。 这意味着某些字段的值不会从POST数据更新。

查看状态ID不匹配将导致标签和文字等内容恢复为初始值。 另一方面,POST数据ID不匹配将导致输入字段恢复为初始值。 如果您在输入字段恢复到初始值时遇到问题,那么查看状态将无法解决问题。 一种常见的误解是字段值在视图状态中持久存在。 但是,这是不必要的,因为输入字段值已包含在POST数据中。 有关View State如何工作的详细讨论,请参阅Scott Mitchell 了解viewstate的工作原理 。

如果你总是以相同的顺序创建动态添加的控件,那么,正如VinayC指出的那样,你可以生成一系列ID,例如“ID1”,“ID2”,“ID3”……,因为你正在创建web控件。 在您的情况下,由于您将用户控件字段值存储在数据库中,因此您可能只想为每个用户控件生成一次新ID,并将每个生成的ID与相关字段值一起存储在数据库中。 这样,您无需担心创建控件的顺序。