因为需要对某一个项目的数据文件(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,主窗体关闭了才会释放mainview
public 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=0
xmlModelsFilePaths.Add(filepath + "\\MachineDatas.xml");//应用数据文件index=1
xmlModelsFilePaths.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));
}
//显示某一页DataTable
public 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;
}
else
break;
}
}
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);