1.其实实现主窗体的刷新无非就是比较简单的调用load事件重新加载数据绑定,但是这样的效果会带来,无状态刷新,页面无法保存上一次的页面状态,比如
刷新前
刷新后
,如果点击刷新按钮执行的话,那么树形菜单会恢复关闭状态,那么如何实现这种刷新保持状态的效果呢?我们这边可以通过两个方法进行实现,原理未为:使用Hashtable来保存每个节点的状态.在把所有Nodes清空掉之前遍历TreeView,取得每个节点的状态,然后根据DataSet重新添加Nodes,添加完成后得根据刚才建立的Hashtable信息来设置每个节点的状态
代码如下:
主要就是给TreeView添加Nodes的前面和后面分别添加上这两个函数GetTreeNodesStatus(tv.Nodes);SetTreeNodesStatus(tv.Nodes);
//绑定根节点
private void BindRoot()
{
GetTreeNodesStatus(treeView1.Nodes);//在这里绑定前的节点状态获取保存
DataRow[] rows = dt.Select("FID=0");//取根
this.treeView1.Nodes.Clear();//多次加载前的清理
foreach (DataRow dRow in rows)
{
TreeNode rootNode = new TreeNode();
rootNode.Tag = dRow;
rootNode.ImageIndex = 1;
rootNode.SelectedImageIndex = 1;
rootNode.Text = dRow["REPORTNAME"].ToString();
this.treeView1.Nodes.Add(rootNode);
BindChildAreas(rootNode);
}
}
//递归绑定子节点
private void BindChildAreas(TreeNode fNode)
{
DataRow dr = (DataRow)fNode.Tag;
//父节点数据关联的数据行
int fid = Convert.ToInt32(dr["ID"].ToString());
//父节点ID
DataRow[] rows = dt.Select("fid=" + fid);//子区域
if (rows.Length == 0) //递归终止,区域不包含子区域时
{ return; }
foreach (DataRow dRow in rows)
{
TreeNode node = new TreeNode();
node.Tag = dRow; node.Text = dRow["REPORTNAME"].ToString(); //添加子点
//如果dRow["IFEND"]=0说明是类型,应该用文件夹
if (Convert.ToInt32(dRow["IFEND"])== 0)
{
node.ImageIndex = 1;
node.SelectedImageIndex = 1;
}
else
{
//对报表进行图标区分
if (dRow["REPORTTYPE"].ToString() == "production")
{
node.ImageIndex = 2; node.SelectedImageIndex = 2;
}
else { node.ImageIndex = 0; node.SelectedImageIndex = 0; }
}
fNode.Nodes.Add(node); //递归
BindChildAreas(node);
}
SetTreeNodesStatus(treeView1.Nodes);//绑定后的节点状态设置
}/// <summary>
/// 保存TreeNode状态
/// </summary>
/// <param name="nodes"></param>
private void GetTreeNodesStatus(TreeNodeCollection nodes)
{
foreach (TreeNode node in nodes)
{
if (node.IsExpanded)
{
NodesStatus[node.FullPath] = true;
}
else
{
NodesStatus.Remove(node.FullPath);
}
if (node.IsSelected)
{
SelectNodeFullPath = node.FullPath;
}
GetTreeNodesStatus(node.Nodes);
}
}/// <summary>
/// 设置TreeNode状态
/// </summary>
/// <param name="nodes"></param>
private void SetTreeNodesStatus(TreeNodeCollection nodes)
{
foreach (TreeNode node in nodes)
{
if (NodesStatus[node.FullPath] != null)
{
node.Expand();
}
if (node.FullPath == SelectNodeFullPath)
{
this.treeView1.SelectedNode = node;
}
SetTreeNodesStatus(node.Nodes);
}
}
通过以上代码在load事件中重新加载的话,就不会再关闭节点了,会保持当前状态;
第二个问题来了,如何在子窗体中增加数据后绑定到主窗体显示,在子窗体关闭的时候展示在列表中?
我们这边可以通过两种方式进行实现:
第一种:1.在父窗体弹出子窗体的事件打开ShowDialog()之前,对父窗体做一个hide的假关闭
ChildForm fr2 = new ChildForm ();
this.Hide();
fr2.ShowDialog();
然后在子窗体的处理事件中,数据处理后的回调,对父窗体隐藏做一个展示效果
this.Close();
ParentForm fr2 = new ParentForm ();
fr2.ShowDialog();
以上就是第一种方式处理,但是这样处理增加或者修改数据的话,返回到主窗体后,主窗体还是一个关闭树的状态效果,无法保持上一次展开树菜单的效果?
因此我们需要考虑,在子窗体关闭之后,需要调用我们一开始说的绑定树列表的方法,里面会记录状态,那么我们如何去调用主窗体的这个绑定过程呢?
第二种:1.定义一个绑定的方法,无参数的绑定方法
//子窗体调用重新加载数据的方法
public void reLoad_method()
{
//窗体数据初始化方法,父窗体中的全部操作,调用此方法可实现数据的刷新
InitDataTable();
BindRoot();
BindViewList(rtsno);//rtsno为全局sno
}
2.父窗体弹出子窗体的事件打开ShowDialog()之前,设置拥有此窗体的窗体
ChildForm fr2 = new ChildForm (l);
fr2.Owner = this;
fr2.ShowDialog();
3.在子窗体中调用父窗体的加载记录状态的方法
ParentForm fr;
fr= (ParentForm)this.Owner;
fr.reLoad_method();//reLoad_method就是重新加载数据的函数
总结:第二种方式体验效果更直观,也能对主窗体的状态记录有一个保持,就不会回填之后主窗体被重新加载状态消失。
在这次开发过程中,出现了一个问题,就是窗体弹出来的事件show和showDialog的区别,用的第二种方法,如果直接弹出子窗体用show事件的话,那么子窗体调用父窗体加载记录方法会抛异常,如果用showDialog的话,就不会出现异常的问题,这两者的区别具体见博客:https://blog.csdn.net/xingkongtianyuzhao/article/details/104067642