/* * DataTreeListView - A data bindable TreeListView * * Author: Phillip Piper * Date: 05/05/2012 3:26 PM * * Change log: * 2012-05-05 JPP Initial version * * TO DO: * * Copyright (C) 2012 Phillip Piper * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * If you wish to use this code in a closed source application, please contact phillip.piper@gmail.com. */ using System; using System.Collections; using System.ComponentModel; using System.Data; using System.Diagnostics; using System.Drawing.Design; using System.Windows.Forms; namespace BrightIdeasSoftware { /// /// A DataTreeListView is a TreeListView that calculates its hierarchy based on /// information in the data source. /// /// /// Like a , a DataTreeListView sources all its information /// from a combination of and . /// can be a DataTable, DataSet, /// or anything that implements . /// /// /// To function properly, the DataTreeListView requires: /// /// the table to have a column which holds a unique for the row. The name of this column must be set in . /// the table to have a column which holds id of the hierarchical parent of the row. The name of this column must be set in . /// a value which identifies which rows are the roots of the tree (). /// /// The hierarchy structure is determined finding all the rows where the parent key is equal to . These rows /// become the root objects of the hierarchy. /// /// Like a TreeListView, the hierarchy must not contain cycles. Bad things will happen if the data is cyclic. /// public partial class DataTreeListView : TreeListView { #region Public Properties /// /// Gets or sets whether or not columns will be automatically generated to show the /// columns when the DataSource is set. /// /// This must be set before the DataSource is set. It has no effect afterwards. [Category("Data"), Description("Should the control automatically generate columns from the DataSource"), DefaultValue(true)] public bool AutoGenerateColumns { get { return this.Adapter.AutoGenerateColumns; } set { this.Adapter.AutoGenerateColumns = value; } } /// /// Get or set the DataSource that will be displayed in this list view. /// /// The DataSource should implement either , , /// or . Some common examples are the following types of objects: /// /// /// /// /// /// /// /// When binding to a list container (i.e. one that implements the /// interface, such as ) /// you must also set the property in order /// to identify which particular list you would like to display. You /// may also set the property even when /// DataSource refers to a list, since can /// also be used to navigate relations between lists. /// [Category("Data"), TypeConverter("System.Windows.Forms.Design.DataSourceConverter, System.Design")] public virtual Object DataSource { get { return this.Adapter.DataSource; } set { this.Adapter.DataSource = value; } } /// /// Gets or sets the name of the list or table in the data source for which the DataListView is displaying data. /// /// If the data source is not a DataSet or DataViewManager, this property has no effect [Category("Data"), Editor("System.Windows.Forms.Design.DataMemberListEditor, System.Design", typeof(UITypeEditor)), DefaultValue("")] public virtual string DataMember { get { return this.Adapter.DataMember; } set { this.Adapter.DataMember = value; } } /// /// Gets or sets the name of the property/column that uniquely identifies each row. /// /// /// /// The value contained by this column must be unique across all rows /// in the data source. Odd and unpredictable things will happen if two /// rows have the same id. /// /// Null cannot be a valid key value. /// [Category("Data"), Description("The name of the property/column that holds the key of a row"), DefaultValue(null)] public virtual string KeyAspectName { get { return this.Adapter.KeyAspectName; } set { this.Adapter.KeyAspectName = value; } } /// /// Gets or sets the name of the property/column that contains the key of /// the parent of a row. /// /// /// /// The test condition for deciding if one row is the parent of another is functionally /// equivilent to this: /// /// Object.Equals(candidateParentRow[this.KeyAspectName], row[this.ParentKeyAspectName]) /// /// /// Unlike key value, parent keys can be null but a null parent key can only be used /// to identify root objects. /// [Category("Data"), Description("The name of the property/column that holds the key of the parent of a row"), DefaultValue(null)] public virtual string ParentKeyAspectName { get { return this.Adapter.ParentKeyAspectName; } set { this.Adapter.ParentKeyAspectName = value; } } /// /// Gets or sets the value that identifies a row as a root object. /// When the ParentKey of a row equals the RootKeyValue, that row will /// be treated as root of the TreeListView. /// /// /// /// The test condition for deciding a root object is functionally /// equivilent to this: /// /// Object.Equals(candidateRow[this.ParentKeyAspectName], this.RootKeyValue) /// /// /// The RootKeyValue can be null. Actually, it can be any value that can /// be compared for equality against a basic type. /// If this is set to the wrong value (i.e. to a value that no row /// has in the parent id column), the list will be empty. /// [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] public virtual object RootKeyValue { get { return this.Adapter.RootKeyValue; } set { this.Adapter.RootKeyValue = value; } } /// /// Gets or sets the value that identifies a row as a root object. /// . The RootKeyValue can be of any type, /// but the IDE cannot sensibly represent a value of any type, /// so this is a typed wrapper around that property. /// /// /// If you want the root value to be something other than a string, /// you will have set it yourself. /// [Category("Data"), Description("The parent id value that identifies a row as a root object"), DefaultValue(null)] public virtual string RootKeyValueString { get { return Convert.ToString(this.Adapter.RootKeyValue); } set { this.Adapter.RootKeyValue = value; } } /// /// Gets or sets whether or not the key columns (id and parent id) should /// be shown to the user. /// /// This must be set before the DataSource is set. It has no effect /// afterwards. [Category("Data"), Description("Should the keys columns (id and parent id) be shown to the user?"), DefaultValue(true)] public virtual bool ShowKeyColumns { get { return this.Adapter.ShowKeyColumns; } set { this.Adapter.ShowKeyColumns = value; } } #endregion #region Implementation properties /// /// Gets or sets the DataSourceAdaptor that does the bulk of the work needed /// for data binding. /// protected TreeDataSourceAdapter Adapter { get { if (this.adapter == null) this.adapter = new TreeDataSourceAdapter(this); return adapter; } set { adapter = value; } } private TreeDataSourceAdapter adapter; #endregion } }