Cara menggunakan kawalan DevExpress TreeList dan TreeListLookupEdit dalam rangka kerja

How Use Devexpress Treelist



Kawalan Bentuk DevExpress Lebih daripada 140 kawalan dan perpustakaan UI dibina, sesuai untuk membina aplikasi yang lancar, cantik dan mudah digunakan. DevExpress WinForm v20.1 baru dilancarkan, ingin mengalaminya? Klik untuk memuat turun >>

Senarai pokok kawalan TreeList yang disediakan oleh DevExpress dan senarai senarai turun-bawah pokok TreeListLookupEdit kedua-duanya merupakan kawalan yang sangat kuat. Ia berbeza dengan kawalan Winform TreeView tradisional kami yang digunakan. Saya secara amnya mencampurkan kawalan ini mengikut keadaan dalam pembangunan Winform. Tetapi secara keseluruhan, TreeList dan TreeListLookupEdit berdasarkan DevExpress agak tampan. Artikel ini memperkenalkan penggunaan dan pemprosesan kedua-dua kawalan ini dalam projek Winform sebenar.



Penggunaan kawalan DevExpress TreeList



Sebagai contoh, dalam pengurusan menu, kita tahu bahawa menu pada umumnya adalah nod hierarki. Untuk keperluan paparan intuitif, kami secara amnya memaparkan menu dengan kawalan senarai pokok. Antaranya, kami akan menggunakan kawalan TreeList, seperti yang ditunjukkan dalam antara muka berikut.



WinForm

Antaranya, TreeList dan inputControl digunakan bersama untuk meningkatkan keramahan antara muka. Kita boleh menapis dan memaparkan nod dengan memasukkan kata kunci.

WinForm



Sebagai contoh, setelah memasukkan konten penyaringan, tanyakan node senarai pohon penyaringan, seperti yang ditunjukkan di bawah ini, sehingga pengguna dapat dengan cepat dan kabur mencari simpul pohon yang ditentukan.

WinForm

Dengan pengertian umum, mari kita memahami penggunaan kawalan TreeList. Dalam paparan reka bentuk antara muka menu, kami menambahkan kawalan menu klik kanan ContextMenuStrip, dan kemudian mengedit beberapa item menu, seperti yang ditunjukkan pada antara muka berikut.

WinForm

Kemudian seret dalam kawalan ImageCollection koleksi gambar, dan tambahkan beberapa gambar kawalan kepadanya (anda juga boleh membiarkannya kosong dan menentukannya secara dinamik, seperti dalam contoh ini)

WinForm

Menginisialisasi senarai pohon umumnya dibagi menjadi beberapa fungsi, salah satunya adalah untuk menginisialisasi daftar pohon, yang lain adalah untuk memproses penyaringan pertanyaan yang mengikat, dan yang lain adalah untuk mengikat data ke daftar pohon, seperti yang ditunjukkan dalam kod berikut.

