WinForm應用實戰開發指南 - 如何完成樹形列表(TreeList)的快捷綁定?

在一些字典綁定中,往往爲了方便展示詳細數據,需要把一些結構樹展現在樹列表TreeList控件中或者下拉列表的樹形控件TreeListLookUpEdit控件中,爲了快速的處理數據的綁定操作,比較每次使用涉及太多細節的操作,我們可以把相關的數據綁定操作,放在一些輔助類的擴展函數中進行處理,這樣可以更方便的,更簡潔的處理數據綁定操作,本文將介紹TreeList控件和TreeListLookUpEdit控件在擴展函數中的處理操作。

PS:給大家推薦一個C#開發可以用到的界面組件——DevExpress WinForms,它能完美構建流暢、美觀且易於使用的應用程序,無論是Office風格的界面,還是分析處理大批量的業務數據,它都能輕鬆勝任!

TreeList控件的綁定操作

TreeList本身就是一個樹形數據的展示控件,可以展示常規的二維表,也可以展示具有嵌套關係的二維表,數據源可以是多種方式的,支持Datable的數據源的嵌套展示。

單個列信息的樹形列表展示界面效果:

WinForm應用實戰開發指南 - 如何實現列表集合控件的拖動?

類似GridView的嵌套列表展示的TreeList界面效果:

WinForm應用實戰開發指南 - 如何實現列表集合控件的拖動?

這些界面都比較常見,也是我們經常碰到的處理效果,但是TreeList的界面設置有很多特性,如果每次拷貝這些代碼,需要很多,也不便於維護,因此我們建立一些擴展函數來處理界面元素的綁定,就非常必要。

WinForm應用實戰開發指南 - 如何實現列表集合控件的拖動?

本文介紹基於TreeList和TreeListLookUpEdit控件的綁定即可。兩個類型控件的數據源,都可以是DataTable類型,也可以是IList集合類型,如下所示是基於SQLSugar開發框架,返回的數據結構是IList類型的。

WinForm應用實戰開發指南 - 如何實現列表集合控件的拖動?

所以一般樹形列表的綁定操作,提供一個方法來獲取數據並綁定即可。

/// <summary>
/// 綁定樹的數據源
/// </summary>
private async void BindTree()
{
var list = await BLLFactory<IDictTypeService>.Instance.GetAllAsync();
this.tree.DataSource = list?.Items;
this.tree.ExpandAll();
}

如果使用原生代碼初始化樹列表,那麼代碼如下所示。

//使用原生代碼處理
//添加顯示列
this.tree.Columns.Add(new TreeListColumn{ FieldName= "Id", Caption= "ID"});//增加一個隱藏的字段,存儲需要的ID
this.tree.Columns.Add(new TreeListColumn{ FieldName= "Name", Caption= "字典類型名稱", Width=160, VisibleIndex =0});
//設置樹控件的層次關係及屬性
tree.KeyFieldName = "Id";
tree.ParentFieldName = "PID";
this.tree.OptionsBehavior.Editable = false;
this.tree.OptionsView.ShowColumns = false;
this.tree.OptionsView.ShowCheckBoxes = false;
this.tree.OptionsView.EnableAppearanceOddRow = true;
this.tree.OptionsView.EnableAppearanceEvenRow = true;

而實現查詢過濾的操作,還需要另外處理代碼,我們看看大概的代碼如下。

/// <summary>
/// 實現樹節點的過濾查詢
/// </summary>
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");//參數填寫FieldName
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;
};
}

這些是比較常見的操作,我們把它封裝爲擴展函數,然後根據特性傳入對應參數實現即可。

最後簡單的三行代碼來簡單處理,可以達到同樣的效果就可以了。

//控件擴展函數封裝處理
this.tree.CreateColumn("Name", "字典類型名稱", 160, true);
this.tree.InitTree("Id", "PID", "-1", false, false);
this.tree.InitSearchControl(this.searchControl1, "Name");

我們擴展方法放在一個單獨的文件中,標註爲靜態類即可。

/// <summary>
/// TreeList控件的擴展函數
/// </summary>
public static class TreeList_Extension

其中提供幾個對TreeList 常見的封裝處理方法就可以了。

WinForm應用實戰開發指南 - 如何實現列表集合控件的拖動?

