我有一个我构建的页面,它动态生成用户控件。例如,用户控件有两个可以编辑的字段:SomeId和SomeData。我希望能够根据UserControlObject
设置这些值。当我之后读取控件时,我希望能够从控件返回UserControlObject
并将数据库值设置为该值。我在使值保持最新状态时遇到了一些麻烦。
//Page
public class SomePage
{
private List<MyUserControl> _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)
{
List<MyUserObject>listObj = new List<MyUserObject>();
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)点击保存事件后,在回发后,重建控件不会导致我保留初始加载中的任何“旧”值?我该如何处理视图状态?我希望数据反映用户的变化。
答案 0 :(得分:9)
要使视图状态/控件状态正常工作,您的控件必须具有相同的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
}
}
答案 1 :(得分:4)
正如VinayC所指出的,这里的根本问题在于,当您动态地向页面添加控件时,如果您没有为这些控件分配ID,则会为它们提供生成的ID。如果动态生成的控件的数量发生更改,或者创建它们的顺序发生更改,则动态创建的Web控件与视图状态中这些对象的状态信息之间将不匹配。同样,动态创建的Web控件的ID与POST头中的查询参数的ID不匹配。这意味着某些字段的值不会从POST数据更新。
查看状态ID不匹配会导致标签和文字等内容恢复为初始值。另一方面,POST数据ID不匹配将导致输入字段恢复为初始值。如果您遇到输入字段恢复到初始值的问题,那么查看状态将无法解决问题。一种常见的误解是字段值在视图状态中持久存在。但是,这是不必要的,因为输入字段值已包含在POST数据中。有关View State如何工作的详细讨论,请参阅Scott Mitchell撰写的Understanding how the viewstate works。
如果你总是以相同的顺序创建动态添加的控件,那么,正如VinayC指出的那样,你可以生成一系列ID,例如“ID1”,“ID2”,“ID3”......网页控件。在您的情况下,由于您将用户控件字段值存储在数据库中,您可能只想为每个用户控件生成一次新ID,并将每个生成的ID与相关字段值一起存储在数据库中。这样,您无需担心创建控件的顺序。