GridMemory:记住其列宽的网格






1.77/5 (6投票s)
2005年1月23日
3分钟阅读

52900

424
一个 DataGrid,它会将最后的状态存储在 XML 文件中,并在下次加载应用程序时加载列宽的最后状态。
引言
当您使用 DataGrid
控件时,一个很有用的功能是让它记住其列的宽度。在本文中,我将介绍一种方法,让您的 Grid 控件记住其列的大小。基本上,您需要以某种方式将 Grid 控件的“记忆”关联起来。
如今,XML 已在工业界被广泛接受。因此,我将使用它来充当 Grid 控件的内存。在本文中,我将介绍一个可以记住单个 Data Grid 控件列宽的 XML 文件。本文的扩展之处在于使其能够记住多个 Grid 控件的多个状态。
使用代码
首先,您需要为 Grid 控件添加一个 DataGridTableStyle
,然后再将 Grid 控件绑定到 DataSource
。此 Tablestyle 将通过其 Width
属性用于设置列的宽度。因此,每次加载应用程序时,都会获取并加载最后的列状态。
下面的示例向您展示了设置 Grid 控件列宽的一种硬编码方法。通过这种方式,您无法期望 Grid 控件记住其状态。
public void HardcodedInitializeGrid()
{
Hashtable colWidths = LoadLastGridState();
// develop datatable schema
tAddress = new DataTable();
tAddress.TableName = "tAddress";
tAddress.Columns.Add("No", typeof(int));
tAddress.Columns.Add("Firstname", typeof(string));
tAddress.Columns.Add("Lastname", typeof(string));
tAddress.Columns.Add("Email", typeof(string));
// fill data row with record #1
DataRow newRow;
newRow = tAddress.NewRow();
newRow["No"] = 0;
newRow["Firstname"] = "Henry";
newRow["Lastname"] = "Tan";
newRow["Email"] = "henryws@it.uts.edu.au";
// add record #1 to the tAddress
tAddress.Rows.Add(newRow);
// fill data row with record #2
newRow = tAddress.NewRow();
newRow["No"] = 1;
newRow["Firstname"] = "Albert";
newRow["Lastname"] = "Einstein";
newRow["Email"] = "albert.einstein@heaven.au";
// add record #2 to the tAddress
tAddress.Rows.Add(newRow);
DataGridTableStyle tablestyle = new DataGridTableStyle();
tablestyle.AlternatingBackColor = Color.WhiteSmoke;
tablestyle.MappingName = "tAddress";
// initialize tAddress style: set columns width
// use DataGridTextBoxColumn, display textbox on each column
DataGridTextBoxColumn textboxColumn = null;
for(int i=0; i < tAddress.Columns.Count; i++)
{
string colname = tAddress.Columns[i].ColumnName;
if(colname.Equals("No"))
{
textboxColumn = new DataGridTextBoxColumn();
textboxColumn.HeaderText = colname;
textboxColumn.MappingName = colname;
textboxColumn.Width = int.Parse(colWidths["No"].ToString());
tablestyle.GridColumnStyles.Add(textboxColumn);
}
else if(colname.Equals("Firstname"))
{
textboxColumn = new DataGridTextBoxColumn();
textboxColumn.HeaderText = colname;
textboxColumn.MappingName = colname;
textboxColumn.Width = int.Parse(colWidths["Firstname"].ToString());
tablestyle.GridColumnStyles.Add(textboxColumn);
}
else if(colname.Equals("Lastname"))
{
textboxColumn = new DataGridTextBoxColumn();
textboxColumn.HeaderText = colname;
textboxColumn.MappingName = colname;
textboxColumn.Width = int.Parse(colWidths["Lastname"].ToString());
tablestyle.GridColumnStyles.Add(textboxColumn);
}
else if(colname.Equals("Email"))
{
textboxColumn = new DataGridTextBoxColumn();
textboxColumn.HeaderText = colname;
textboxColumn.MappingName = colname;
textboxColumn.Width = int.Parse(colWidths["Email"].ToString());
tablestyle.GridColumnStyles.Add(textboxColumn);
}
else // default column with default size
{
textboxColumn = new DataGridTextBoxColumn();
textboxColumn.HeaderText = "Default";
textboxColumn.MappingName = "Default";
textboxColumn.Width = int.Parse(colWidths["Default"].ToString());
tablestyle.GridColumnStyles.Add(textboxColumn);
}
}
// add the tAddressstyle to the grid
dataGrid.TableStyles.Add(tablestyle);
// bind the grid with the datatAddress
dataGrid.DataSource = tAddress;
}
图 1:设置列宽的硬编码方法。
硬编码方法并不是我们在实际应用程序中通常想要的。我们想要的是一个能够记住每列宽度的应用程序。上面的代码创建了一个包含四列的 DataTable
:“No
”、“Firstname
”、“Lastname
”和“Email
”。然后向表中添加了两条记录。接下来,创建 DataGridTableStyle
对象,将 Grid 的 AlternatingBackColor
设置为 WhiteSmoke
,并通过将 MappingName
设置为等于表名来将其与之前创建的表进行映射。接下来,我们需要构造一个 XML 文件来存储 Grid 列的宽度状态。以下是一种可能的格式。
<?xml version="1.0" encoding="utf-8"?>
<GridState>
<Control name="MemoryGrid">
<Column name="No">30</Column>
<Column name="FirstName">200</Column>
<Column name="LastName">200</Column>
<Column name="Email">250</Column>
<Column name="Default">100</Column>
</Control>
</GridState>
图 2:用于记住列宽的 XML 文件。
由于现在列宽以 XML 格式存储,因此需要对图 1 中的前一个代码进行一些更改。您需要读取每一列的宽度,并为其设置相应的宽度。为了提高可读性,图 1 中对前一个代码所做的所有更改都将以红色突出显示。
public void InitializeGridWithLastState()
{
Hashtable colWidths = LoadLastGridState();
// develop datatable schema
tAddress = new DataTable();
tAddress.TableName = "tAddress";
tAddress.Columns.Add("No", typeof(int));
tAddress.Columns.Add("Firstname", typeof(string));
tAddress.Columns.Add("Lastname", typeof(string));
tAddress.Columns.Add("Email", typeof(string));
// fill data row with record #1
DataRow newRow;
newRow = tAddress.NewRow();
newRow["No"] = 0;
newRow["Firstname"] = "Henry";
newRow["Lastname"] = "Tan";
newRow["Email"] = "henryws@it.uts.edu.au";
// add record #1 to the tAddress
tAddress.Rows.Add(newRow);
// fill data row with record #2
newRow = tAddress.NewRow();
newRow["No"] = 1;
newRow["Firstname"] = "Albert";
newRow["Lastname"] = "Einstein";
newRow["Email"] = "albert.einstein@heaven.au";
// add record #2 to the tAddress
tAddress.Rows.Add(newRow);
DataGridTableStyle tablestyle = new DataGridTableStyle();
tablestyle.AlternatingBackColor = Color.WhiteSmoke;
tablestyle.MappingName = "tAddress";
// initialize table style: set columns width
// use DataGridTextBoxColumn, display textbox on each column
DataGridTextBoxColumn textboxColStyle = null;
for(int i=0; i < table.Column.Count; i++)
{
string colname = table.Column[i].ColumnName;
if(colname.Equals(“No”))
{
textboxColumn = new DataGridTextBoxColumn();
textboxColumn.HeaderText = colname;
textboxColumn.MappingName = colname;
textboxColumn.Width = colWidths[“No”];
}
else if(colname.Equals(“Firstname”))
{
textboxColumn = new DataGridTextBoxColumn();
textboxColumn.HeaderText = colname;
textboxColumn.MappingName = colname;
textboxColumn.Width = colWidths[“Firstname”];
}
else if(colname.Equals(“Lastname”))
{
textboxColumn = new DataGridTextBoxColumn();
textboxColumn.HeaderText = colname;
textboxColumn.MappingName = colname;
textboxColumn.Width = colWidths[“Lastname”];
}
else if(colname.Equals(“Emails”))
{
textboxColumn = new DataGridTextBoxColumn();
textboxColumn.HeaderText = colname;
textboxColumn.MappingName = colname;
textboxColumn.Width = colWidths[“Emails”];
}
else // default column with default size
{
textboxColumn = new DataGridTextBoxColumn();
textboxColumn.HeaderText = colname;
textboxColumn.MappingName = colname;
textboxColumn.Width = colWidths[“Default”];
}
}
// add the tablestyle to the grid
dataGrid.TableStyles.Add(tablestyle);
// bind the grid with the datatable
dataGrid.DataSource = tAddress;
}
图 3:使用 Grid 的最后状态(列宽)进行初始化。
图 3 中的代码中有一些显而易见的更改。它不是将列宽设置为常量,而是从 XML 文件中获取列宽。使用哈希表使这项任务变得方便。我们将 {列名, 列宽} 对存储在哈希表中。例如,在图 3 中,colWidths[“Firstname”]
将返回其列宽。反之,要向哈希表添加一对,colWidths.Add(“Firstname”, 200)
即可完成,将“Firstname”作为键,“200”作为值存储一对。
public Hashtable LoadLastGridState()
{
Hashtable colWidths = new Hashtable();
// using XmlTextReader to read the gridstate from gridstate.xml
XmlTextReader tr = new XmlTextReader("gridstate.xml");
// traverse the xml document using text reader
while(tr.Read())
{
if(tr.NodeType == XmlNodeType.Element)
{
if(tr.Name == "Column")
{
string key = tr.GetAttribute("name");
string val = tr.ReadElementString();
colWidths.Add(key, val);
}
}
}
tr.Close();
return colWidths;
}
图 4:从 XML 文件加载列宽。
从 XML 文件加载 Grid 的状态非常直接。特别是,如果您已经熟悉 XmlTextReader。对于 XML 中以“Column”开头的每个元素,获取其属性名称(列名)和列宽。将其添加到哈希表对象中,并在完成 XML 读取后返回哈希表对象。
public void SaveCurrentGridState()
{
if(dataGrid.TableStyles.Count == 0)
return;
Hashtable colWidths = new Hashtable();
XmlTextWriter tw =
new XmlTextWriter("gridstate.xml", System.Text.Encoding.ASCII);
tw.Formatting = Formatting.Indented;
// get the GridColumnStylesCollection from the dataGrid control
GridColumnStylesCollection colstyle =
dataGrid.TableStyles[0].GridColumnStyles;
int test = colstyle["No"].Width;
colWidths.Add("No", colstyle["No"].Width);
colWidths.Add("Firstname", colstyle["Firstname"].Width);
colWidths.Add("Lastname", colstyle["Lastname"].Width);
colWidths.Add("Email", colstyle["Email"].Width);
#region Document
tw.WriteStartDocument();
#region GridState
tw.WriteStartElement("GridState");
#region gridMainOptStrategy
tw.WriteStartElement("Control");
tw.WriteAttributeString("name", "MemoryGrid");
#region No
tw.WriteStartElement("Column");
tw.WriteAttributeString("name", "No");
tw.WriteString(colWidths["No"].ToString());
tw.WriteEndElement();
#endregion
#region Firstname
tw.WriteStartElement("Column");
tw.WriteAttributeString("name", "Firstname");
tw.WriteString(colWidths["Firstname"].ToString());
tw.WriteEndElement();
#endregion
#region Lastname
tw.WriteStartElement("Column");
tw.WriteAttributeString("name", "Lastname");
tw.WriteString(colWidths["Lastname"].ToString());
tw.WriteEndElement();
#endregion
#region Email
tw.WriteStartElement("Column");
tw.WriteAttributeString("name", "Email");
tw.WriteString(colWidths["Email"].ToString());
tw.WriteEndElement();
#endregion
tw.WriteEndElement();
#endregion
tw.WriteEndElement();
#endregion
tw.WriteEndDocument();
#endregion
tw.Close();
}
图 5:将 Grid 当前的列宽保存到 XML 文件。
最后,在某个时候,您需要调用 SaveCurrentGridState()
。否则,Grid 将无法在将来的某个时候调用当前状态。您可以在应用程序关闭时的关闭事件中保存 Grid 的状态。
private void MainForm_Closed(object sender, System.EventArgs e)
{
SaveCurrentGridState();
}
图 6:关闭事件处理程序。
就是这样!现在,您的 Grid 控件可以始终记住其列的宽度。一旦您关闭应用程序并再次加载它,您将不会注意到任何区别。在结束本文之前,还有几点说明,您可以扩展 XML 格式,以便它可以记住多个 Grid 控件。您需要做的就是按照以下 XML 文件结构化 Grid 状态
<?xml version="1.0" encoding="utf-8"?>
<GridState>
<Control name="Grid1">
<Column name="No">50</Column>
<Column name="FirstName">200</Column>
<Column name="LastName">200</Column>
<Column name="Email">250</Column>
<Column name="Default">100</Column>
</Control>
<Control name="Grid2">
<Column name="Id">30</Column>
<Column name="Item Description">200</Column>
<Column name="Price">200</Column>
<Column name="Default">100</Column>
</Control>
</GridState>
Figure 7: XML remember many controls' state
关注点
您需要在 LoadLastGridState()
和 SaveCurrentGridState()
中进行一些调整,我将在接下来的文章中编写。
历史
首次发布 - 记住一个 Grid 的列宽。