private async void FrmMenu_Load(object sender, EventArgs e) { //List information InitTree() InitSearchControl() await BindTree() }

Operasi tak segerak digunakan di atas, biasanya kita tidak perlu menggunakan asinkron, di sini kita menanganinya mengikut keadaan.

Kod operasi untuk memulakan senarai pokok ditunjukkan di bawah.

/// /// Initialize the tree control /// private void InitTree() { this.tree.Columns.Clear() //Add display column this.tree.Columns.Add(new TreeListColumn {FieldName = 'Id', Caption = 'Id' })//Add a hidden field to store the required ID this.tree.Columns.Add(new TreeListColumn {FieldName = 'Name', Caption = 'Menu Name', Width = 160, VisibleIndex = 0 }) //Set the hierarchy and properties of the tree control tree.KeyFieldName = 'Id' tree.ParentFieldName = 'PID' this.tree.OptionsBehavior.Editable = false this.tree.OptionsView.EnableAppearanceOddRow = true this.tree.OptionsView.EnableAppearanceEvenRow = true this.tree.OptionsDragAndDrop.DragNodesMode = DragNodesMode.None//Dragging is not allowed //Set the icon set and step-by-step icon of the tree this.tree.SelectImageList = this.imageCollection1 this.tree.CustomDrawNodeImages += (object sender, CustomDrawNodeImagesEventArgs e) => { //int maxCount = this.imageCollection1.Images.Count //var index = e.Node.Level 

Untuk memulakan kod pemprosesan senarai pokok, kami juga dapat menggunakan fungsi peluasan untuk mempermudahnya, seperti yang ditunjukkan di bawah.

/// /// Initialize the tree control /// private void InitTree() { this.tree.Columns.Clear() this.tree.OptionsDragAndDrop.DragNodesMode = DragNodesMode.None//Dragging is not allowed //Control extension function packaging processing this.tree.CreateColumn('Name', 'Menu Name', 160, true) this.tree.InitTree('Id', 'PID', null, false, false) //Set the icon set and step-by-step icon of the tree this.tree.SelectImageList = this.imageCollection1 this.tree.CustomDrawNodeImages += (object sender, CustomDrawNodeImagesEventArgs e) => { //int maxCount = this.imageCollection1.Images.Count //var index = e.Node.Level 

Kod untuk memulakan kawalan carian SearchControl ditunjukkan di bawah.

/// /// Achieve filtering query of tree nodes /// private void InitSearchControl() { this.searchControl1.Client = this.tree this.tree.FilterNode += (object sender, FilterNodeEventArgs e) => { if (tree.DataSource == null) return string nodeText = e.Node.GetDisplayText('Name')//Fill in FieldName as parameter if (string.IsNullOrWhiteSpace(nodeText)) return bool isExist = nodeText.IndexOf(searchControl1.Text, StringComparison.OrdinalIgnoreCase) >= 0 if (isExist) { var node = e.Node.ParentNode while (node != null) { if (!node.Visible) { node.Visible = true node = node.ParentNode } else break } } e.Node.Visible = isExist e.Handled = true } }

Perkara di atas adalah untuk memulakan kawalan senarai pokok, kita juga perlu mengikat data dengannya. Kod utama untuk senarai pokok adalah pengikatan data dan pengikatan ikon.

this.tree.SelectImageList = this.imageCollection1 this.tree.DataSource = result.Items

Namun, kerana ikon kami dibina secara dinamik dari sumber data, ikon tersebut perlu disimpan dalam koleksi agar mudah diberikan kepada kawalan senarai pokok. Berikut adalah kod pengikat yang lengkap.

/// /// Data source of binding tree /// private async Task BindTree() { var pageDto = new MenuPagedDto() var result = await MenuApiCaller.Instance.GetAll(pageDto) //Used to store the corresponding ID and index order IdIndexDict = new Dictionary() //Refresh the node picture this.imageCollection1 = new ImageCollection() this.imageCollection1.ImageSize = new Size(16, 16) if (result != null && result.Items != null) { foreach (var menuInfo in result.Items) { var image = LoadIcon(menuInfo) this.imageCollection1.Images.Add(image) //Add a picture serial number for each menu ID, easy to find if(!IdIndexDict.ContainsKey(menuInfo.Id)) { int index = this.imageCollection1.Images.Count-1//The last number IdIndexDict.Add(menuInfo.Id, index) } } } //imageCollection has changed and needs to be re-assigned to treeList this.tree.SelectImageList = this.imageCollection1 this.tree.DataSource = result.Items this.tree.ExpandAll() }

Sekiranya kita perlu mendapatkan nilai mengikat simpul pohon yang ditentukan, kita dapat memperoleh nilai medan melalui FocusNode saat ini, seperti yang ditunjukkan dalam kod berikut.

/// /// Edit list data /// private async Task EditTreeData() { string ID = string.Concat(this.tree.FocusedNode.GetValue(Id_FieldName)) if (!string.IsNullOrEmpty(ID)) { FrmEditMenu dlg = new FrmEditMenu() dlg.ID = ID dlg.OnDataSaved += new EventHandler(dlg_OnDataSaved) dlg.InitFunction(LoginUserInfo, FunctionDict)//Assign user permission information to the subform if (DialogResult.OK == dlg.ShowDialog()) { await BindTree() } } }

Di atas adalah proses penggunaan kawalan TreeList, perhatian utama adalah pengikatan sumber data dan operasi pengikatan ikon.

Sekiranya kita juga membiarkan senarai pokok diseret untuk menyesuaikan kedudukan induk, maka kita dapat mengatasinya dengan peristiwa seret.

this.tree.CalcNodeDragImageIndex += new DevExpress.XtraTreeList.CalcNodeDragImageIndexEventHandler(this.Tree_CalcNodeDragImageIndex) this.tree.DragDrop += new System.Windows.Forms.DragEventHandler(this.Tree_DragDrop) this.tree.DragOver += new System.Windows.Forms.DragEventHandler(this.Tree_DragOver) private void Tree_DragOver(object sender, DragEventArgs e) { TreeListNode dragNode = e.Data.GetData(typeof(TreeListNode)) as TreeListNode e.Effect = GetDragDropEffect(sender as TreeList, dragNode) } private async void Tree_DragDrop(object sender, DragEventArgs e) { TreeListNode dragNode, targetNode TreeList tl = sender as TreeList Point p = tl.PointToClient(new Point(e.X, e.Y)) dragNode = e.Data.GetData(typeof(TreeListNode)) as TreeListNode targetNode = tl.CalcHitInfo(p).Node //Update data after moving var id = string.Concat(dragNode.GetValue('Id')).ToInt64() var pid = string.Concat(targetNode.GetValue('Id')).ToInt64() await OrganizationUnitApiCaller.Instance.Move(new MoveOrganizationUnitDto() { Id = id, ParentId = pid }) await BindTree() e.Effect = DragDropEffects.None } private void Tree_CalcNodeDragImageIndex(object sender, CalcNodeDragImageIndexEventArgs e) { TreeList tl = sender as TreeList if (GetDragDropEffect(tl, tl.FocusedNode) == DragDropEffects.None) e.ImageIndex = -1 // no icon else e.ImageIndex = 1 // the reorder icon (a curved arrow) }

WinForm

Penggunaan kawalan DevExpress TreeListLookupEdit

TreeList dan TreeListLookupEdit umumnya muncul secara berpasangan. Secara amnya, apabila kita perlu menyesuaikan nod induk, senarai drop-down TreeListLookupEdit berbentuk pokok ini terlibat.

Untuk kemudahan, kami secara amnya menentukan kawalan khusus untuk menangani pengikatan senarai drop-down ini, jadi tidak perlu mengikat data dan kod inisialisasi setiap saat.

WinForm

private void FunctionControl_Load(object sender, EventArgs e) { if (!this.DesignMode) { InitTree() BindTree() } } /// /// Initialize the tree /// /// private void InitTree() { this.txtMenu.Properties.ValueMember = 'Id' this.txtMenu.Properties.DisplayMember = 'Name' var tree = this.treeListLookUpEdit1TreeList tree.Columns.Clear() //Control extension function packaging processing tree.CreateColumn('Name', 'Menu Name', 160, true) tree.InitTree('Id', 'PID', null, false, false) //Set the icon set and step-by-step icon of the tree tree.SelectImageList = this.imageCollection1 tree.CustomDrawNodeImages += (object sender, CustomDrawNodeImagesEventArgs e) => { int maxCount = this.imageCollection1.Images.Count var index = e.Node.Level  MenuApiCaller.Instance.GetAll(new MenuPagedDto() { })) if (result != null && result.Items != null) { tree.DataSource = result.Items tree.ExpandAll()//Expand all } //Perform post-binding processing if (DataBinded != null) { DataBinded(null, null) } }

Antaranya, AsyncContext.Run memperlakukan fungsi tak segerak sebagai penggunaan segerak. Secara amnya, kami menggunakan operasi segerak pada kawalan pengguna untuk mengelakkan kelewatan pengikatan data dan tanpa pemprosesan

Dengan merumuskan ValueMember dan DisplayMember, konten dapat ditampilkan secara normal, dan operasi nilai yang diperlukan dapat disimpan kemudian.

this.txtMenu.Properties.ValueMember = 'Id' this.txtMenu.Properties.DisplayMember = 'Name'

Masih terdapat kawalan TreeList dalam kawalan TreeListLookupEdit. Operasi kawalan ini sama persis dengan kawalan TreeList yang kami nyatakan di atas. Kita boleh memulakan dan mengikatnya dengan cara senarai pokok.

Kesan antara muka adalah seperti berikut.

WinForm

Kawalan senarai pokok berkembang seperti gambar di bawah.

WinForm

Artikel ini diterbitkan semula dari Blog Garden-Wu Huacong