📄 virtualobjectlistview.cs
字号:
/*
* VirtualObjectListView - A virtual listview to show various aspects of a collection of objects
*
* Author: Phillip Piper
* Date: 27/09/2008 9:15 AM
*
* Change log:
* 2009-02-24 JPP - Removed redundant OnMouseDown() since checkbox
* handling is now handled in the base class
* 2009-01-07 JPP - Made all public and protected methods virtual
* 2008-12-07 JPP - Trigger Before/AfterSearching events
* 2008-11-15 JPP - Fixed some caching issues
* 2008-11-05 JPP - Rewrote handling of check boxes
* 2008-10-28 JPP - Handle SetSelectedObjects(null)
* 2008-10-02 JPP - MAJOR CHANGE: Use IVirtualListDataSource
* 2008-09-27 JPP - Separated from ObjectListView.cs
*
* Copyright (C) 2006-2009 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.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Windows.Forms;
namespace BrightIdeasSoftware
{
/// <summary>
/// A virtual object list view operates in virtual mode, that is, it only gets model objects for
/// a row when it is needed. This gives it the ability to handle very large numbers of rows with
/// minimal resources.
/// </summary>
/// <remarks><para>A listview is not a great user interface for a large number of items. But if you've
/// ever wanted to have a list with 10 million items, go ahead, knock yourself out.</para>
/// <para>Virtual lists can never iterate their contents. That would defeat the whole purpose.</para>
/// <para>Given the above, grouping is not possible on virtual lists.</para>
/// <para>For the same reason, animate GIFs should not be used in virtual lists. Animated GIFs require some state
/// information to be stored for each animation, but virtual lists specifically do not keep any state information.
/// In any case, you really do not want to keep state information for 10 million animations!</para>
/// <para>
/// Although it isn't documented, .NET virtual lists cannot have checkboxes. This class codes around this limitation,
/// but you must use the functions provided by ObjectListView: CheckedObjects, CheckObject(), UncheckObject() and their friends.
/// </para>
/// <para>
/// If you use the normal check box properties (CheckedItems or CheckedIndicies), they will throw an exception, since the
/// list is in virtual mode, and .NET "knows" it can't handle checkboxes in virtual mode.
/// The "CheckBoxes" property itself can be set once, but trying to unset it later will throw an exception.
/// </para>
/// <para>Due to the limits of the underlying Windows control, virtual lists do not trigger ItemCheck/ItemChecked events.
/// Use a CheckStatePutter instead.</para>
/// </remarks>
public class VirtualObjectListView : ObjectListView
{
/// <summary>
/// Create a VirtualObjectListView
/// </summary>
public VirtualObjectListView()
: base()
{
this.ShowGroups = false; // virtual lists can never show groups
this.VirtualMode = true; // Virtual lists have to be virtual -- no prizes for guessing that :)
this.CacheVirtualItems += new CacheVirtualItemsEventHandler(this.HandleCacheVirtualItems);
this.RetrieveVirtualItem += new RetrieveVirtualItemEventHandler(this.HandleRetrieveVirtualItem);
this.SearchForVirtualItem += new SearchForVirtualItemEventHandler(this.HandleSearchForVirtualItem);
// At the moment, we don't need to handle this event. But we'll keep this comment to remind us about it.
//this.VirtualItemsSelectionRangeChanged += new ListViewVirtualItemsSelectionRangeChangedEventHandler(VirtualObjectListView_VirtualItemsSelectionRangeChanged);
this.DataSource = new VirtualListVersion1DataSource(this);
}
#region Public Properties
/// <summary>
/// Get or set the collection of model objects that are checked.
/// When setting this property, any row whose model object isn't
/// in the given collection will be unchecked. Setting to null is
/// equivilent to unchecking all.
/// </summary>
/// <remarks>
/// <para>
/// This property returns a simple collection. Changes made to the returned
/// collection do NOT affect the list. This is different to the behaviour of
/// CheckedIndicies collection.
/// </para>
/// <para>
/// When getting CheckedObjects, the performance of this method is O(n) where n is the number of checked objects.
/// When setting CheckedObjects, the performance of this method is O(n) where n is the number of checked objects plus
/// the number of objects to be checked.
/// </para>
/// <para>
/// If the ListView is not currently showing CheckBoxes, this property does nothing. It does
/// not remember any check box settings made.
/// </para>
/// </remarks>
[Browsable(false),
DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public override IList CheckedObjects
{
get {
ArrayList objects = new ArrayList();
if (!this.CheckBoxes)
return objects;
if (this.CheckStateGetter != null)
return base.CheckedObjects;
foreach (KeyValuePair<Object, CheckState> kvp in this.checkStateMap) {
if (kvp.Value == CheckState.Checked)
objects.Add(kvp.Key);
}
return objects;
}
set {
if (!this.CheckBoxes)
return;
if (value == null)
value = new ArrayList();
Object[] keys = new Object[this.checkStateMap.Count];
this.checkStateMap.Keys.CopyTo(keys, 0);
foreach (Object key in keys) {
if (value.Contains(key))
this.SetObjectCheckedness(key, CheckState.Checked);
else
this.SetObjectCheckedness(key, CheckState.Unchecked);
}
foreach (Object x in value)
this.SetObjectCheckedness(x, CheckState.Checked);
}
}
/// <summary>
/// Get/set the data source that is behind this virtual list
/// </summary>
/// <remarks>Setting this will cause the list to redraw.</remarks>
[Browsable(false),
DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public virtual IVirtualListDataSource DataSource
{
get {
return this.dataSource;
}
set {
this.dataSource = value;
this.CustomSorter = delegate(OLVColumn column, SortOrder sortOrder) {
this.ClearCachedInfo();
this.dataSource.Sort(column, sortOrder);
};
this.UpdateVirtualListSize();
this.Invalidate();
}
}
private IVirtualListDataSource dataSource;
/// <summary>
/// This delegate is used to fetch a rowObject, given it's index within the list
/// </summary>
/// <remarks>Only use this property if you are not using a DataSource.</remarks>
[Browsable(false),
DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public virtual RowGetterDelegate RowGetter
{
get { return ((VirtualListVersion1DataSource)this.dataSource).RowGetter; }
set { ((VirtualListVersion1DataSource)this.dataSource).RowGetter = value; }
}
#endregion
#region OLV accessing
/// <summary>
/// Return the number of items in the list
/// </summary>
/// <returns>the number of items in the list</returns>
public override int GetItemCount()
{
return this.VirtualListSize;
}
/// <summary>
/// Return the model object at the given index
/// </summary>
/// <param name="index">Index of the model object to be returned</param>
/// <returns>A model object</returns>
public override object GetModelObject(int index)
{
if (this.DataSource != null)
return this.DataSource.GetNthObject(index);
else
return null;
}
/// <summary>
/// Return the OLVListItem that displays the given model object
/// </summary>
/// <param name="modelObject">The modelObject whose item is to be found</param>
/// <returns>The OLVListItem that displays the model, or null</returns>
/// <remarks>This method has O(n) performance.</remarks>
public override OLVListItem ModelToItem(object modelObject)
{
if (this.DataSource == null || modelObject == null)
return null;
int idx = this.DataSource.GetObjectIndex(modelObject);
if (idx >= 0)
return this.GetItem(idx);
else
return null;
}
#endregion
#region Object manipulation
/// <summary>
/// Add the given collection of model objects to this control.
/// </summary>
/// <param name="modelObjects">A collection of model objects</param>
/// <remarks>
/// <para>The added objects will appear in their correct sort position, if sorting
/// is active. Otherwise, they will appear at the end of the list.</para>
/// <para>No check is performed to see if any of the objects are already in the ListView.</para>
/// <para>Null objects are silently ignored.</para>
/// </remarks>
public override void AddObjects(ICollection modelObjects)
{
if (this.DataSource == null)
return;
// Give the world a chance to cancel or change the added objects
ItemsAddingEventArgs args = new ItemsAddingEventArgs(modelObjects);
this.OnItemsAdding(args);
if (args.Canceled)
return;
this.ClearCachedInfo();
this.DataSource.AddObjects(args.ObjectsToAdd);
this.Sort();
this.UpdateVirtualListSize();
}
/// <summary>
/// Remove all items from this list
/// </summary>
/// <remark>This method can safely be called from background threads.</remark>
public override void ClearObjects()
{
if (this.InvokeRequired)
this.Invoke(new MethodInvoker(this.ClearObjects));
else {
this.ClearCachedInfo();
this.SetVirtualListSize(0);
}
}
/// <summary>
/// Update the rows that are showing the given objects
/// </summary>
/// <remarks>This method does not resort the items.</remarks>
public override void RefreshObjects(IList modelObjects)
{
if (this.InvokeRequired) {
this.Invoke((MethodInvoker)delegate { this.RefreshObjects(modelObjects); });
return;
}
// Without a data source, we can't do this.
if (this.DataSource == null)
return;
this.ClearCachedInfo();
foreach (object modelObject in modelObjects) {
int index = this.DataSource.GetObjectIndex(modelObject);
if (index >= 0)
this.RedrawItems(index, index, true);
}
}
/// <summary>
/// Remove all of the given objects from the control
/// </summary>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -