mirror of
				https://github.com/9ParsonsB/Pulsar.git
				synced 2025-11-03 15:26:43 -05:00 
			
		
		
		
	[Core + Framework] Performance improvements for re-drawing the grid (#141)
This proposes a *new method* on IObservatoryCore: `SetGridItems(worker, items)` which does 2 things: * Clears the grid * Adds the given items. Effectively replaces the entire content of the grid -- which is something a handful of plugins now do. Why add this when you could just call Core's Clear + AddGridItems methods?? So it can all be done within the same rendering suppression "scope" to reduce flickering and increase rendering speed. Speaking of rendering suppression, I have implemented such rendering suppression "scope" which uses Listview's built-in Begin/EndUpdate() in combination with temporary removal of the sort comparer (as is done for read-alls). This was also applied to the existing AddGridItems(worker, items) method as well, addressing a TODO.
This commit is contained in:
		@@ -2,6 +2,7 @@
 | 
			
		||||
using Observatory.Framework.Files;
 | 
			
		||||
using Observatory.Framework.Interfaces;
 | 
			
		||||
using Observatory.NativeNotification;
 | 
			
		||||
using Observatory.UI;
 | 
			
		||||
using Observatory.Utils;
 | 
			
		||||
using System;
 | 
			
		||||
using System.Collections.ObjectModel;
 | 
			
		||||
@@ -114,11 +115,27 @@ namespace Observatory.PluginManagement
 | 
			
		||||
 | 
			
		||||
        public void AddGridItems(IObservatoryWorker worker, IEnumerable<object> items)
 | 
			
		||||
        {
 | 
			
		||||
            //TODO: Use better bulk handling here.
 | 
			
		||||
            BeginBulkUpdate(worker);
 | 
			
		||||
 | 
			
		||||
            foreach (var item in items)
 | 
			
		||||
            {
 | 
			
		||||
                worker.PluginUI.DataGrid.Add(item);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            EndBulkUpdate(worker);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void SetGridItems(IObservatoryWorker worker, IEnumerable<object> items)
 | 
			
		||||
        {
 | 
			
		||||
            BeginBulkUpdate(worker);
 | 
			
		||||
 | 
			
		||||
            worker.PluginUI.DataGrid.Clear();
 | 
			
		||||
            foreach (var item in items)
 | 
			
		||||
            {
 | 
			
		||||
                worker.PluginUI.DataGrid.Add(item);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            EndBulkUpdate(worker);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void ClearGrid(IObservatoryWorker worker, object templateItem)
 | 
			
		||||
@@ -186,5 +203,40 @@ namespace Observatory.PluginManagement
 | 
			
		||||
        {
 | 
			
		||||
            NativePopup.CloseAll();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void BeginBulkUpdate(IObservatoryWorker worker)
 | 
			
		||||
        {
 | 
			
		||||
            PluginListView? listView = FindPluginListView(worker);
 | 
			
		||||
            if (listView == null) return;
 | 
			
		||||
 | 
			
		||||
            ExecuteOnUIThread(() => { listView.SuspendDrawing(); });
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void EndBulkUpdate(IObservatoryWorker worker)
 | 
			
		||||
        {
 | 
			
		||||
            PluginListView? listView = FindPluginListView(worker);
 | 
			
		||||
            if (listView == null) return;
 | 
			
		||||
 | 
			
		||||
            ExecuteOnUIThread(() => { listView.ResumeDrawing(); });
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private PluginListView? FindPluginListView(IObservatoryWorker worker)
 | 
			
		||||
        {
 | 
			
		||||
            if (worker.PluginUI.PluginUIType != PluginUI.UIType.Basic
 | 
			
		||||
                || !(worker.PluginUI.UI is Panel)) return null;
 | 
			
		||||
 | 
			
		||||
            PluginListView? listView = null;
 | 
			
		||||
            Panel panel = worker.PluginUI.UI as Panel;
 | 
			
		||||
 | 
			
		||||
            foreach (var control in panel.Controls)
 | 
			
		||||
            {
 | 
			
		||||
                if (control?.GetType() == typeof(PluginListView))
 | 
			
		||||
                {
 | 
			
		||||
                    listView = (PluginListView)control;
 | 
			
		||||
                    return listView;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            return null;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -61,6 +61,7 @@ namespace Observatory.UI
 | 
			
		||||
            {
 | 
			
		||||
                Anchor = AnchorStyles.Left | AnchorStyles.Right | AnchorStyles.Bottom | AnchorStyles.Top
 | 
			
		||||
            };
 | 
			
		||||
            plugin.PluginUI.UI = panel;
 | 
			
		||||
 | 
			
		||||
            IObservatoryComparer columnSorter;
 | 
			
		||||
            if (plugin.ColumnSorter != null)
 | 
			
		||||
 
 | 
			
		||||
@@ -1,20 +1,17 @@
 | 
			
		||||
using System;
 | 
			
		||||
using System.Collections;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System.Linq;
 | 
			
		||||
using System.Runtime.InteropServices;
 | 
			
		||||
using System.Security.Permissions;
 | 
			
		||||
using System.Text;
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
using System.Windows.Forms;
 | 
			
		||||
 | 
			
		||||
namespace Observatory.UI
 | 
			
		||||
{
 | 
			
		||||
    internal class PluginListView : ListView
 | 
			
		||||
    {
 | 
			
		||||
        [DllImport("user32.dll")]
 | 
			
		||||
        private static extern int SendMessage(IntPtr hWnd, int wMsg, bool wParam, int lParam);
 | 
			
		||||
        
 | 
			
		||||
        private const int WM_SETREDRAW = 11;
 | 
			
		||||
 | 
			
		||||
        public PluginListView()
 | 
			
		||||
        {
 | 
			
		||||
            OwnerDraw = true;
 | 
			
		||||
@@ -28,6 +25,25 @@ namespace Observatory.UI
 | 
			
		||||
            base.GridLines = false;//We should prevent the default drawing of gridlines.
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Stash for performance when doing large UI updates.
 | 
			
		||||
        private IComparer? comparer = null;
 | 
			
		||||
 | 
			
		||||
        public void SuspendDrawing()
 | 
			
		||||
        {
 | 
			
		||||
            BeginUpdate();
 | 
			
		||||
            comparer = ListViewItemSorter;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void ResumeDrawing()
 | 
			
		||||
        {
 | 
			
		||||
            if (comparer != null)
 | 
			
		||||
            {
 | 
			
		||||
                ListViewItemSorter = comparer;
 | 
			
		||||
                comparer = null;
 | 
			
		||||
            }
 | 
			
		||||
            EndUpdate();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private static void DrawBorder(Graphics graphics, Pen pen, Rectangle bounds, bool header = false)
 | 
			
		||||
        {
 | 
			
		||||
            
 | 
			
		||||
 
 | 
			
		||||
@@ -187,6 +187,13 @@ namespace Observatory.Framework.Interfaces
 | 
			
		||||
        /// <param name="items">Grid items to be added. Object types should match original template item used to create the grid.</param>
 | 
			
		||||
        public void AddGridItems(IObservatoryWorker worker, IEnumerable<object> items);
 | 
			
		||||
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// Replace the contents of the grid with the provided items.
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        /// <param name="worker">Reference to the calling plugin's worker interface.</param>
 | 
			
		||||
        /// <param name="items">Grid items to be added. Object types should match original template item used to create the grid.</param>
 | 
			
		||||
        public void SetGridItems(IObservatoryWorker worker, IEnumerable<object> items);
 | 
			
		||||
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// Clears basic UI grid, removing all items.
 | 
			
		||||
        /// </summary>
 | 
			
		||||
 
 | 
			
		||||
@@ -1605,6 +1605,13 @@
 | 
			
		||||
            <param name="worker">Reference to the calling plugin's worker interface.</param>
 | 
			
		||||
            <param name="items">Grid items to be added. Object types should match original template item used to create the grid.</param>
 | 
			
		||||
        </member>
 | 
			
		||||
        <member name="M:Observatory.Framework.Interfaces.IObservatoryCore.SetGridItems(Observatory.Framework.Interfaces.IObservatoryWorker,System.Collections.Generic.IEnumerable{System.Object})">
 | 
			
		||||
            <summary>
 | 
			
		||||
            Replace the contents of the grid with the provided items.
 | 
			
		||||
            </summary>
 | 
			
		||||
            <param name="worker">Reference to the calling plugin's worker interface.</param>
 | 
			
		||||
            <param name="items">Grid items to be added. Object types should match original template item used to create the grid.</param>
 | 
			
		||||
        </member>
 | 
			
		||||
        <member name="M:Observatory.Framework.Interfaces.IObservatoryCore.ClearGrid(Observatory.Framework.Interfaces.IObservatoryWorker,System.Object)">
 | 
			
		||||
            <summary>
 | 
			
		||||
            Clears basic UI grid, removing all items.
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user