因为需要对某一个项目的数据文件(xml类型)的文件进行编辑,手动输入十分不变,并且之后需要数据校正的功能,所以对DevExpress控件进行的半生不熟的应用。<br /><首先放一下界面照片>--之后有个问题就是删除的控件资源仍然在程序designer.cs里面,不小心把系统提示给关了<br />主窗体是mdicontainer,里面有splitContainerControl,将TreeList窗体置入panel1中<br /><br />TreeForm<br /><br />两个窗体一个是ribbon类型的就是菜单栏文件、站场图、等对应不同的工具栏。但是container窗体只有一个,之后不知道怎么解决里面窗体的layout情况,之后填坑。<br />1.主窗体里主要写
public partial class MainView : DevExpress.XtraBars.Ribbon.RibbonForm{public TreeForm treeForm;//这块主要写一个全局的TreeForm窗体释放之后可以重新实例化,不知道有没有问题public MainView(){InitializeComponent();if (!mvvmContext1.IsDesignMode)InitializeBindings();SkinHelper.InitSkinGallery(skinRibbonGalleryBarItem1, true);//这一部分主要是皮肤控件//显示MDI窗体this.IsMdiContainer = true;showTreeForm();}public void showTreeForm()//显示TreeForm窗体{treeForm = new TreeForm();treeForm.MdiParent = this;treeForm.TopLevel = false;treeForm.Dock = DockStyle.Fill;this.splitContainerControl1.Panel1.Controls.Add(treeForm);treeForm.Show();}void InitializeBindings()//所以需要在工具箱里找到mvvmContext置于窗体{var fluent = mvvmContext1.OfType<MainViewModel>();}}
强烈建议添加皮肤因为 除了皮肤很多以外,还有很多很骚气的皮肤噢
康康多好看~~
还有万圣节特供款蛤蛤蛤
2.而在子窗体中则需要定义一个他的MdiParent窗体
public partial class TreeForm : DevExpress.XtraEditors.XtraForm{public static MainView parentForm = new MainView();//因为打开一次TreeForm,主窗体关闭了才会释放mainviewpublic TreeForm(){InitializeComponent();parentForm = (MainView)this.MdiParent;this.TopLevel = false;this.Dock = DockStyle.Fill;}private void TreeForm_Load(object sender, EventArgs e){try{this.Dock = DockStyle.Fill;MainView parentForm = (MainView)this.MdiParent;//这句是设置主窗体}catch (Exception ex){MessageBox.Show(ex.ToString());}}}
3.接下来就是点击主窗体调用xml中的绑定xml文件至TreeList事件
就是对象treeForm的showTree方法-第29行,需要提供文件列表即字符串数组,注意是完整路径
private void btnOpenFile_ItemClick(object sender, DevExpress.XtraBars.ItemClickEventArgs e){if(!HaveOpened(this,"TreeForm")){OpenChildForm(treeForm);showTreeForm();OpenXmlTree();}else{OpenChildForm(treeForm);treeForm.Activate();showTreeForm();OpenXmlTree();}}private void OpenXmlTree(){OpenFileDialog o = new OpenFileDialog();o.InitialDirectory = Application.StartupPath;o.Title = "打开文件";o.Multiselect = false;o.RestoreDirectory = true;o.Filter = "Xml文件(*.xml)|*.xml";o.Multiselect = true;if (o.ShowDialog() == DialogResult.OK){string[] xmlFile = o.FileNames;treeForm.ShowTree(xmlFile);}}//查看窗口是否已经被打开或存在private bool HaveOpened(XtraForm MdiParentForm, string MdiChildFormType){bool bReturn = false;for (int i = 0; i < MdiParentForm.MdiChildren.Length; i++){if (MdiParentForm.MdiChildren[i].GetType().Name == MdiChildFormType){MdiParentForm.MdiChildren[i].BringToFront();bReturn = true;break;}}return bReturn;}//MDI窗体不重复打开同一类型子窗体public void OpenChildForm(XtraForm formChild){formChild.Name = formChild.GetType().FullName;bool isOpened = false;foreach (XtraForm form in this.MdiChildren){//如果要显示的子窗体已经在子窗体的子窗体数组中,就把新建的多余的销毁if (formChild.GetType().ToString() == form.GetType().ToString()){form.Activate();formChild.Dispose();isOpened = true;break;}}if (!isOpened){formChild.MdiParent = this;formChild.Show();}}
4.之后就是TreeList中的一系列方法
首先是定义一些全局变量,list类型的,模型的DataTable,主窗体文件集合待转换成的DataTable集合,主窗体提供的xml文件的文件路径
public List
public List
public List
由于TreeForm中的TreeList需要时可编辑的,所以在构造函数中写
此处出现了个大大的问题第12.15行
<构造函数主要完成了:>
1)构造主窗体还有他在主窗体中的dock
2)得到已经在根目录中定义好的三个主要文件xml模型,GetFile得到文件路径,
3)treeList高亮SearchControl—搜索框中的文本,但是不能利用treelist中的enabledFiltering设置为true,即把高亮的文本匹配置前
public TreeForm(){InitializeComponent();parentForm = (MainView)this.MdiParent;this.TopLevel = false;this.Dock = DockStyle.Fill;//this.treeList2.OptionsBehavior.Editable = false;//treelist不可编辑GetFile();GetXmlModels();//得到模型文件的DataTable和树;//this.repositoryItemSearchControl1.Client = this.treeList2;//this.treeList2.OptionsBehavior.EnableFiltering = true;//有错误,不能自动过滤出最后的节点//原因好像是因为在treelist初始有树的情况下可以使用过滤,绑定数据源的情况下不能使用this.treeList2.OptionsFilter.FilterMode = FilterMode.Smart;//this.treeList2.FilterNode += treeList2_FilterNode;}private void GetFile()//集合模型文件的相对路径{string filepath = Application.StartupPath + "\\example\\xmlModels";xmlModelsFilePaths.Add(filepath + "\\TrackGeoInfo.xml");//轨道地理信息文件index=0xmlModelsFilePaths.Add(filepath + "\\MachineDatas.xml");//应用数据文件index=1xmlModelsFilePaths.Add(filepath + "\\IndexFile.xml");//区域索引文件index=2}private void GetXmlModels()//转换模型文件的DataTables模型{foreach (string s in xmlModelsFilePaths){ModelDataTables.Add(XmlFileToTable(s));}}
showPage—即treelist展示xml文件
#region MDI父窗体调用的函数//MDI父窗体打开页面时显示第一个文件树模型的操作public void ShowTree(string[] xmlFiles){pageCount += xmlFiles.Length;//总页数增加foreach (string s in xmlFiles){GetFilePages(s);}showPage(1);//显示第一份文件的xml树模型}#endregion
<读取的xml文件首先转换成为DataTable,然后绑定Treelist的DataSource为DataTable导致了后面的很多问题>
首先绑定数据源需要先设置TreeList的一些属性
点击RunDesigner,首先设置好TreeList中的Column这样之后才能绑定xml文件转成的DataTable
ParentID是斜的主要是因为设置了此column的visible为false不可见,<父级编号>是此列的Tag
注意设置Name和FiledName保持一致,因为Dev的TreeList和Winform的TreeView不太一样,有FiledName和KeyFieldName

想要忽略注释文本即xml文件中的需要这样写
//读取时忽略注释信息
XmlReaderSettings settings = new XmlReaderSettings();
settings.IgnoreComments = true;
XmlReader reader = XmlReader.Create(xmlFile, settings);
xmlDoc.Load(reader);
这些主要是设置节点名称、属性、和值
dr[“MenuName”] = Node.Name.ToString();
dr[“Tag”] = GetNodeAttributes(xmlnode);
dr[“value”] = GetText(xmlnode);
利用XmlFileToTable()就能够得到某一个xml文件的DataTable了
#region 读xml文件转化生成树结构//需要提供xml文件的文件名称--存在问题DOM方式是否可取private DataTable XmlFileToTable(string xmlFile){string fileName = xmlFile.Substring(xmlFile.LastIndexOf('\\') + 1, xmlFile.LastIndexOf('.') - xmlFile.LastIndexOf('\\') - 1);DataTable dt = new DataTable(fileName);dt.Columns.Add("ID");dt.Columns.Add("ParentID");dt.Columns.Add("MenuName");dt.Columns.Add("Tag");dt.Columns.Add("value");XmlDocument xmlDoc = new XmlDocument();//读取时忽略注释信息XmlReaderSettings settings = new XmlReaderSettings();settings.IgnoreComments = true;XmlReader reader = XmlReader.Create(xmlFile, settings);xmlDoc.Load(reader);///XmlNode rootnode = xmlDoc.DocumentElement;DataRow dr = dt.NewRow();int Id = 1;dr["ID"] = Id++;dr["ParentID"] = 0;dr["MenuName"] = rootnode.Name.ToString();dr["Tag"] = GetNodeAttributes(rootnode);dr["value"] = GetText(rootnode);dt.Rows.Add(dr);if (rootnode.HasChildNodes){XmlNodeList xmlnodelist = rootnode.ChildNodes;foreach (XmlNode xmlnode in xmlnodelist){dr = dt.NewRow();dr["ID"] = Id++;dr["ParentID"] = 1;dr["MenuName"] = xmlnode.Name.ToString();dr["Tag"] = GetNodeAttributes(xmlnode);dr["value"] = GetText(xmlnode);dt.Rows.Add(dr);if (xmlnode.HasChildNodes){int j = 1;XmlNodeList nodelist = xmlnode.ChildNodes;foreach (XmlNode node in nodelist){int pId = Id;dr = dt.NewRow();dr["ID"] = Id++;dr["ParentID"] = pId - j;dr["MenuName"] = node.Name.ToString();dr["Tag"] = GetNodeAttributes(node);dr["value"] = GetText(node);//node.Value.ToString();dt.Rows.Add(dr);j++;if (node.HasChildNodes){int i = 1;XmlNodeList list = node.ChildNodes;foreach (XmlNode Node in list){if (Node.NodeType == XmlNodeType.Text){continue;}else{int ppId = Id;dr = dt.NewRow();dr["ID"] = Id++;dr["ParentID"] = ppId - i;dr["MenuName"] = Node.Name.ToString();dr["Tag"] = GetNodeAttributes(xmlnode);dr["value"] = GetText(xmlnode);dt.Rows.Add(dr);i++;j++;}}}else{continue;}}}else{continue;}}}reader.Close();return dt;}//得到此节点的属性值,因为DOM方式属性节点即此节点的属性,和文本节点和注释节点不一样private string GetNodeAttributes(XmlNode node){string result = null;if(node.Attributes!=null){foreach(XmlAttribute x in node.Attributes){result += x.Name.ToString() + "=" + x.Value.ToString()+" ";}}else{}return result;}private string GetText(XmlNode node)//得到节点内的值{string result = null;string nodename = node.Name.ToString();if (node.HasChildNodes&&node.ChildNodes.Count==1){if (node.InnerText != null)result = node.InnerText.ToString();}return result;}//private DataTable GetCurrentDataTable(){string text = this.Text;DataTable temp = new DataTable();foreach(DataTable dt in fileDataTables){if(text==dt.TableName){temp = dt;temp.TableName = text;break;}}return temp;}#endregion
<分页操作—转换好的DataTable需要显示在TreeList中,并且不是一个单独的文件,所以可以进行分页>
此处有问题——由于showPage中主要是针对的主窗体的文件,并没有针对xmlmodel的文件,所以主要重载了一个showpage方法
showpage方法主要实现了绑定数据源即超出页码限制datanavigator的按钮无效。
由于DataNavigator的Button_Click调用了showEvent,保证了点击不同的pageindex,显示不同的showpage

#region 分页操作private void GetFilePages(string xmlFile)//得到多个文件的DataTables集合于fileDataTables{XmlDocument doc = new XmlDocument();doc.Load(xmlFile);XmlNode rootnode = doc.DocumentElement;fileDataTables.Add(XmlFileToTable(xmlFile));}//显示某一页DataTablepublic int pageIndex = 1;public int pageCount = 0;//初始赋值为0;private void showPage(int pageindex){try{dataNavigator1.Buttons.CustomButtons[0].Enabled = true;dataNavigator1.Buttons.CustomButtons[1].Enabled = true;dataNavigator1.Buttons.CustomButtons[2].Enabled = true;dataNavigator1.Buttons.CustomButtons[3].Enabled = true;DataTable dt = fileDataTables[pageindex - 1];if (pageIndex == 1 || pageIndex == 0){dataNavigator1.Buttons.CustomButtons[0].Enabled = false;dataNavigator1.Buttons.CustomButtons[1].Enabled = false;}if (dt.Rows.Count == 0){pageIndex = 0;}if (pageCount == pageIndex){dataNavigator1.Buttons.CustomButtons[2].Enabled = false;dataNavigator1.Buttons.CustomButtons[3].Enabled = false;}this.treeList2.Nodes.Clear();this.treeList2.DataSource = fileDataTables[pageindex - 1];this.treeList2.ExpandAll();this.Text = fileDataTables[pageindex - 1].TableName;dataNavigator1.TextStringFormat = string.Format("第{0}页,共{1}页", pageindex, pageCount);message.Caption = string.Format("共有{0}个节点", fileDataTables[pageindex - 1].Rows.Count);}catch (Exception ex){XtraMessageBox.Show(ex.ToString());}}private void showPage(DataTable dataTable){this.treeList2.Nodes.Clear();this.treeList2.DataSource = dataTable;this.treeList2.ExpandAll();this.Text = dataTable.TableName;dataNavigator1.TextStringFormat = string.Format("第{0}页,共{1}页",1 , 1);message.Caption = string.Format("共有{0}个节点", dataTable.Rows.Count);}//点击进度条事件改变treelist中显示的树private void dataNavigator1_ButtonClick(object sender,NavigatorButtonClickEventArgs e){ShowEvent(e.Button);}private void ShowEvent(NavigatorButtonBase button){NavigatorCustomButton btn = (NavigatorCustomButton)button;string type = btn.Tag.ToString();if (type == "首页"){pageIndex = 1;//pageIndex改变}if (type == "下一页"){pageIndex++;}if (type == "末页"){pageIndex = pageCount;}if (type == "上一页"){pageIndex--;}showPage(pageIndex);}//跳转按钮的操作private void btn_GoToPage_Click(object sender, EventArgs e){if (pageCount > 0 && Convert.ToInt32(txt_pageindex.Text) <= pageCount){pageIndex = Convert.ToInt32(txt_pageindex.Text);showPage(pageIndex);}else{XtraMessageBox.Show("请保证输入页码有效");}}//转页文本框的快捷键操作private void txt_pageindex_KeyPress(object sender, KeyPressEventArgs e){if (e.KeyChar != '\b')//这是允许输入退格键{int len = txt_pageindex.Text.Length;if (len < 1 && e.KeyChar == '0'){e.Handled = true;}else if ((e.KeyChar < '0') || (e.KeyChar > '9'))//这是允许输入0-9数字{e.Handled = true;}}}private void txt_pageindex_KeyDown(object sender, KeyEventArgs e){if(e.KeyData==Keys.Enter){btn_GoToPage_Click(sender, e);}}#endregion
<过滤数据事件—>
构造函数中写首先定义searchControl的client必须设置为TreeList2
this.repositoryItemSearchControl1.Client = this.treeList2;
//this.treeList2.OptionsBehavior.EnableFiltering = true;//有错误,不能自动过滤出最后的节点
//原因好像是因为在treelist初始有树的情况下可以使用过滤,绑定数据源的情况下不能使用
this.treeList2.OptionsFilter.FilterMode = FilterMode.Smart;
//this.treeList2.FilterNode += treeList2_FilterNode;
以下是TreeList的过滤节点事件
private void treeList2_FilterNode(object sender, FilterNodeEventArgs e){if (treeList2.DataSource == null) return;string NodeText = e.Node.GetDisplayText("MenuName");if (string.IsNullOrWhiteSpace(NodeText)) return;bool IsVisible = NodeText.ToUpper().IndexOf(searchControl.EditValue.ToString().ToUpper()) >= 0;if (IsVisible){TreeListNode Node = e.Node.ParentNode;while (Node != null){if (!Node.Visible){Node.Visible = true;Node = Node.ParentNode;}elsebreak;}}e.Node.Visible = IsVisible;e.Handled = true;}
<连带—父节点选中则子节点选中,每个子节点选中则父节点选中>
//点击节点操作,出现复选框private void NodeEdit_ItemClick(object sender, ItemClickEventArgs e){this.treeList2.OptionsBehavior.Editable = true;this.treeList2.OptionsView.ShowCheckBoxes = true;//出现复选框this.treeList2.OptionsBehavior.AllowIndeterminateCheckState = true;//允许一部分子节点选中}//节点选中前的事件private void treeList2_BeforeCheckNode(object sender, DevExpress.XtraTreeList.CheckNodeEventArgs e){if (e.PrevState == CheckState.Checked){ e.State = CheckState.Unchecked; }else{ e.State = CheckState.Checked; }}//节点选中后事件private void treeList2_AfterCheckNode(object sender, DevExpress.XtraTreeList.NodeEventArgs e){SetCheckedChildNodes(e.Node, e.Node.CheckState);SetCheckedParentNodes(e.Node, e.Node.CheckState);//MessageBox.Show(e.Node.GetDisplayText("MenuName"));//this.treeList2.Selection.Add(e.Node);//AddCheckNodes(e.Node);//chooseNodes.Add(e.Node);}//此节点选中则所有子节点选中即子节点的子节点也选中.private void SetCheckedChildNodes(TreeListNode node, CheckState check){for (int i = 0; i < node.Nodes.Count; i++){node.Nodes[i].CheckState = check;SetCheckedChildNodes(node.Nodes[i], check);}}//遍历所有子节点都选中则父节点选中private void SetCheckedParentNodes(TreeListNode node, CheckState check){if (node.ParentNode != null)//选中节点有父节点{bool IsSelected = false;CheckState state;for (int i = 0; i < node.ParentNode.Nodes.Count; i++){state = (CheckState)node.ParentNode.Nodes[i].CheckState;//每个同胞节点的选中状态if (!check.Equals(state))//同胞节点状态不同则拒绝,退出{IsSelected = !IsSelected;break;}}if (IsSelected)//b为true即子节点并没有全部选中,此时父节点的状态为不确定状态{node.ParentNode.CheckState = CheckState.Indeterminate;}else{node.ParentNode.CheckState = check;}SetCheckedParentNodes(node.ParentNode, check);}}
<弹出菜单操作>—-鼠标点击事件,需要工具箱的popupMenu,右击出现菜单按钮
编辑时候需要点击customize

//右键弹出菜单private void treeList2_MouseDown(object sender, MouseEventArgs e){TreeList tree = sender as TreeList;if (e.Button == MouseButtons.Right&& ModifierKeys == Keys.None&& treeList2.State == TreeListState.Regular){Point p = new Point(Cursor.Position.X, Cursor.Position.Y);TreeListHitInfo hitinfo = tree.CalcHitInfo(e.Location);if (hitinfo.HitInfoType == DevExpress.XtraTreeList.HitInfoType.Cell){tree.SetFocusedNode(hitinfo.Node);}if (tree.FocusedNode != null){popupMenu1.ShowPopup(p);}}}
一些元数据(数据的数据)解析
可以得到
Point p = new Point(Cursor.Position.X, Cursor.Position.Y);//这一句得到光标的X,Y坐标
TreeListHitInfo hitinfo = tree.CalcHitInfo(e.Location);//这一句得到光标下的TreeList下坐落某个元素(cell/column/row等等)
类TreeListHitInfo-------Gets the column located under the test point.方法public TreeListHitInfo CalcHitInfo(Point pt);// 摘要:// Returns information about the Tree List's elements which are located at the specified// point.//// 参数:// pt:// A System.Drawing.Point structure which specifies test point coordinates relative// to the Tree List's top-left corner.//// 返回结果:// A DevExpress.XtraTreeList.TreeListHitInfo object which contains information about// the Tree List's elements located at the test point.方法SetFocusNode(TreeListNode node)// 摘要:// Sets focus to a specific node within the current DevExpress.XtraTreeList.TreeList// control.//// 参数:// node:// The node to set focus on.//// 返回结果:// The index of the focused node among visible nodes.public virtual int SetFocusedNode(TreeListNode node);
