@@ -175,6 +175,12 @@ public void OnInputLanguageChanged(IKeyboardDefinition previousKeyboard, IKeyboa
175175 /// as on Mono Setting AutoScrollPosition causes a redraw even when AllowPainting == false
176176 /// </summary>
177177 private Point ? cachedAutoScrollPosition = null ;
178+ private bool m_fWarmingScrollViewport ;
179+ private bool m_fDeferredScrollWarmupPending = true ;
180+ private bool m_fDeferredScrollWarmupQueued ;
181+ private int m_lastScrollWarmDirection ;
182+ private int m_scrollWarmRangeTop = int . MinValue ;
183+ private int m_scrollWarmRangeBottom = int . MinValue ;
178184
179185 /// <summary>Used to draw the rootbox</summary>
180186 private IVwDrawRootBuffered m_vdrb ;
@@ -1620,6 +1626,7 @@ public virtual Point ScrollPosition
16201626 set
16211627 {
16221628 CheckDisposed ( ) ;
1629+ int previousViewportTop = - AutoScrollPosition . Y ;
16231630 Point newPos = value ;
16241631 if ( this . AutoScroll )
16251632 {
@@ -1637,7 +1644,140 @@ public virtual Point ScrollPosition
16371644 AutoScrollPosition = newPos ;
16381645 else
16391646 cachedAutoScrollPosition = newPos ;
1647+
1648+ int scrollDelta = newPos . Y - previousViewportTop ;
1649+ if ( scrollDelta != 0 )
1650+ m_lastScrollWarmDirection = Math . Sign ( scrollDelta ) ;
1651+
1652+ WarmScrollViewportIfNeeded ( ) ;
1653+ }
1654+ }
1655+
1656+ protected virtual int ScrollWarmupMargin
1657+ {
1658+ get
1659+ {
1660+ return Math . Max ( 1 , ClientRectangle . Height / 2 ) ;
1661+ }
1662+ }
1663+
1664+ protected virtual void WarmScrollViewportIfNeeded ( )
1665+ {
1666+ WarmScrollViewportIfNeeded ( false ) ;
1667+ }
1668+
1669+ private void WarmScrollViewportIfNeeded ( bool preferSymmetric )
1670+ {
1671+ if ( m_fWarmingScrollViewport || m_fInPaint || m_fInLayout || m_rootb == null ||
1672+ m_dxdLayoutWidth <= 0 || ! AllowPainting || ClientRectangle . Height <= 0 )
1673+ {
1674+ return ;
1675+ }
1676+
1677+ int viewportTop = - ScrollPosition . Y ;
1678+ int viewportBottom = viewportTop + ClientRectangle . Height ;
1679+ GetScrollWarmupMargins ( preferSymmetric , out int warmMarginTop , out int warmMarginBottom ) ;
1680+ if ( viewportTop >= m_scrollWarmRangeTop && viewportBottom <= m_scrollWarmRangeBottom )
1681+ {
1682+ m_fDeferredScrollWarmupPending = false ;
1683+ return ;
1684+ }
1685+
1686+ using ( new HoldGraphics ( this ) )
1687+ {
1688+ m_fWarmingScrollViewport = true ;
1689+ try
1690+ {
1691+ Rectangle rcSrcRoot ;
1692+ Rectangle rcDstRoot ;
1693+ GetCoordRects ( out rcSrcRoot , out rcDstRoot ) ;
1694+
1695+ if ( PrepareToDrawForScrollWarmup ( rcSrcRoot , rcDstRoot ) == VwPrepDrawResult . kxpdrInvalidate )
1696+ return ;
1697+
1698+ if ( warmMarginTop > 0 )
1699+ {
1700+ if ( PrepareToDrawForScrollWarmup ( rcSrcRoot , OffsetRootRect ( rcDstRoot , - warmMarginTop ) ) == VwPrepDrawResult . kxpdrInvalidate )
1701+ return ;
1702+ }
1703+
1704+ if ( warmMarginBottom > 0 )
1705+ {
1706+ if ( PrepareToDrawForScrollWarmup ( rcSrcRoot , OffsetRootRect ( rcDstRoot , warmMarginBottom ) ) == VwPrepDrawResult . kxpdrInvalidate )
1707+ return ;
1708+ }
1709+ }
1710+ finally
1711+ {
1712+ m_fWarmingScrollViewport = false ;
1713+ }
16401714 }
1715+
1716+ viewportTop = - ScrollPosition . Y ;
1717+ viewportBottom = viewportTop + ClientRectangle . Height ;
1718+ m_scrollWarmRangeTop = viewportTop - warmMarginTop ;
1719+ m_scrollWarmRangeBottom = viewportBottom + warmMarginBottom ;
1720+ m_fDeferredScrollWarmupPending = false ;
1721+ }
1722+
1723+ private void GetScrollWarmupMargins ( bool preferSymmetric , out int warmMarginTop , out int warmMarginBottom )
1724+ {
1725+ int fullMargin = ScrollWarmupMargin ;
1726+ if ( preferSymmetric || m_lastScrollWarmDirection == 0 )
1727+ {
1728+ warmMarginTop = fullMargin ;
1729+ warmMarginBottom = fullMargin ;
1730+ return ;
1731+ }
1732+
1733+ int trailingMargin = Math . Max ( 1 , fullMargin / 2 ) ;
1734+ if ( m_lastScrollWarmDirection > 0 )
1735+ {
1736+ warmMarginTop = trailingMargin ;
1737+ warmMarginBottom = fullMargin ;
1738+ }
1739+ else
1740+ {
1741+ warmMarginTop = fullMargin ;
1742+ warmMarginBottom = trailingMargin ;
1743+ }
1744+ }
1745+
1746+ private static Rectangle OffsetRootRect ( Rectangle rect , int dy )
1747+ {
1748+ rect . Offset ( 0 , dy ) ;
1749+ return rect ;
1750+ }
1751+
1752+ protected virtual VwPrepDrawResult PrepareToDrawForScrollWarmup ( Rectangle rcSrcRoot , Rectangle rcDstRoot )
1753+ {
1754+ VwPrepDrawResult xpdr = VwPrepDrawResult . kxpdrAdjust ;
1755+ while ( xpdr == VwPrepDrawResult . kxpdrAdjust )
1756+ xpdr = PrepareToDraw ( rcSrcRoot , rcDstRoot ) ;
1757+
1758+ return xpdr ;
1759+ }
1760+
1761+ private void QueueDeferredScrollWarmup ( )
1762+ {
1763+ if ( m_fDeferredScrollWarmupQueued || IsDisposed )
1764+ return ;
1765+ if ( ! m_fDeferredScrollWarmupPending )
1766+ return ;
1767+ if ( ! IsHandleCreated || ! Visible || m_rootb == null || ! AllowPainting )
1768+ return ;
1769+
1770+ m_fDeferredScrollWarmupQueued = true ;
1771+ BeginInvoke ( ( MethodInvoker ) delegate
1772+ {
1773+ m_fDeferredScrollWarmupQueued = false ;
1774+ if ( IsDisposed || ! m_fDeferredScrollWarmupPending )
1775+ return ;
1776+ if ( ! IsHandleCreated || ! Visible || m_rootb == null || ! AllowPainting || m_fInLayout )
1777+ return ;
1778+
1779+ WarmScrollViewportIfNeeded ( true ) ;
1780+ } ) ;
16411781 }
16421782
16431783 /// -----------------------------------------------------------------------------------
@@ -2151,6 +2291,8 @@ public bool AllowPainting
21512291 Update ( ) ;
21522292 Invalidate ( ) ;
21532293 }
2294+
2295+ QueueDeferredScrollWarmup ( ) ;
21542296 }
21552297 }
21562298 else
@@ -3287,6 +3429,8 @@ protected override void OnVisibleChanged(EventArgs e)
32873429 base . OnVisibleChanged ( e ) ;
32883430 if ( Visible && m_fRootboxMade && m_rootb != null && m_fRefreshPending )
32893431 RefreshDisplay ( ) ;
3432+ if ( Visible )
3433+ QueueDeferredScrollWarmup ( ) ;
32903434 }
32913435
32923436 /// <summary>
@@ -3854,7 +3998,10 @@ protected override void OnLayout(LayoutEventArgs levent)
38543998 using ( new HoldGraphics ( this ) )
38553999 {
38564000 if ( DoLayout ( ) )
4001+ {
38574002 Invalidate ( ) ;
4003+ QueueDeferredScrollWarmup ( ) ;
4004+ }
38584005 }
38594006 }
38604007
@@ -5570,6 +5717,10 @@ protected bool UpdateScrollRange(int dxdRange, int dxdPos, int dydRange, int dyd
55705717 /// -----------------------------------------------------------------------------------
55715718 protected virtual bool DoLayout ( )
55725719 {
5720+ m_fDeferredScrollWarmupPending = true ;
5721+ m_scrollWarmRangeTop = int . MinValue ;
5722+ m_scrollWarmRangeBottom = int . MinValue ;
5723+
55735724 if ( DesignMode && ! AllowPaintingInDesigner )
55745725 return false ;
55755726
0 commit comments