📄 virtualobjectlistview.cs
字号:
/// <param name="modelObjects">Collection of objects to be removed</param>
/// <remarks>
/// <para>Nulls and model objects that are not in the ListView are silently ignored.</para>
/// <para>Due to problems in the underlying ListView, if you remove all the objects from
/// the control using this method and the list scroll vertically when you do so,
/// then when you subsequenially add more objects to the control,
/// the vertical scroll bar will become confused and the control will draw one or more
/// blank lines at the top of the list. </para>
/// </remarks>
public override void RemoveObjects(ICollection modelObjects)
{
if (this.DataSource == null)
return;
// Give the world a chance to cancel or change the removed objects
ItemsRemovingEventArgs args = new ItemsRemovingEventArgs(modelObjects);
this.OnItemsRemoving(args);
if (args.Canceled)
return;
this.ClearCachedInfo();
this.DataSource.RemoveObjects(args.ObjectsToRemove);
this.UpdateVirtualListSize();
}
/// <summary>
/// Select the row that is displaying the given model object. All other rows are deselected.
/// </summary>
/// <param name="setFocus">Should the object be focused as well?</param>
public override void SelectObject(object modelObject, bool setFocus)
{
// Without a data source, we can't do this.
if (this.DataSource == null)
return;
// Check that the object is in the list (plus not all data sources can locate objects)
int index = this.DataSource.GetObjectIndex(modelObject);
if (index < 0 || index >= this.VirtualListSize)
return;
// If the given model is already selected, don't do anything else (prevents an flicker)
if (this.SelectedIndices.Count == 1 && this.SelectedIndices[0] == index)
return;
// Finally, select the row
this.SelectedIndices.Clear();
this.SelectedIndices.Add(index);
if (setFocus)
this.SelectedItem.Focused = true;
}
/// <summary>
/// Select the rows that is displaying any of the given model object. All other rows are deselected.
/// </summary>
/// <param name="modelObjects">A collection of model objects</param>
/// <remarks>This method has O(n) performance where n is the number of model objects passed.
/// Do not use this to select all the rows in the list -- use SelectAll() for that.</remarks>
public override void SelectObjects(IList modelObjects)
{
// Without a data source, we can't do this.
if (this.DataSource == null)
return;
this.SelectedIndices.Clear();
if (modelObjects == null)
return;
foreach (object modelObject in modelObjects) {
int index = this.DataSource.GetObjectIndex(modelObject);
if (index >= 0 && index < this.VirtualListSize)
this.SelectedIndices.Add(index);
}
}
/// <summary>
/// Set the collection of objects that this control will show.
/// </summary>
/// <param name="collection"></param>
/// <remark>This method can safely be called from background threads.</remark>
public override void SetObjects(IEnumerable collection)
{
if (this.InvokeRequired) {
this.Invoke((MethodInvoker)delegate { this.SetObjects(collection); });
return;
}
if (this.DataSource == null)
return;
this.BeginUpdate();
try {
// Give the world a chance to cancel or change the assigned collection
ItemsChangingEventArgs args = new ItemsChangingEventArgs(null, collection);
this.OnItemsChanging(args);
if (args.Canceled)
return;
this.DataSource.SetObjects(args.NewObjects);
this.UpdateVirtualListSize();
this.Sort();
}
finally {
this.EndUpdate();
}
}
#endregion
#region Implementation
/// <summary>
/// Invalidate any cached information when we rebuild the list.
/// </summary>
public override void BuildList(bool shouldPreserveSelection)
{
this.ClearCachedInfo();
this.Invalidate();
}
/// <summary>
/// Clear any cached info this list may have been using
/// </summary>
public virtual void ClearCachedInfo()
{
this.lastRetrieveVirtualItemIndex = -1;
}
/// <summary>
/// Get the checkedness of an object from the model. Returning null means the
/// model does know and the value from the control will be used.
/// </summary>
/// <param name="modelObject"></param>
/// <returns></returns>
protected override CheckState? GetCheckState(object modelObject)
{
if (this.CheckStateGetter != null)
return base.GetCheckState(modelObject);
CheckState state = CheckState.Unchecked;
if (modelObject != null)
this.checkStateMap.TryGetValue(modelObject, out state);
return state;
}
/// <summary>
/// Create a OLVListItem for given row index
/// </summary>
/// <param name="itemIndex">The index of the row that is needed</param>
/// <returns>An OLVListItem</returns>
public virtual OLVListItem MakeListViewItem(int itemIndex)
{
OLVListItem olvi = new OLVListItem(this.GetModelObject(itemIndex));
this.FillInValues(olvi, olvi.RowObject);
if (this.UseAlternatingBackColors) {
if (this.View == View.Details && itemIndex % 2 == 1)
olvi.BackColor = this.AlternateRowBackColorOrDefault;
else
olvi.BackColor = this.BackColor;
this.CorrectSubItemColors(olvi);
}
if (this.UseHotItem && this.HotItemIndex == itemIndex)
this.ApplyHotItemStyle(olvi);
this.SetSubItemImages(itemIndex, olvi);
return olvi;
}
/// <summary>
/// Record the change of checkstate for the given object in the model.
/// This does not update the UI -- only the model
/// </summary>
/// <param name="modelObject"></param>
/// <param name="state"></param>
/// <returns>The check state that was recorded and that should be used to update
/// the control.</returns>
protected override CheckState PutCheckState(object modelObject, CheckState state)
{
state = base.PutCheckState(modelObject, state);
this.checkStateMap[modelObject] = state;
return state;
}
/// <summary>
/// Prepare the listview to show alternate row backcolors
/// </summary>
/// <remarks>Alternate colored backrows can't be handle in the same way as our base class.
/// With virtual lists, they are handled at RetrieveVirtualItem time.</remarks>
protected override void PrepareAlternateBackColors()
{
// do nothing
}
/// <summary>
/// Refresh the given item in the list
/// </summary>
/// <param name="olvi">The item to refresh</param>
public override void RefreshItem(OLVListItem olvi)
{
this.ClearCachedInfo();
this.RedrawItems(olvi.Index, olvi.Index, false);
}
/// <summary>
/// Change the size of the list
/// </summary>
/// <param name="newSize"></param>
protected virtual void SetVirtualListSize(int newSize)
{
if (newSize < 0 || this.VirtualListSize == newSize)
return;
int oldSize = this.VirtualListSize;
this.ClearCachedInfo();
// There is a bug in .NET when a virtual ListView is cleared
// (i.e. VirtuaListSize set to 0) AND it is scrolled vertically: the scroll position
// is wrong when the list is next populated. To avoid this, before
// clearing a virtual list, we make sure the list is scrolled to the top.
// [6 weeks later] Damn this is a pain! There are cases where this can also throw exceptions!
try {
if (newSize == 0 && this.TopItemIndex > 0)
this.TopItemIndex = 0;
}
catch (Exception) {
// Ignore any failures
}
// In strange cases, this can throw the exceptions too. The best we can do is ignore them :(
try {
this.VirtualListSize = newSize;
}
catch (ArgumentOutOfRangeException) {
// pass
}
catch (NullReferenceException) {
// pass
}
// Tell the world that the size of the list has changed
this.OnItemsChanged(new ItemsChangedEventArgs(oldSize, this.VirtualListSize));
}
/// <summary>
/// Take ownership of the 'objects' collection. This separates our collection from the source.
/// </summary>
/// <remarks>
/// <para>
/// This method
/// separates the 'objects' instance variable from its source, so that any AddObject/RemoveObject
/// calls will modify our collection and not the original colleciton.
/// </para>
/// <para>
/// VirtualObjectListViews always own their collections, so this is a no-op.
/// </para>
/// </remarks>
protected override void TakeOwnershipOfObjects()
{
}
/// <summary>
/// Change the size of the virtual list so that it matches its data source
/// </summary>
public virtual void UpdateVirtualListSize()
{
if (this.DataSource != null)
this.SetVirtualListSize(this.DataSource.GetObjectCount());
}
#endregion
#region Event handlers
/// <summary>
/// Handle the CacheVirtualItems event
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
protected virtual void HandleCacheVirtualItems(object sender, CacheVirtualItemsEventArgs e)
{
if (this.DataSource != null)
this.DataSource.PrepareCache(e.StartIndex, e.EndIndex);
}
/// <summary>
/// Event handler for the column click event
/// </summary>
/// <remarks>
/// <para>
/// This differs from its base version by explicitly preserving selection.
/// The base class (ObjectListView) stores the selection state in the ListViewItem
/// objects, so when they are sorted, the selected-ness is automatically preserved.
/// But a virtual list only knows which indices are selected, so the same rows are
/// selected after sorting, even if they are showing different objects. So, we have
/// to specifically remember which objects were selected, and then reselected them
/// afterwards.
/// </para>
/// <para>
/// For large lists when many objects are selected, this re-selection
/// is the slowest part of sorting the list.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -