/GDFlacToolVS2008/ObjectListView2010/OLVColumn.cs
http://gdflactool.codeplex.com · C# · 1494 lines · 764 code · 139 blank · 591 comment · 162 complexity · c3e0817cce2c29b7e709062b87b75a1b MD5 · raw file
- /*
- * OLVColumn - A column in an ObjectListView
- *
- * Author: Phillip Piper
- * Date: 31-March-2011 5:53 pm
- *
- * Change log:
- * 2011-05-27 JPP - Added Sortable, Hideable, Groupable, Searchable, ShowTextInHeader properties
- * 2011-04-12 JPP - Added HasFilterIndicator
- * 2011-03-31 JPP - Split into its own file
- *
- * Copyright (C) 2011-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 <http://www.gnu.org/licenses/>.
- *
- * If you wish to use this code in a closed source application, please contact phillip_piper@bigfoot.com.
- */
-
- using System;
- using System.ComponentModel;
- using System.Windows.Forms;
- using System.Drawing;
- using System.Collections;
- using System.Diagnostics;
-
- namespace BrightIdeasSoftware {
-
- /// <summary>
- /// An OLVColumn knows which aspect of an object it should present.
- /// </summary>
- /// <remarks>
- /// The column knows how to:
- /// <list type="bullet">
- /// <item><description>extract its aspect from the row object</description></item>
- /// <item><description>convert an aspect to a string</description></item>
- /// <item><description>calculate the image for the row object</description></item>
- /// <item><description>extract a group "key" from the row object</description></item>
- /// <item><description>convert a group "key" into a title for the group</description></item>
- /// </list>
- /// <para>For sorting to work correctly, aspects from the same column
- /// must be of the same type, that is, the same aspect cannot sometimes
- /// return strings and other times integers.</para>
- /// </remarks>
- [Browsable(false)]
- public partial class OLVColumn : ColumnHeader {
-
- #region Life and death
-
- /// <summary>
- /// Create an OLVColumn
- /// </summary>
- public OLVColumn() {
- }
-
- /// <summary>
- /// Initialize a column to have the given title, and show the given aspect
- /// </summary>
- /// <param name="title">The title of the column</param>
- /// <param name="aspect">The aspect to be shown in the column</param>
- public OLVColumn(string title, string aspect)
- : this() {
- this.Text = title;
- this.AspectName = aspect;
- }
-
- #endregion
-
- #region Public Properties
-
- /// <summary>
- /// This delegate will be used to extract a value to be displayed in this column.
- /// </summary>
- /// <remarks>
- /// If this is set, AspectName is ignored.
- /// </remarks>
- [Browsable(false),
- DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
- public AspectGetterDelegate AspectGetter {
- get { return aspectGetter; }
- set { aspectGetter = value; }
- }
- private AspectGetterDelegate aspectGetter;
-
- /// <summary>
- /// Remember if this aspect getter for this column was generated internally, and can therefore
- /// be regenerated at will
- /// </summary>
- [Obsolete("This property is no longer maintained", true),
- Browsable(false),
- DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
- public bool AspectGetterAutoGenerated {
- get { return aspectGetterAutoGenerated; }
- set { aspectGetterAutoGenerated = value; }
- }
- private bool aspectGetterAutoGenerated;
-
- /// <summary>
- /// The name of the property or method that should be called to get the value to display in this column.
- /// This is only used if a ValueGetterDelegate has not been given.
- /// </summary>
- /// <remarks>This name can be dotted to chain references to properties or parameter-less methods.</remarks>
- /// <example>"DateOfBirth"</example>
- /// <example>"Owner.HomeAddress.Postcode"</example>
- [Category("ObjectListView"),
- Description("The name of the property or method that should be called to get the aspect to display in this column"),
- DefaultValue(null)]
- public string AspectName {
- get { return aspectName; }
- set {
- aspectName = value;
- this.aspectMunger = null;
- }
- }
- private string aspectName;
-
- /// <summary>
- /// This delegate will be used to put an edited value back into the model object.
- /// </summary>
- /// <remarks>
- /// This does nothing if IsEditable == false.
- /// </remarks>
- [Browsable(false),
- DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
- public AspectPutterDelegate AspectPutter {
- get { return aspectPutter; }
- set { aspectPutter = value; }
- }
- private AspectPutterDelegate aspectPutter;
-
- /// <summary>
- /// The delegate that will be used to translate the aspect to display in this column into a string.
- /// </summary>
- /// <remarks>If this value is set, AspectToStringFormat will be ignored.</remarks>
- [Browsable(false),
- DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
- public AspectToStringConverterDelegate AspectToStringConverter {
- get { return aspectToStringConverter; }
- set { aspectToStringConverter = value; }
- }
- private AspectToStringConverterDelegate aspectToStringConverter;
-
- /// <summary>
- /// This format string will be used to convert an aspect to its string representation.
- /// </summary>
- /// <remarks>
- /// This string is passed as the first parameter to the String.Format() method.
- /// This is only used if AspectToStringConverter has not been set.</remarks>
- /// <example>"{0:C}" to convert a number to currency</example>
- [Category("ObjectListView"),
- Description("The format string that will be used to convert an aspect to its string representation"),
- DefaultValue(null)]
- public string AspectToStringFormat {
- get { return aspectToStringFormat; }
- set { aspectToStringFormat = value; }
- }
- private string aspectToStringFormat;
-
- /// <summary>
- /// Gets or sets whether the cell editor should use AutoComplete
- /// </summary>
- [Category("ObjectListView"),
- Description("Should the editor for cells of this column use AutoComplete"),
- DefaultValue(true)]
- public bool AutoCompleteEditor {
- get { return this.AutoCompleteEditorMode != AutoCompleteMode.None; }
- set {
- if (value) {
- if (this.AutoCompleteEditorMode == AutoCompleteMode.None)
- this.AutoCompleteEditorMode = AutoCompleteMode.Append;
- } else
- this.AutoCompleteEditorMode = AutoCompleteMode.None;
- }
- }
-
- /// <summary>
- /// Gets or sets whether the cell editor should use AutoComplete
- /// </summary>
- [Category("ObjectListView"),
- Description("Should the editor for cells of this column use AutoComplete"),
- DefaultValue(AutoCompleteMode.Append)]
- public AutoCompleteMode AutoCompleteEditorMode {
- get { return autoCompleteEditorMode; }
- set { autoCompleteEditorMode = value; }
- }
- private AutoCompleteMode autoCompleteEditorMode = AutoCompleteMode.Append;
-
- /// <summary>
- /// Gets whether this column can be hidden by user actions
- /// </summary>
- /// <remarks>This take into account both the Hideable property and whether this column
- /// is the primary column of the listview (column 0).</remarks>
- [Browsable(false)]
- public bool CanBeHidden {
- get {
- return this.Hideable && (this.Index != 0);
- }
- }
-
- /// <summary>
- /// Gets or sets whether this column will show a checkbox.
- /// </summary>
- /// <remarks>
- /// Setting this on column 0 has no effect. Column 0 check box is controlled
- /// by the CheckBoxes property on the ObjectListView itself.
- /// </remarks>
- [Category("ObjectListView"),
- Description("Should values in this column be treated as a checkbox, rather than a string?"),
- DefaultValue(false)]
- public virtual bool CheckBoxes {
- get { return checkBoxes; }
- set {
- if (this.checkBoxes == value)
- return;
-
- this.checkBoxes = value;
- if (this.checkBoxes) {
- if (this.Renderer == null)
- this.Renderer = new CheckStateRenderer();
- } else {
- if (this.Renderer is CheckStateRenderer)
- this.Renderer = null;
- }
- }
- }
- private bool checkBoxes;
-
- /// <summary>
- /// Gets or sets the clustering strategy used for this column.
- /// </summary>
- /// <remarks>
- /// <para>
- /// The clustering strategy is used to build a Filtering menu for this item.
- /// If this is null, a useful default will be chosen.
- /// </para>
- /// <para>
- /// To disable filtering on this colummn, set UseFiltering to false.
- /// </para>
- /// <para>
- /// Cluster strategies belong to a particular column. The same instance
- /// cannot be shared between multiple columns.
- /// </para>
- /// </remarks>
- [Browsable(false),
- DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
- public IClusteringStrategy ClusteringStrategy {
- get {
- if (this.clusteringStrategy == null)
- this.ClusteringStrategy = this.DecideDefaultClusteringStrategy();
- return clusteringStrategy;
- }
- set {
- this.clusteringStrategy = value;
- if (this.clusteringStrategy != null)
- this.clusteringStrategy.Column = this;
- }
- }
- private IClusteringStrategy clusteringStrategy;
-
- /// <summary>
- /// Should this column resize to fill the free space in the listview?
- /// </summary>
- /// <remarks>
- /// <para>
- /// If you want two (or more) columns to equally share the available free space, set this property to True.
- /// If you want this column to have a larger or smaller share of the free space, you must
- /// set the FreeSpaceProportion property explicitly.
- /// </para>
- /// <para>
- /// Space filling columns are still governed by the MinimumWidth and MaximumWidth properties.
- /// </para>
- /// /// </remarks>
- [Category("ObjectListView"),
- Description("Will this column resize to fill unoccupied horizontal space in the listview?"),
- DefaultValue(false)]
- public bool FillsFreeSpace {
- get { return this.FreeSpaceProportion > 0; }
- set { this.freeSpaceProportion = value ? 1 : 0; }
- }
-
- /// <summary>
- /// What proportion of the unoccupied horizontal space in the control should be given to this column?
- /// </summary>
- /// <remarks>
- /// <para>
- /// There are situations where it would be nice if a column (normally the rightmost one) would expand as
- /// the list view expands, so that as much of the column was visible as possible without having to scroll
- /// horizontally (you should never, ever make your users have to scroll anything horizontally!).
- /// </para>
- /// <para>
- /// A space filling column is resized to occupy a proportion of the unoccupied width of the listview (the
- /// unoccupied width is the width left over once all the the non-filling columns have been given their space).
- /// This property indicates the relative proportion of that unoccupied space that will be given to this column.
- /// The actual value of this property is not important -- only its value relative to the value in other columns.
- /// For example:
- /// <list type="bullet">
- /// <item><description>
- /// If there is only one space filling column, it will be given all the free space, regardless of the value in FreeSpaceProportion.
- /// </description></item>
- /// <item><description>
- /// If there are two or more space filling columns and they all have the same value for FreeSpaceProportion,
- /// they will share the free space equally.
- /// </description></item>
- /// <item><description>
- /// If there are three space filling columns with values of 3, 2, and 1
- /// for FreeSpaceProportion, then the first column with occupy half the free space, the second will
- /// occupy one-third of the free space, and the third column one-sixth of the free space.
- /// </description></item>
- /// </list>
- /// </para>
- /// </remarks>
- [Browsable(false),
- DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
- public int FreeSpaceProportion {
- get { return freeSpaceProportion; }
- set { freeSpaceProportion = Math.Max(0, value); }
- }
- private int freeSpaceProportion;
-
- /// <summary>
- /// Gets or sets whether groups will be rebuild on this columns values when this column's header is clicked.
- /// </summary>
- /// <remarks>
- /// <para>This setting is only used when ShowGroups is true.</para>
- /// <para>
- /// If this is false, clicking the header will not rebuild groups. It will not provide
- /// any feedback as to why the list is not being regrouped. It is the programmers responsibility to
- /// provide appropriate feedback.
- /// </para>
- /// <para>When this is false, BeforeCreatingGroups events are still fired, which can be used to allow grouping
- /// or give feedback, on a case by case basis.</para>
- /// </remarks>
- [Category("ObjectListView"),
- Description("Will the list create groups when this header is clicked?"),
- DefaultValue(true)]
- public bool Groupable {
- get { return groupable; }
- set { groupable = value; }
- }
- private bool groupable = true;
-
- /// <summary>
- /// This delegate is called when a group has been created but not yet made
- /// into a real ListViewGroup. The user can take this opportunity to fill
- /// in lots of other details about the group.
- /// </summary>
- [Browsable(false),
- DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
- public GroupFormatterDelegate GroupFormatter {
- get { return groupFormatter; }
- set { groupFormatter = value; }
- }
- private GroupFormatterDelegate groupFormatter;
-
- /// <summary>
- /// This delegate is called to get the object that is the key for the group
- /// to which the given row belongs.
- /// </summary>
- [Browsable(false),
- DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
- public GroupKeyGetterDelegate GroupKeyGetter {
- get { return groupKeyGetter; }
- set { groupKeyGetter = value; }
- }
- private GroupKeyGetterDelegate groupKeyGetter;
-
- /// <summary>
- /// This delegate is called to convert a group key into a title for that group.
- /// </summary>
- [Browsable(false),
- DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
- public GroupKeyToTitleConverterDelegate GroupKeyToTitleConverter {
- get { return groupKeyToTitleConverter; }
- set { groupKeyToTitleConverter = value; }
- }
- private GroupKeyToTitleConverterDelegate groupKeyToTitleConverter;
-
- /// <summary>
- /// When the listview is grouped by this column and group title has an item count,
- /// how should the lable be formatted?
- /// </summary>
- /// <remarks>
- /// The given format string can/should have two placeholders:
- /// <list type="bullet">
- /// <item><description>{0} - the original group title</description></item>
- /// <item><description>{1} - the number of items in the group</description></item>
- /// </list>
- /// </remarks>
- /// <example>"{0} [{1} items]"</example>
- [Category("ObjectListView"),
- Description("The format to use when suffixing item counts to group titles"),
- DefaultValue(null),
- Localizable(true)]
- public string GroupWithItemCountFormat {
- get { return groupWithItemCountFormat; }
- set { groupWithItemCountFormat = value; }
- }
- private string groupWithItemCountFormat;
-
- /// <summary>
- /// Gets this.GroupWithItemCountFormat or a reasonable default
- /// </summary>
- /// <remarks>
- /// If GroupWithItemCountFormat is not set, its value will be taken from the ObjectListView if possible.
- /// </remarks>
- [Browsable(false)]
- public string GroupWithItemCountFormatOrDefault {
- get {
- if (!String.IsNullOrEmpty(this.GroupWithItemCountFormat))
- return this.GroupWithItemCountFormat;
-
- if (this.ListView != null) {
- cachedGroupWithItemCountFormat = ((ObjectListView)this.ListView).GroupWithItemCountFormatOrDefault;
- return cachedGroupWithItemCountFormat;
- }
-
- // There is one rare but pathelogically possible case where the ListView can
- // be null (if the column is grouping a ListView, but is not one of the columns
- // for that ListView) so we have to provide a workable default for that rare case.
- return cachedGroupWithItemCountFormat ?? "{0} [{1} items]";
- }
- }
- private string cachedGroupWithItemCountFormat;
-
- /// <summary>
- /// When the listview is grouped by this column and a group title has an item count,
- /// how should the lable be formatted if there is only one item in the group?
- /// </summary>
- /// <remarks>
- /// The given format string can/should have two placeholders:
- /// <list type="bullet">
- /// <item><description>{0} - the original group title</description></item>
- /// <item><description>{1} - the number of items in the group (always 1)</description></item>
- /// </list>
- /// </remarks>
- /// <example>"{0} [{1} item]"</example>
- [Category("ObjectListView"),
- Description("The format to use when suffixing item counts to group titles"),
- DefaultValue(null),
- Localizable(true)]
- public string GroupWithItemCountSingularFormat {
- get { return groupWithItemCountSingularFormat; }
- set { groupWithItemCountSingularFormat = value; }
- }
- private string groupWithItemCountSingularFormat;
-
- /// <summary>
- /// Get this.GroupWithItemCountSingularFormat or a reasonable default
- /// </summary>
- /// <remarks>
- /// <para>If this value is not set, the values from the list view will be used</para>
- /// </remarks>
- [Browsable(false)]
- public string GroupWithItemCountSingularFormatOrDefault {
- get {
- if (!String.IsNullOrEmpty(this.GroupWithItemCountSingularFormat))
- return this.GroupWithItemCountSingularFormat;
-
- if (this.ListView != null) {
- cachedGroupWithItemCountSingularFormat = ((ObjectListView)this.ListView).GroupWithItemCountSingularFormatOrDefault;
- return cachedGroupWithItemCountSingularFormat;
- }
-
- // There is one rare but pathelogically possible case where the ListView can
- // be null (if the column is grouping a ListView, but is not one of the columns
- // for that ListView) so we have to provide a workable default for that rare case.
- return cachedGroupWithItemCountSingularFormat ?? "{0} [{1} item]";
- }
- }
- private string cachedGroupWithItemCountSingularFormat;
-
- /// <summary>
- /// Gets whether this column should be drawn with a filter indicator in the column header.
- /// </summary>
- [Browsable(false)]
- public bool HasFilterIndicator {
- get {
- return this.UseFiltering && this.ValuesChosenForFiltering != null && this.ValuesChosenForFiltering.Count > 0;
- }
- }
-
- /// <summary>
- /// Gets or sets a delegate that will be used to own draw header column.
- /// </summary>
- [Browsable(false),
- DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
- public HeaderDrawingDelegate HeaderDrawing {
- get { return headerDrawing; }
- set { headerDrawing = value; }
- }
- private HeaderDrawingDelegate headerDrawing;
-
- /// <summary>
- /// Gets or sets the style that will be used to draw the header for this column
- /// </summary>
- /// <remarks>This is only uses when the owning ObjectListView has HeaderUsesThemes set to false.</remarks>
- [Category("ObjectListView"),
- Description("What style will be used to draw the header of this column"),
- DefaultValue(null)]
- public HeaderFormatStyle HeaderFormatStyle {
- get { return this.headerFormatStyle; }
- set { this.headerFormatStyle = value; }
- }
- private HeaderFormatStyle headerFormatStyle;
-
- /// <summary>
- /// Gets or sets the font in which the header for this column will be drawn
- /// </summary>
- /// <remarks>This property will be made obsolete in v2.5. Use HeaderFormatStyle instead</remarks>
- /// <remarks>This is only uses when HeaderUsesThemes is false.</remarks>
- [Browsable(false)]
- [DefaultValue(null)]
- public Font HeaderFont {
- get { return this.HeaderFormatStyle == null ? null : this.HeaderFormatStyle.Normal.Font; }
- set {
- if (value == null && this.HeaderFormatStyle == null)
- return;
-
- if (this.HeaderFormatStyle == null)
- this.HeaderFormatStyle = new HeaderFormatStyle();
-
- this.HeaderFormatStyle.SetFont(value);
- }
- }
-
- /// <summary>
- /// Gets or sets the color in which the text of the header for this column will be drawn
- /// </summary>
- /// <remarks>This property will be made obsolete in v2.5. Use HeaderFormatStyle instead</remarks>
- /// <remarks>This is only uses when HeaderUsesThemes is false.</remarks>
- [Browsable(false)]
- [DefaultValue(typeof(Color), "")]
- public Color HeaderForeColor {
- get { return this.HeaderFormatStyle == null ? Color.Empty : this.HeaderFormatStyle.Normal.ForeColor; }
- set {
- if (value.IsEmpty && this.HeaderFormatStyle == null)
- return;
-
- if (this.HeaderFormatStyle == null)
- this.HeaderFormatStyle = new HeaderFormatStyle();
-
- this.HeaderFormatStyle.SetForeColor(value);
- }
- }
-
- /// <summary>
- /// Gets or sets whether the text values in this column will act like hyperlinks
- /// </summary>
- /// <remarks>This is only taken into account when HeaderUsesThemes is false.</remarks>
- [Category("ObjectListView"),
- Description("Name of the image that will be shown in the column header."),
- DefaultValue(null),
- TypeConverter(typeof(ImageKeyConverter)),
- Editor("System.Windows.Forms.Design.ImageIndexEditor, System.Design, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a", typeof(System.Drawing.Design.UITypeEditor)),
- RefreshProperties(RefreshProperties.Repaint)]
- public string HeaderImageKey {
- get { return headerImageKey; }
- set { headerImageKey = value; }
- }
- private string headerImageKey;
-
-
- /// <summary>
- /// Gets or sets how the text of the header will be drawn?
- /// </summary>
- [Category("ObjectListView"),
- Description("How will the header text be aligned?"),
- DefaultValue(HorizontalAlignment.Left)]
- public HorizontalAlignment HeaderTextAlign {
- get { return headerTextAlign.HasValue ? headerTextAlign.Value : this.TextAlign; }
- set { headerTextAlign = value; }
- }
- private HorizontalAlignment? headerTextAlign;
-
- /// <summary>
- /// Gets the header alignment converted to a StringAlignment
- /// </summary>
- [Browsable(false)]
- public StringAlignment HeaderTextAlignAsStringAlignment {
- get {
- switch (this.HeaderTextAlign) {
- case HorizontalAlignment.Left: return StringAlignment.Near;
- case HorizontalAlignment.Center: return StringAlignment.Center;
- case HorizontalAlignment.Right: return StringAlignment.Far;
- default: return StringAlignment.Near;
- }
- }
- }
-
- /// <summary>
- /// Gets whether or not this column has an image in the header
- /// </summary>
- [Browsable(false)]
- public bool HasHeaderImage {
- get {
- return (this.ListView != null &&
- this.ListView.SmallImageList != null &&
- this.ListView.SmallImageList.Images.ContainsKey(this.HeaderImageKey));
- }
- }
-
- /// <summary>
- /// Gets or sets whether this column can be hidden by the user.
- /// </summary>
- /// <remarks>
- /// <para>Column 0 can never be hidden, regardless of this setting.</para>
- /// </remarks>
- [Category("ObjectListView"),
- Description("Will the user be able to choose to hide this column?"),
- DefaultValue(true)]
- public bool Hideable {
- get { return hideable; }
- set { hideable = value; }
- }
- private bool hideable = true;
-
- /// <summary>
- /// Gets or sets whether the text values in this column will act like hyperlinks
- /// </summary>
- [Category("ObjectListView"),
- Description("Will the text values of this column act like hyperlinks?"),
- DefaultValue(false)]
- public bool Hyperlink {
- get { return hyperlink; }
- set { hyperlink = value; }
- }
- private bool hyperlink;
-
- /// <summary>
- /// This is the name of property that will be invoked to get the image selector of the
- /// image that should be shown in this column.
- /// It can return an int, string, Image or null.
- /// </summary>
- /// <remarks>
- /// <para>This is ignored if ImageGetter is not null.</para>
- /// <para>The property can use these return value to identify the image:</para>
- /// <list type="bullet">
- /// <item><description>null or -1 -- indicates no image</description></item>
- /// <item><description>an int -- the int value will be used as an index into the image list</description></item>
- /// <item><description>a String -- the string value will be used as a key into the image list</description></item>
- /// <item><description>an Image -- the Image will be drawn directly (only in OwnerDrawn mode)</description></item>
- /// </list>
- /// </remarks>
- [Category("ObjectListView"),
- Description("The name of the property that holds the image selector"),
- DefaultValue(null)]
- public string ImageAspectName {
- get { return imageAspectName; }
- set { imageAspectName = value; }
- }
- private string imageAspectName;
-
- /// <summary>
- /// This delegate is called to get the image selector of the image that should be shown in this column.
- /// It can return an int, string, Image or null.
- /// </summary>
- /// <remarks><para>This delegate can use these return value to identify the image:</para>
- /// <list type="bullet">
- /// <item><description>null or -1 -- indicates no image</description></item>
- /// <item><description>an int -- the int value will be used as an index into the image list</description></item>
- /// <item><description>a String -- the string value will be used as a key into the image list</description></item>
- /// <item><description>an Image -- the Image will be drawn directly (only in OwnerDrawn mode)</description></item>
- /// </list>
- /// </remarks>
- [Browsable(false),
- DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
- public ImageGetterDelegate ImageGetter {
- get { return imageGetter; }
- set { imageGetter = value; }
- }
- private ImageGetterDelegate imageGetter;
-
- /// <summary>
- /// Can the values shown in this column be edited?
- /// </summary>
- /// <remarks>This defaults to true, since the primary means to control the editability of a listview
- /// is on the listview itself. Once a listview is editable, all the columns are too, unless the
- /// programmer explicitly marks them as not editable</remarks>
- [Category("ObjectListView"),
- Description("Can the value in this column be edited?"),
- DefaultValue(true)]
- public bool IsEditable {
- get { return isEditable; }
- set { isEditable = value; }
- }
- private bool isEditable = true;
-
- /// <summary>
- /// Is this column a fixed width column?
- /// </summary>
- [Browsable(false)]
- public bool IsFixedWidth {
- get {
- return (this.MinimumWidth != -1 && this.MaximumWidth != -1 && this.MinimumWidth >= this.MaximumWidth);
- }
- }
-
- /// <summary>
- /// Get/set whether this column should be used when the view is switched to tile view.
- /// </summary>
- /// <remarks>Column 0 is always included in tileview regardless of this setting.
- /// Tile views do not work well with many "columns" of information.
- /// Two or three works best.</remarks>
- [Category("ObjectListView"),
- Description("Will this column be used when the view is switched to tile view"),
- DefaultValue(false)]
- public bool IsTileViewColumn {
- get { return isTileViewColumn; }
- set { isTileViewColumn = value; }
- }
- private bool isTileViewColumn;
-
- /// <summary>
- /// Gets or sets whether the text of this header should be
- /// rendered vertically.
- /// </summary>
- /// <remarks>
- /// <para>If this is true, it is a good idea to set ToolTipText to the name of the column so it's easy to read.</para>
- /// <para>Currently (2010-08), vertical headers are text only. They do not draw their image.</para>
- /// </remarks>
- [Category("ObjectListView"),
- Description("Will the header for this column be drawn vertically?"),
- DefaultValue(false)]
- public bool IsHeaderVertical {
- get { return isHeaderVertical; }
- set { isHeaderVertical = value; }
- }
- private bool isHeaderVertical;
-
- /// <summary>
- /// Can this column be seen by the user?
- /// </summary>
- /// <remarks>After changing this value, you must call RebuildColumns() before the changes will be effected.</remarks>
- [Category("ObjectListView"),
- Description("Can this column be seen by the user?"),
- DefaultValue(true)]
- public bool IsVisible {
- get { return isVisible; }
- set { isVisible = value; }
- }
- private bool isVisible = true;
-
- /// <summary>
- /// Where was this column last positioned within the Detail view columns
- /// </summary>
- /// <remarks>DisplayIndex is volatile. Once a column is removed from the control,
- /// there is no way to discover where it was in the display order. This property
- /// guards that information even when the column is not in the listview's active columns.</remarks>
- [Browsable(false),
- DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
- public int LastDisplayIndex {
- get { return this.lastDisplayIndex; }
- set { this.lastDisplayIndex = value; }
- }
- private int lastDisplayIndex = -1;
-
- /// <summary>
- /// What is the maximum width that the user can give to this column?
- /// </summary>
- /// <remarks>-1 means there is no maximum width. Give this the same value as MinimumWidth to make a fixed width column.</remarks>
- [Category("ObjectListView"),
- Description("What is the maximum width to which the user can resize this column?"),
- DefaultValue(-1)]
- public int MaximumWidth {
- get { return maxWidth; }
- set {
- maxWidth = value;
- if (maxWidth != -1 && this.Width > maxWidth)
- this.Width = maxWidth;
- }
- }
- private int maxWidth = -1;
-
- /// <summary>
- /// What is the minimum width that the user can give to this column?
- /// </summary>
- /// <remarks>-1 means there is no minimum width. Give this the same value as MaximumWidth to make a fixed width column.</remarks>
- [Category("ObjectListView"),
- Description("What is the minimum width to which the user can resize this column?"),
- DefaultValue(-1)]
- public int MinimumWidth {
- get { return minWidth; }
- set {
- minWidth = value;
- if (this.Width < minWidth)
- this.Width = minWidth;
- }
- }
- private int minWidth = -1;
-
- /// <summary>
- /// Get/set the renderer that will be invoked when a cell needs to be redrawn
- /// </summary>
- [Category("ObjectListView"),
- Description("The renderer will draw this column when the ListView is owner drawn"),
- DefaultValue(null)]
- public IRenderer Renderer {
- get { return renderer; }
- set { renderer = value; }
- }
- private IRenderer renderer;
-
- /// <summary>
- /// This delegate is called when a cell needs to be drawn in OwnerDrawn mode.
- /// </summary>
- /// <remarks>This method is kept primarily for backwards compatibility.
- /// New code should implement an IRenderer, though this property will be maintained.</remarks>
- [Browsable(false),
- DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
- public RenderDelegate RendererDelegate {
- get {
- if (this.Renderer is Version1Renderer)
- return ((Version1Renderer)this.Renderer).RenderDelegate;
- else
- return null;
- }
- set {
- this.Renderer = value == null ? null : new Version1Renderer(value);
- }
- }
-
- /// <summary>
- /// Gets or sets whether the text in this column's cell will be used when doing text searching.
- /// </summary>
- /// <remarks>
- /// <para>
- /// If this is false, text filters will not trying searching this columns cells when looking for matches.
- /// </para>
- /// </remarks>
- [Category("ObjectListView"),
- Description("Will the text of the cells in this column be considered when searching?"),
- DefaultValue(true)]
- public bool Searchable {
- get { return searchable; }
- set { searchable = value; }
- }
- private bool searchable = true;
-
- /// <summary>
- /// Gets or sets whether the header for this column will include the column's Text.
- /// </summary>
- /// <remarks>
- /// <para>
- /// If this is false, the only thing rendered in the column header will be the image from <see cref="HeaderImageKey"/>.
- /// </para>
- /// <para>This setting is only considered when <see cref="ObjectListView.HeaderUsesThemes"/> is false on the owning ObjectListView.</para>
- /// </remarks>
- [Category("ObjectListView"),
- Description("Will the header for this column include text?"),
- DefaultValue(true)]
- public bool ShowTextInHeader {
- get { return showTextInHeader; }
- set { showTextInHeader = value; }
- }
- private bool showTextInHeader = true;
-
- /// <summary>
- /// Gets or sets whether the contents of the list will be resorted when the user clicks the
- /// header of this column.
- /// </summary>
- /// <remarks>
- /// <para>
- /// If this is false, clicking the header will not sort the list, but will not provide
- /// any feedback as to why the list is not being sorted. It is the programmers responsibility to
- /// provide appropriate feedback.
- /// </para>
- /// <para>When this is false, BeforeSorting events are still fired, which can be used to allow sorting
- /// or give feedback, on a case by case basis.</para>
- /// </remarks>
- [Category("ObjectListView"),
- Description("Will clicking this columns header resort the list?"),
- DefaultValue(true)]
- public bool Sortable {
- get { return sortable; }
- set { sortable = value; }
- }
- private bool sortable = true;
-
- /// <summary>
- /// Gets or sets the horizontal alignment of the contents of the column.
- /// </summary>
- /// <remarks>.NET will not allow column 0 to have any alignment except
- /// to the left. We can't change the basic behaviour of the listview,
- /// but when owner drawn, column 0 can now have other alignments.</remarks>
- new public HorizontalAlignment TextAlign {
- get {
- return this.textAlign.HasValue ? this.textAlign.Value : base.TextAlign;
- }
- set {
- this.textAlign = value;
- base.TextAlign = value;
- }
- }
- private HorizontalAlignment? textAlign;
-
- /// <summary>
- /// Gets the StringAlignment equivilent of the column text alignment
- /// </summary>
- [Browsable(false)]
- public StringAlignment TextStringAlign {
- get {
- switch (this.TextAlign) {
- case HorizontalAlignment.Center:
- return StringAlignment.Center;
- case HorizontalAlignment.Left:
- return StringAlignment.Near;
- case HorizontalAlignment.Right:
- return StringAlignment.Far;
- default:
- return StringAlignment.Near;
- }
- }
- }
-
- /// <summary>
- /// What string should be displayed when the mouse is hovered over the header of this column?
- /// </summary>
- /// <remarks>If a HeaderToolTipGetter is installed on the owning ObjectListView, this
- /// value will be ignored.</remarks>
- [Category("ObjectListView"),
- Description("The tooltip to show when the mouse is hovered over the header of this column"),
- DefaultValue((String)null),
- Localizable(true)]
- public String ToolTipText {
- get { return toolTipText; }
- set { toolTipText = value; }
- }
- private String toolTipText;
-
- /// <summary>
- /// Should this column have a tri-state checkbox?
- /// </summary>
- /// <remarks>
- /// If this is true, the user can choose the third state (normally Indeterminate).
- /// </remarks>
- [Category("ObjectListView"),
- Description("Should values in this column be treated as a tri-state checkbox?"),
- DefaultValue(false)]
- public virtual bool TriStateCheckBoxes {
- get { return triStateCheckBoxes; }
- set {
- triStateCheckBoxes = value;
- if (value && !this.CheckBoxes)
- this.CheckBoxes = true;
- }
- }
- private bool triStateCheckBoxes;
-
- /// <summary>
- /// Group objects by the initial letter of the aspect of the column
- /// </summary>
- /// <remarks>
- /// One common pattern is to group column by the initial letter of the value for that group.
- /// The aspect must be a string (obviously).
- /// </remarks>
- [Category("ObjectListView"),
- Description("The name of the property or method that should be called to get the aspect to display in this column"),
- DefaultValue(false)]
- public bool UseInitialLetterForGroup {
- get { return useInitialLetterForGroup; }
- set { useInitialLetterForGroup = value; }
- }
- private bool useInitialLetterForGroup;
-
- /// <summary>
- /// Gets or sets whether or not this column should be user filterable
- /// </summary>
- [Category("ObjectListView"),
- Description("Does this column want to show a Filter menu item when its header is right clicked"),
- DefaultValue(true)]
- public bool UseFiltering {
- get { return useFiltering; }
- set { useFiltering = value; }
- }
- private bool useFiltering = true;
-
- /// <summary>
- /// Gets or sets a filter that will only include models where the model's value
- /// for this column is one of the values in ValuesChosenForFiltering
- /// </summary>
- [Browsable(false),
- DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
- public IModelFilter ValueBasedFilter {
- get {
- if (!this.UseFiltering)
- return null;
-
- if (valueBasedFilter != null)
- return valueBasedFilter;
-
- if (this.ClusteringStrategy == null)
- return null;
-
- if (this.ValuesChosenForFiltering == null || this.ValuesChosenForFiltering.Count == 0)
- return null;
-
- return new OneOfFilter(this.ClusteringStrategy.GetClusterKey, this.ValuesChosenForFiltering);
- }
- set { valueBasedFilter = value; }
- }
- private IModelFilter valueBasedFilter;
-
- /// <summary>
- /// Gets or sets the values that will be used to generate a filter for this
- /// column. For a model to be included by the generated filter, its value for this column
- /// must be in this list. If the list is null or empty, this column will
- /// not be used for filtering.
- /// </summary>
- [Browsable(false),
- DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
- public IList ValuesChosenForFiltering {
- get { return this.valuesChosenForFiltering; }
- set { this.valuesChosenForFiltering = value; }
- }
- private IList valuesChosenForFiltering = new ArrayList();
-
- /// <summary>
- /// What is the width of this column?
- /// </summary>
- [Category("ObjectListView"),
- Description("The width in pixels of this column"),
- DefaultValue(60)]
- new public int Width {
- get { return base.Width; }
- set {
- if (this.MaximumWidth != -1 && value > this.MaximumWidth)
- base.Width = this.MaximumWidth;
- else
- base.Width = Math.Max(this.MinimumWidth, value);
- }
- }
-
- /// <summary>
- /// Gets or set whether the contents of this column's cells should be word wrapped
- /// </summary>
- /// <remarks>If this column uses a custom IRenderer (that is, one that is not descended
- /// from BaseRenderer), then that renderer is responsible for implementing word wrapping.</remarks>
- [Category("ObjectListView"),
- Description("Draw this column cell's word wrapped"),
- DefaultValue(false)]
- public bool WordWrap {
- get { return wordWrap; }
- set {
- wordWrap = value;
-
- // If there isn't a renderer and they are turning word wrap off, we don't need to do anything
- if (this.Renderer == null && !wordWrap)
- return;
-
- // All other cases require a renderer of some sort
- if (this.Renderer == null)
- this.Renderer = new HighlightTextRenderer();
-
- BaseRenderer baseRenderer = this.Renderer as BaseRenderer;
-
- // If there is a custom renderer (not descended from BaseRenderer),
- // we leave it up to them to implement wrapping
- if (baseRenderer == null)
- return;
-
- baseRenderer.CanWrap = wordWrap;
- }
- }
- private bool wordWrap;
-
- #endregion
-
- #region Object commands
-
- /// <summary>
- /// For a given group value, return the string that should be used as the groups title.
- /// </summary>
- /// <param name="value">The group key that is being converted to a title</param>
- /// <returns>string</returns>
- public string ConvertGroupKeyToTitle(object value) {
- if (this.groupKeyToTitleConverter != null)
- return this.groupKeyToTitleConverter(value);
-
- return value == null ? "{null}" : this.ValueToString(value);
- }
-
- /// <summary>
- /// Get the checkedness of the given object for this column
- /// </summary>
- /// <param name="rowObject">The row object that is being displayed</param>
- /// <returns>The checkedness of the object</returns>
- public CheckState GetCheckState(object rowObject) {
- if (!this.CheckBoxes)
- return CheckState.Unchecked;
-
- bool? aspectAsBool = this.GetValue(rowObject) as bool?;
- if (aspectAsBool.HasValue) {
- if (aspectAsBool.Value)
- return CheckState.Checked;
- else
- return CheckState.Unchecked;
- } else
- return CheckState.Indeterminate;
- }
-
- /// <summary>
- /// Put the checkedness of the given object for this column
- /// </summary>
- /// <param name="rowObject">The row object that is being displayed</param>
- /// <param name="newState"></param>
- /// <returns>The checkedness of the object</returns>
- public void PutCheckState(object rowObject, CheckState newState) {
- if (newState == CheckState.Checked)
- this.PutValue(rowObject, true);
- else
- if (newState == CheckState.Unchecked)
- this.PutValue(rowObject, false);
- else
- this.PutValue(rowObject, null);
- }
-
- /// <summary>
- /// For a given row object, extract the value indicated by the AspectName property of this column.
- /// </summary>
- /// <param name="rowObject">The row object that is being displayed</param>
- /// <returns>An object, which is the aspect named by AspectName</returns>
- public object GetAspectByName(object rowObject) {
- if (this.aspectMunger == null)
- this.aspectMunger = new Munger(this.AspectName);
-
- return this.aspectMunger.GetValue(rowObject);
- }
- private Munger aspectMunger;
-
- /// <summary>
- /// For a given row object, return the object that is the key of the group that this row belongs to.
- /// </summary>
- /// <param name="rowObject">The row object that is being displayed</param>
- /// <returns>Group key object</returns>
- public object GetGroupKey(object rowObject) {
- if (this.groupKeyGetter == null) {
- object key = this.GetValue(rowObject);
- String keyAsString = key as String;
- if (keyAsString != null && this.UseInitialLetterForGroup) {
- if (keyAsString.Length > 0)
- key = keyAsString.Substring(0, 1).ToUpper();
- }
- return key;
- } else
- return this.groupKeyGetter(rowObject);
- }
-
- /// <summary>
- /// For a given row object, return the image selector of the image that should displayed in this column.
- /// </summary>
- /// <param name="rowObject">The row object that is being displayed</param>
- /// <returns>int or string or Image. int or string will be used as index into image list. null or -1 means no image</returns>
- public Object GetImage(object rowObject) {
- if (this.CheckBoxes)
- return this.GetCheckStateImage(rowObject);
-
- if (this.ImageGetter != null)
- return this.ImageGetter(rowObject);
-
- if (!String.IsNullOrEmpty(this.ImageAspectName)) {
- if (this.imageAspectMunger == null)
- this.imageAspectMunger = new Munger(this.ImageAspectName);
-
- return this.imageAspectMunger.GetValue(rowObject);
- }
-
- // I think this is wrong. ImageKey is meant for the image in the header, not in the rows
- if (!String.IsNullOrEmpty(this.ImageKey))
- return this.ImageKey;
-
- return this.ImageIndex;
- }
- private Munger imageAspectMunger;
-
- /// <summary>
- /// Return the image that represents the check box for the given model
- /// </summary>
- /// <param name="rowObject"></param>
- /// <returns></returns>
- public string GetCheckStateImage(Object rowObject) {
- CheckState checkState = this.GetCheckState(rowObject);
-
- if (checkState == CheckState.Checked)
- return ObjectListView.CHECKED_KEY;
-
- if (checkState == CheckState.Unchecked)
- return ObjectListView.UNCHECKED_KEY;
-
- return ObjectListView.INDETERMINATE_KEY;
- }
-
- /// <summary>
- /// For a given row object, return the string representation of the value shown in this column.
- /// </summary>
- /// <remarks>
- /// For aspects that are string (e.g. aPerson.Name), the aspect and its string representation are the same.
- /// For non-strings (e.g. aPerson.DateOfBirth), the string representation is very different.
- /// </remarks>
- /// <param name="rowObject"></param>
- /// <returns></returns>
- public string GetStringValue(object rowObject) {
- return this.ValueToString(this.GetValue(rowObject));
- }
-
- /// <summary>
- /// For a given row object, return the object that is to be displayed in this column.
- /// </summary>
- /// <param name="rowObject">The row object that is being displayed</param>
- /// <returns>An object, which is the aspect to be displayed</returns>
- public object GetValue(object rowObject) {
- if (this.AspectGetter == null)
- return this.GetAspectByName(rowObject);
- else
- return this.AspectGetter(rowObject);
- }
-
- /// <summary>
- /// Update the given model object with the given value using the column's
- /// AspectName.
- /// </summary>
- /// <param name="rowObject">The model object to be updated</param>
- /// <param name="newValue">The value to be put into the model</param>
- public void PutAspectByName(Object rowObject, Object newValue) {
- if (this.aspectMunger == null)
- this.aspectMunger = new Munger(this.AspectName);
-
- this.aspectMunger.PutValue(rowObject, newValue);
- }
-
- /// <summary>
- /// Update the given model object with the given value
- /// </summary>
- /// <param name="rowObject">The model object to be updated</param>
- /// <param name="newValue">The value to be put into the model</param>
- public void PutValue(Object rowObject, Object newValue) {
- if (this.aspectPutter == null)
- this.PutAspectByName(rowObject, newValue);
- else
- this.aspectPutter(rowObject, newValue);
- }
-
- /// <summary>
- /// Convert the aspect object to its string representation.
- /// </summary>
- /// <remarks>
- /// If the column has been given a AspectToStringConverter, that will be used to do
- /// the conversion, otherwise just use ToString().
- /// The returned value will not be null. Nulls are always converted
- /// to empty strings.
- /// </remarks>
- /// <param name="value">The value of the aspect that should be displayed</param>
- /// <returns>A string representation of the aspect</returns>
- public string ValueToString(object value) {
- // Give the installed converter a chance to work (even if the value is null)
- if (this.AspectToStringConverter != null)
- return this.AspectToStringConverter(value) ?? String.Empty;
-
- // Without a converter, nulls become simple empty strings
- if (value == null)
- return String.Empty;
-
- string fmt = this.AspectToStringFormat;
- if (String.IsNullOrEmpty(fmt))
- return value.ToString();
- else
- return String.Format(fmt, value);
- }
-
- #endregion
-
- #region Utilities
-
- /// <summary>
- /// Decide the clustering strategy that will be used for this column
- /// </summary>
- /// <returns></returns>
- private IClusteringStrategy DecideDefaultClusteringStrategy() {
- if (!this.UseFiltering)
- return null;
-
- if (this.DataType == typeof(DateTime))
- return new DateTimeClusteringStrategy();
-
- return new ClustersFromGroupsStrategy();
- }
-
- /// <summary>
- /// Gets or sets the type of data shown in this column.
- /// </summary>
- /// <remarks>If this is not set, it will try to get the type
- /// by looking through the rows of the listview.</remarks>
- [Browsable(false),
- DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
- public Type DataType {
- get {
- if (this.dataType == null) {
- ObjectListView olv = this.ListView as ObjectListView;
- if (olv != null) {
- object value = olv.GetFirstNonNullValue(this);
- if (value != null)
- return value.GetType(); // THINK: Should we cache this?
- }
- }
- return this.dataType;
- }
- set {
- this.dataType = value;
- }
- }
- private Type dataType;
-
- /// <summary>
- /// Create groupies
- /// This is an untyped version to help with Generator and OLVColumn attributes
- /// </summary>
- /// <param name="values"></param>
- /// <param name="descriptions"></param>
- public void MakeGroupies(object[] values, string[] descriptions) {
- this.MakeGroupies(values, descriptions, null, null, null);
- }
-
- /// <summary>
- /// Create groupies
- /// </summary>
- /// <typeparam name="T"></typeparam>
- /// <param name="values"></param>
- /// <param name="descriptions"></param>
- public void MakeGroupies<T>(T[] values, string[] descriptions) {
- this.MakeGroupies(values, descriptions, null, null, null);
- }
-
- /// <summary>
- /// Create groupies
- /// </summary>
- /// <typeparam name="T"></typeparam>
- /// <param name="values"></param>
- /// <param name="descriptions"></param>
- /// <param name="images"></param>
- public void MakeGroupies<T>(T[] values, string[] descriptions, object[] images) {
- this.MakeGroupies(values, descriptions, images, null, null);
- }
-
- /// <summary>
- /// Create groupies
- /// </summary>
- /// <typeparam name="T"></typeparam>
- /// <param name="values"></param>
- /// <param name="descriptions"></param>
- /// <param name="images"></param>
- /// <param name="subtitles"></param>
- public void MakeGroupies<T>(T[] values, string[] descriptions, object[] images, string[] subtitles) {
- this.MakeGroupies(values, descriptions, images, subtitles, null);
- }
-
- /// <summary>
- /// Create groupies.
- /// Install delegates that will group the columns aspects into progressive partitions.
- /// If an aspect is less than value[n], it will be grouped with description[n].
- /// If an aspect has a value greater than the last element in "values", it will be grouped
- /// with the last element in "descriptions".
- /// </summary>
- /// <param name="values">Array of values. Values must be able to be
- /// compared to the aspect (using IComparable)</param>
- /// <param name="descriptions">The description for the matching value. The last element is the default description.
- /// If there are n values, there must be n+1 descriptions.</param>
- /// <example>
- /// this.salaryColumn.MakeGroupies(
- /// new UInt32[] { 20000, 100000 },
- /// new string[] { "Lowly worker", "Middle management", "Rarified elevation"});
- /// </example>
- /// <typeparam name="T"></typeparam>
- /// <param name="images"></param>
- /// <param name="subtitles"></param>
- /// <param name="tasks"></param>
- public void MakeGroupies<T>(T[] values, string[] descriptions, object[] images, string[] subtitles, string[] tasks) {
- // Sanity checks
- if (values == null)
- throw new ArgumentNullException("values");
- if (descriptions == null)
- throw new ArgumentNullException("descriptions");
- if (values.Length + 1 != descriptions.Length)
- throw new ArgumentException("descriptions must have one more element than values.");
-
- // Install a delegate that returns the index of the description to be shown
- this.GroupKeyGetter = delegate(object row) {
- Object aspect = this.GetValue(row);
- if (aspect == null || aspect == System.DBNull.Value)
- return -1;
- IComparable comparable = (IComparable)aspect;
- for (int i = 0; i < values.Length; i++) {
- if (comparable.CompareTo(values[i]) < 0)
- return i;
- }
-
- // Display the last element in the array
- return descriptions.Length - 1;
- };
-
- // Install a delegate that simply looks up the given index in the descriptions.
- this.GroupKeyToTitleConverter = delegate(object key) {
- if ((int)key < 0)
- return "";
-
- return descriptions[(int)key];
- };
-
- // Install one delegate that does all the other formatting
- this.GroupFormatter = delegate(OLVGroup group, GroupingParameters parms) {
- int key = (int)group.Key; // we know this is an int since we created it in GroupKeyGetter
-
- if (key >= 0) {
- if (images != null && key < images.Length)
- group.TitleImage = images[key];
-
- if (subtitles != null && key < subtitles.Length)
- group.Subtitle = subtitles[key];
-
- if (tasks != null && key < tasks.Length)
- group.Task = tasks[key];
- }
- };
- }
- /// <summary>
- /// Create groupies based on exact value matches.
- /// </summary>
- /// <remarks>
- /// Install delegates that will group rows into partitions based on equality of this columns aspects.
- /// If an aspect is equal to value[n], it will be grouped with description[n].
- /// If an aspect is not equal to any value, it will be grouped with "[other]".
- /// </remarks>
- /// <param name="values">Array of values. Values must be able to be
- /// equated to the aspect</param>
- /// <param name="descriptions">The description for the matching value.</param>
- /// <example>
- /// this.marriedColumn.MakeEqualGroupies(
- /// new MaritalStatus[] { MaritalStatus.Single, MaritalStatus.Married, MaritalStatus.Divorced, MaritalStatus.Partnered },
- /// new string[] { "Looking", "Content", "Looking again", "Mostly content" });
- /// </example>
- /// <typeparam name="T"></typeparam>
- /// <param name="images"></param>
- /// <param name="subtitles"></param>
- /// <param name="tasks"></param>
- public void MakeEqualGroupies<T>(T[] values, string[] descriptions, object[] images, string[] subtitles, string[] tasks) {
- // Sanity checks
- if (values == null)
- throw new ArgumentNullException("values");
- if (descriptions == null)
- throw new ArgumentNullException("descriptions");
- if (values.Length != descriptions.Length)
- throw new ArgumentException("descriptions must have the same number of elements as values.");
-
- ArrayList valuesArray = new ArrayList(values);
-
- // Install a delegate that returns the index of the description to be shown
- this.GroupKeyGetter = delegate(object row) {
- return valuesArray.IndexOf(this.GetValue(row));
- };
-
- // Install a delegate that simply looks up the given index in the descriptions.
- this.GroupKeyToTitleConverter = delegate(object key) {
- int intKey = (int)key; // we know this is an int since we created it in GroupKeyGetter
- return (intKey < 0) ? "[other]" : descriptions[intKey];
- };
-
- // Install one delegate that does all the other formatting
- this.GroupFormatter = delegate(OLVGroup group, GroupingParameters parms) {
- int key = (int)group.Key; // we know this is an int since we created it in GroupKeyGetter
-
- if (key >= 0) {
- if (images != null && key < images.Length)
- group.TitleImage = images[key];
-
- if (subtitles != null && key < subtitles.Length)
- group.Subtitle = subtitles[key];
-
- if (tasks != null && key < tasks.Length)
- group.Task = tasks[key];
- }
- };
- }
-
- #endregion
- }
- }