對於一些不常見的屬性,我們保留它即可,如下界面代碼是對TreeList綁定展示多個列的處理操作。

/// <summary>
/// 初始化TreeList控件,展現嵌套的列表。
/// </summary>
private void InitControl()
{
this.tree.Columns.Clear();//控件擴展函數封裝處理
this.tree.CreateColumn("Name", "機構名稱", 160, true);
this.tree.CreateColumn("HandNo", "機構編碼", 80, true);
this.tree.CreateColumn("Category", "機構分類", 80, true);
this.tree.CreateColumn("Address", "機構地址", 160, true);
this.tree.CreateColumn("InnerPhone", "內線電話", 80, true);
this.tree.CreateColumn("OuterPhone", "外線電話", 80, true);
this.tree.CreateColumn("SortCode", "排序碼", 80, true);
this.tree.InitTree("Id", "PID", null, true, true);

this.tree.OptionsView.RowImagesShowMode = RowImagesShowMode.InCell;//緊湊型圖標
this.tree.ExpandAll();

// 列過濾處理
this.tree.OptionsView.ShowAutoFilterRow = true;//顯示過濾行
this.tree.OptionsBehavior.EnableFiltering = true;//開啓過濾功能

//初始化樹節點選擇事件
this.tree.FocusedNodeChanged += delegate (object sender, FocusedNodeChangedEventArgs e)
{
this.FocusedNodeChanged();
};
//樹節點雙擊處理事件
this.tree.DoubleClick += (s, e) =>
{
if (this.tree.FocusedNode != null)
{
string ID = string.Concat(this.tree.FocusedNode.GetValue("Id"));
MessageDxUtil.ShowTips("Id=" + ID);
}
};
//編輯記錄失去焦點後校驗處理
this.tree.ValidateNode += (s, e) =>
{
Console.WriteLine(this.tree.FocusedNode.GetValue("Name"));
};
}

實現類似GridView的嵌套列表展示的TreeList界面效果如下所示。

WinForm應用實戰開發指南 - 如何實現列表集合控件的拖動?

TreeListLookUpEdit控件綁定操作

在一些參考的列表中,我們往往需要展示更豐富一點的列表內容,如下所示。

WinForm應用實戰開發指南 - 如何實現列表集合控件的拖動?
WinForm應用實戰開發指南 - 如何實現列表集合控件的拖動?

如果有嵌套列表的,展示嵌套列表的處理:

WinForm應用實戰開發指南 - 如何實現列表集合控件的拖動?

對於下拉的樹形列表,雖然這個控件比TreeList更復雜一些,它是下拉列表和TreeList的整合體,不過我們也可以用類似的擴展函數方法,來簡單的實現數據的綁定展示。

如對於常規的數據綁定,我們大概的代碼如下所示。

//TreeListLookupEdit數據綁定
//this.txtProjectList3.Properties.TreeList.OptionsView.ShowCheckBoxes = true;
this.txtProjectList3.Properties.DataSource = list;
this.txtProjectList3.Properties.ValueMember = "Value";
this.txtProjectList3.Properties.DisplayMember = "Text";
this.txtProjectList3.Properties.TreeList.Columns.Clear();
for (int i = 0; i < columns.Count; i++)
{
this.txtProjectList3.Properties.TreeList.CreateColumn(columns[i].FieldName, columns[i].Caption,
columns[i].Width, true);
}
this.txtProjectList3.Properties.TreeList.InitTree(null, null, null, true, true);

this.txtProjectList3.Properties.ImmediatePopup = true;
this.txtProjectList3.Properties.TextEditStyle = TextEditStyles.Standard;
this.txtProjectList3.Properties.PopupWidthMode = DevExpress.XtraEditors.PopupWidthMode.ContentWidth;
this.txtProjectList3.Properties.PopupFormSize = new System.Drawing.Size(this.txtProjectList3.Width, 300);
this.txtProjectList3.Properties.TreeList.IndicatorWidth = 40;
this.txtProjectList3.Properties.TreeList.CustomDrawNodeIndicator += (s, ee) =>
{
if (ee.IsNodeIndicator)
{
var index = ee.Node.TreeList.GetVisibleIndexByNode(ee.Node);
ee.Info.DisplayText = (index + 1).ToString();
}
};

對於常規的列表綁定,我們可以用簡單的一個擴展函數實現,如下所示。

