ViewMakerで作成するリアルアプリケーション 主要機能の開発(その1)
今回からViewModelの開発を行いますが、まず最初に重要な構成要素であるツリービューに対応するViewModelのクラスを定義します。ツリービューは階層型データを表示するコントロールなので、ViewModel側も階層型の構造をもつクラス構造を用意します。また、階層データの各要素にはアセンブリやタイプなどのバリエーションがあることも考慮するので、コンポジットな以下のような構造のクラス群を用意します。なお、今回Model部分に相当するクラスは.NETで用意されている標準のAssemblyやType、MemberInfoのクラスになります。
ベースクラスのTreeItemはViewModelから派生して子コレクション(Children)を再帰的にもつコンポジット構造になっています。また、IsSelectedやIsExpandedなどのTreeViewを制御するための基本的なプロパティを実装しています。
public abstract class TreeItem : ViewModel { public abstract string Name { get; } public bool IsSelected { get { return _isSelected; } set { _isSelected = value; OnPropertyChanged("IsSelected"); } } private bool _isSelected; public bool IsExpanded { get { return _isExpanded; } set { _isExpanded = value; OnPropertyChanged("IsExpanded"); } } private bool _isExpanded; public ObservableCollection<TreeItem> Children { get; private set; } public TreeItem Parent { get; private set; } public TreeItem(TreeItem parent) { this.Parent = parent; this.Children = new ObservableCollection<TreeItem>(); } public TreeItem FindNode(string findStr, bool childOnly = false) { //省略 } }
ツリービューの各アイテムは上記のTreeItemを継承してノードのタイトルであるNameプロパティをオーバライドします。これでツリービューに各要素を表示できるようにします。また、詳細情報用のプロパティを合わせて追加します。以下はアセンブリノード用のクラス定義で、ノードのタイトルにはAssemblyクラスのFullNameを利用し、詳細情報用にAsemmbly情報をプロパティとして公開します。
public class AssemblyTreeItem : TreeItem { public override string Name { get { return TargetAseembly.FullName; } } public Assembly TargetAseembly { get { return _targetAssembly; } } private Assembly _targetAssembly; public AssemblyTreeItem(TreeItem parent, Assembly assembly) : base(parent) { _targetAssembly = assembly; GenerateChildren(); } private void GenerateChildren() { foreach (var item in TargetAseembly.GetTypes().OrderBy(x => x.FullName)) { Children.Add(new TypeTreeItem(this, item)); } } }
これらのクラスは通常のクラスであり自動テストも難しくありません。コンポジットな構造もOOPの世界では取り扱いが特段難しいものではありません。もし新しいバリエーションが増えれば派生クラスを追加すればよいだけです。もしこの構造をXAMLで直接表現する場合、DataTemplateなどを使ってできなくはないのですが、取り扱いはC#のコードにくらべてかなり難しいことになります。