C# WPF MVVM 實戰 – 3 – 樹結構

來源:互聯網
上載者:User

  樹結構放在 WPF ,有大家熟悉的 TreeView、Menu / MenuItem 等等,自訂的話它是 HierarchicalDataTemplate。

  用上 MVVM 模式,視圖與資料分離,意味著你不再需要管 UI ,不用再在 TreeView 內上上下下跑來跑去找控制項了。MVVM 不是把樹結構變成不是一顆樹,只是,你操作的,是一個具樹結構的集合而已。我很怕搞 UI,我覺得,這是個解脫,起碼對我是那樣。

  我說,如果你發現自己在糾結 TreeView 內怎樣找控制項,或者在研究它單一個元素的結構(Grid 包裹著 Border、Border又包裹著 TextBox、最後,哦,找到 TextBox 的 Text 了,手起刀落,改它… 之類),與其糾結下去,不如收手吧,試試用下面方式,你會喜歡的。

  我覺得本來 WPF 的設計就是給你這樣用的。

TreeView

  使用 WPF + MVVM,特別是當你從 WinForm 轉過來,你需要一個重大的思路改變。UI 是用來「顯示」資料,並非「暫存」資料。它只是個與使用者互動的媒介。當對資料操作,你要從資料本身下手,而不是從 UI 找。

  舉個例子,主菜單,是左側顯示,外層 Expander,裡面的內容每一單元放一個 TreeView,TreeView 內每一項的結構是左邊顯示圖示,右邊顯示文字標題,整項都可以雙擊開啟某某功能的介面。這很普通吧。但要求是模組載入後初始化時可以動態插入項,插入邏輯是提供上一層菜單的標題時,插在它下一級。沒有提供上一級時候,加在最頂層。

  不是綁定的話,寫一開始的菜單是很簡單,麻煩在於要開放方法出來,接受上級功能表標題 string、圖示 URI 、標題 string、和需要開啟的介面引用。這方法的代碼,需要在菜單結構中找出所謂的上級是哪個項。上級沒有的話,加進去 Expander,有上級就糾結了,要在 TreeView 的結構中找,在 UI 找,這時你必須清楚 TreeView 內項目的結構,比如內容是 Grid 你要在裡面找出 TextBlock 控制項的文字是什麼,比較一下,符合時按照已定的結構加 node。

  花了點時間,寫完。客戶說 Expander 不好用,通通改為 TreeView,你懂的。另一個客戶,說除了左側菜單外,希望上面有些傳統菜單,額,你又改。設計師哪天看到 Dev 說好,我們改吧,那你又改吧。。。

這些問題,源於演算法與 UI 結構緊扣在一起,特別是 XAML 介面,你要多複雜,有多複雜,然後你的插入演算法也跟著複雜。而且 UI 變,你也要改。但這世界可以更美好的。

資料結構

  為求簡單,這結構只有標題。

    public class MyMenuItem : INotifyPropertyChanged {        public MyMenuItem() {            Childs = new ObservableCollection<MyMenuItem>();        }        private string text;        public string Text {            get {                return text;            }            set {                text = value;                if (PropertyChanged != null)                    PropertyChanged(this, new PropertyChangedEventArgs("Text"));            }        }        private ObservableCollection<MyMenuItem> childs;        public ObservableCollection<MyMenuItem> Childs {            get {                return childs;            }            set {                childs = value;                if (PropertyChanged != null)                    PropertyChanged(this, new PropertyChangedEventArgs("Childs"));            }        }        #region INotifyPropertyChanged Members        public event PropertyChangedEventHandler PropertyChanged;        #endregion    }

  資料結構是樹結構,你就要把它寫成樹結構,不用考慮 UI 那邊怎樣。

  要對於結構操作,搜尋標題然後加項的話,這類菜單我選擇 Breadth First。擴充方法有時候覺得用的機會不多吧,來一個玩玩看。

    internal static class MenuItemExtension {        internal static MyMenuItem Search(            this MyMenuItem node,             Predicate<MyMenuItem> match) {            Queue<MyMenuItem> queue = new Queue<MyMenuItem>();            queue.Enqueue(node);            while (queue.Count > 0) {                MyMenuItem thisNode = queue.Dequeue();                if (match(thisNode))                    return thisNode;                foreach (MyMenuItem child in thisNode.Childs)                    queue.Enqueue(child);            }            return null;        }    }

  實際插菜單,對外開放的加菜單功能,大概這樣實現咯。

    public class MenuService {        private MyMenuItem MainMenu;        public MenuService() {            //... 一些拿到主菜單的代碼,比如從容器中 Resolve        }        public void Add(string MenuText, string ParentText) {            if (ParentText == null) {                this.MainMenu.Childs.Add(new MyMenuItem {                    Text = MenuText                });            } else {                MyMenuItem result = this.MainMenu.Search(x => {                    return x.Text == ParentText;                });                if (result != null) {                    result.Childs.Add(new MyMenuItem {                        Text = MenuText                    });                } else {                    throw new ArgumentOutOfRangeException("ParentText");                }            }        }    }

  一切都很合理,沒有了奇怪的 UI 結構在演算法內,任何形式的菜單,都能用這結構和方法。喜歡直接 TreeView 的就 TreeView,複雜起來的介面用 HierarchicalDataTemplate。

  綁定寫法請自己查 MSDN 或看書,不寫出來了。下面源碼有些超簡單樣本。

  點擊下載原始碼:Lepton_Practical_MVVM_3.zip 

  MVVM 大神 Josh Smith 在 Code Project 寫了一篇相當經典的,關於 MVVM 與 TreeView 的做法,點擊這裡開啟。我極力推薦。學習 WPF 和 Silverlight 的同學們,Josh Smith 在 wordpress 寫了些博文,應該一篇不漏的看一遍(貌似要翻牆)。

  最近玩 Silverlight 玩上癮,甚至有點過火了,啥都 SL。下篇有時間寫下去的話,我想寫寫 Silverlight 的模組化。誰說 SL 不能做 LOB 的?Silverlight 有限制,你清楚那些限制,也判斷了你程式沒有觸碰到那些,是可以的。有時間再寫下去。

 

後記:2012-09-27 10:35 PM 關於Lepton_Practical_MVVM_3.zip,不好意思我上網抄了個 ViewModelBase 後,心癢,把它的 DisplayName 屬性刪除後忘記了改 #IF DEBUG 內的代碼,請在這後記編寫前下載了代碼的朋友,在 VS 用 Release Build 運行,或者自行修改。目前的版本已修正此問題。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.