//常規類別綁定
this.txtProjectList4.BindDictItems(list, "Text", "Value", true, columns.ToArray());

就可以實現常規的界面效果處理。

WinForm應用實戰開發指南 - 如何實現列表集合控件的拖動?

對於樹形列表,我們需要設置屬性的ID和PID,以及一些顯示的列屬性,那麼也可以增加更多的參數來實現。

var dictTypeColumns = new List<LookUpColumnInfo>()
{
new LookUpColumnInfo("Id", "Id"),
new LookUpColumnInfo("Name", "字典類別名稱")
};
treeListLookUp.BindDictItems(result.Items, "Name", "Id", true, false, "Id", "PID", null, true, true, true, false, dictTypeColumns.ToArray());

因此嵌套列表就可以正常的展示出層次關係了。

WinForm應用實戰開發指南 - 如何實現列表集合控件的拖動?

因此我們把擴展方法,放到靜態類裏面就可以了,方法封裝如下所示:

/// <summary>
/// 綁定TreeListLookUpEdit控件的數據源(完整版)
/// </summary>
/// <param name="lookup">控件對象</param>
/// <param name="dataSource">數據源</param>
/// <param name="displayMember">顯示字段</param>
/// <param name="valueMember">值字段</param>
/// <param name="showRowIndicator">是否顯示序號</param>
/// <param name="showCheckbox">是否顯示覆選框</param>
/// <param name="keyFieldName">設置父子遞歸關係字段-子字段,不指定則使用valueMember</param>
/// <param name="parentFieldName">設置父子遞歸關係字段-父字段,不指定則不嵌套展示</param>
/// <param name="rootValue">根節點的值</param>
/// <param name="editable">樹節點是否可以編輯</param>
/// <param name="showColumnHeader">是否顯示列頭</param>
/// <param name="oddEvenRowColor">是否奇偶行不同顏色</param>
/// <param name="allowDrop">是否運行拖動列</param>
/// <param name="lookUpColumnInfos">顯示的列</param>
/// <returns></returns>
public static object BindDictItems(this TreeListLookUpEdit lookup, object dataSource, string displayMember, string valueMember, bool showRowIndicator = true,
bool showCheckbox = false, string keyFieldName = null, string parentFieldName = null, string rootValue = null, bool editable = true,
bool showColumnHeader = false, bool oddEvenRowColor = true, bool allowDrop = false,
params LookUpColumnInfo[] lookUpColumnInfos)
{
lookup.Properties.DataSource = dataSource;
lookup.Properties.DisplayMember = displayMember;
lookup.Properties.ValueMember = valueMember;
lookup.Properties.TreeList.OptionsView.ShowCheckBoxes = showCheckbox;

lookup.Properties.TreeList.Columns.Clear();
for (int i = 0; i < lookUpColumnInfos.Length; i++)
{
lookup.Properties.TreeList.CreateColumn(lookUpColumnInfos[i].FieldName, lookUpColumnInfos[i].Caption,
lookUpColumnInfos[i].Width, true);
}

//初始化樹的樣式和特性
//keyFieldName = !string.IsNullOrWhiteSpace(keyFieldName) ? keyFieldName : valueMember;//如果不指定,採用valueMember
lookup.Properties.TreeList.InitTree(keyFieldName, parentFieldName, rootValue, editable, showColumnHeader, oddEvenRowColor, allowDrop);
lookup.Properties.PopupFormSize = new System.Drawing.Size(lookup.Width, 300);

lookup.Properties.ImmediatePopup = true;
lookup.Properties.TextEditStyle = TextEditStyles.Standard;

if (showRowIndicator)
{
lookup.Properties.TreeList.IndicatorWidth = 40;
//重寫序號顯示,默認不顯示數值
lookup.Properties.TreeList.CustomDrawNodeIndicator += (s, ee) =>
{
if (ee.IsNodeIndicator)
{
var index = ee.Node.TreeList.GetVisibleIndexByNode(ee.Node);
ee.Info.DisplayText = (index + 1).ToString();
}
};
}

return dataSource;
}

通過擴展方法的方式,可以簡化界面的處理代碼,同時利於我們在項目開發的時候,快速的實現相關的效果,而不需要過多的中斷查找相關的界面控件屬性。

本文轉載自:博客園 - 伍華聰

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章