@@ -1756,7 +1756,7 @@ private void PresentationSourceChangedHandler(object sender, SourceChangedEventA
17561756 }
17571757 }
17581758
1759- private void OnWindowStateChanged ( object sender , EventArgs e )
1759+ private async void OnWindowStateChanged ( object sender , EventArgs e )
17601760 {
17611761 var window = ( Window ) sender ;
17621762
@@ -1767,33 +1767,54 @@ private void OnWindowStateChanged(object sender, EventArgs e)
17671767 {
17681768 if ( previousWindowState == WindowState . Minimized )
17691769 {
1770- CefUiThreadRunAsync ( ( ) =>
1770+ await CefUiThreadRunAsync ( async ( ) =>
17711771 {
1772- if ( browser != null )
1772+ var host = browser ? . GetHost ( ) ;
1773+ if ( host != null && ! host . IsDisposed )
17731774 {
1774- browser . GetHost ( ) . WasHidden ( false ) ;
1775+ try
1776+ {
1777+ host . WasHidden ( false ) ;
1778+
1779+ await ResizeHackFor2779 ( ) ;
1780+ }
1781+ catch ( ObjectDisposedException )
1782+ {
1783+ // Because Dispose runs in another thread there's a race condition between
1784+ // that and this code running on the CEF UI thread, so the host could be disposed
1785+ // between the check and using it. We can either synchronize access using locking
1786+ // (potentially blocking the UI thread in Dispose) or catch the extremely rare
1787+ // exception, which is what we do here
1788+ }
17751789 }
17761790 } ) ;
1777-
1778- ResizeHackFor2779 ( ) ;
17791791 }
17801792
17811793 break ;
17821794 }
17831795 case WindowState . Minimized :
17841796 {
1785- if ( EnableResizeHackForIssue2779 )
1786- {
1787- resizeHackForIssue2779Enabled = true ;
1788- }
1789-
1790- CefUiThreadRunAsync ( ( ) =>
1797+ await CefUiThreadRunAsync ( ( ) =>
17911798 {
1792- if ( browser != null )
1799+ var host = browser ? . GetHost ( ) ;
1800+ if ( host != null && ! host . IsDisposed )
17931801 {
1794- browser . GetHost ( ) . WasHidden ( true ) ;
1802+ if ( EnableResizeHackForIssue2779 )
1803+ {
1804+ resizeHackForIssue2779Enabled = true ;
1805+ }
1806+
1807+ try
1808+ {
1809+ host . WasHidden ( true ) ;
1810+ }
1811+ catch ( ObjectDisposedException )
1812+ {
1813+ // See comment in catch in OnWindowStateChanged
1814+ }
17951815 }
17961816 } ) ;
1817+
17971818 break ;
17981819 }
17991820 }
@@ -1889,7 +1910,7 @@ internal void UiThreadRunAsync(Action action, DispatcherPriority priority = Disp
18891910 }
18901911 }
18911912
1892- protected void CefUiThreadRunAsync ( Action action )
1913+ protected async Task CefUiThreadRunAsync ( Action action )
18931914 {
18941915 if ( ! IsDisposed && InternalIsBrowserInitialized ( ) )
18951916 {
@@ -1899,7 +1920,7 @@ protected void CefUiThreadRunAsync(Action action)
18991920 }
19001921 else
19011922 {
1902- Cef . UIThreadTaskFactory . StartNew ( delegate
1923+ await Cef . UIThreadTaskFactory . StartNew ( delegate
19031924 {
19041925 action ( ) ;
19051926 } ) ;
@@ -1929,54 +1950,96 @@ private void UiThreadRunSync(Action action, DispatcherPriority priority = Dispat
19291950 /// </summary>
19301951 /// <param name="sender">The sender.</param>
19311952 /// <param name="e">The <see cref="SizeChangedEventArgs"/> instance containing the event data.</param>
1932- private void OnActualSizeChanged ( object sender , SizeChangedEventArgs e )
1953+ private async void OnActualSizeChanged ( object sender , SizeChangedEventArgs e )
19331954 {
19341955 // Initialize RenderClientAdapter when WPF has calculated the actual size of current content.
19351956 CreateOffscreenBrowser ( e . NewSize ) ;
19361957
1937- //NOTE: Previous we used Math.Ceiling to round the sizing up, we
1938- //now set UseLayoutRounding = true; on the control so the sizes are
1939- //already rounded to a whole number for us.
1940- viewRect = new Rect ( 0 , 0 , ( int ) e . NewSize . Width , ( int ) e . NewSize . Height ) ;
1958+ // If the internal browser isn't initialized then the CEF UI thread is not yet running
1959+ // and so we need to set the view rectangle here because it has to be set.
1960+ var hasSetViewRect = false ;
1961+ if ( ! InternalIsBrowserInitialized ( ) )
1962+ {
1963+ SetViewRect ( e ) ;
1964+ hasSetViewRect = true ;
1965+ }
19411966
1942- CefUiThreadRunAsync ( ( ) =>
1967+ await CefUiThreadRunAsync ( ( ) =>
19431968 {
1944- if ( browser != null )
1969+ // If we haven't already set the view rectangle we do it here.
1970+ // If the browser is initialized we need to set this on the CEF UI thread to
1971+ // avoid the crash issue reported here: https://github.com/cefsharp/CefSharp/issues/2779
1972+ if ( ! hasSetViewRect )
19451973 {
1946- browser . GetHost ( ) . WasResized ( ) ;
1974+ SetViewRect ( e ) ;
1975+ }
1976+
1977+ var host = browser ? . GetHost ( ) ;
1978+ if ( host != null && ! host . IsDisposed )
1979+ {
1980+ try
1981+ {
1982+ host . WasResized ( ) ;
1983+ }
1984+ catch ( ObjectDisposedException )
1985+ {
1986+ // See comment in catch in OnWindowStateChanged
1987+ }
19471988 }
19481989 } ) ;
19491990 }
19501991
1992+ private void SetViewRect ( SizeChangedEventArgs e )
1993+ {
1994+ //NOTE: Previous we used Math.Ceiling to round the sizing up, we
1995+ //now set UseLayoutRounding = true; on the control so the sizes are
1996+ //already rounded to a whole number for us.
1997+ viewRect = new Rect ( 0 , 0 , ( int ) e . NewSize . Width , ( int ) e . NewSize . Height ) ;
1998+ }
1999+
19512000 /// <summary>
19522001 /// Handles the <see cref="E:IsVisibleChanged" /> event.
19532002 /// </summary>
19542003 /// <param name="sender">The sender.</param>
19552004 /// <param name="args">The <see cref="DependencyPropertyChangedEventArgs"/> instance containing the event data.</param>
1956- private void OnIsVisibleChanged ( object sender , DependencyPropertyChangedEventArgs args )
2005+ private async void OnIsVisibleChanged ( object sender , DependencyPropertyChangedEventArgs args )
19572006 {
19582007 var isVisible = ( bool ) args . NewValue ;
19592008
19602009 if ( browser != null )
19612010 {
1962- CefUiThreadRunAsync ( ( ) =>
2011+ await CefUiThreadRunAsync ( async ( ) =>
19632012 {
1964- if ( browser != null )
2013+ var host = browser ? . GetHost ( ) ;
2014+ if ( host != null && ! host . IsDisposed )
19652015 {
1966- browser . GetHost ( ) . WasHidden ( ! isVisible ) ;
2016+ try
2017+ {
2018+ host . WasHidden ( ! isVisible ) ;
2019+
2020+ if ( isVisible )
2021+ {
2022+ await ResizeHackFor2779 ( ) ;
2023+ }
2024+ else if ( EnableResizeHackForIssue2779 )
2025+ {
2026+ resizeHackForIssue2779Enabled = true ;
2027+ }
2028+ }
2029+ catch ( ObjectDisposedException )
2030+ {
2031+ // See comment in catch in OnWindowStateChanged
2032+ }
19672033 }
19682034 } ) ;
19692035
1970-
1971- if ( isVisible )
2036+ if ( browser != null )
19722037 {
1973- ResizeHackFor2779 ( ) ;
1974-
19752038 //Fix for #1778 - When browser becomes visible we update the zoom level
19762039 //browsers of the same origin will share the same zoomlevel and
19772040 //we need to track the update, so our ZoomLevelProperty works
19782041 //properly
1979- browser . GetHost ( ) . GetZoomLevelAsync ( ) . ContinueWith ( t =>
2042+ await browser . GetHost ( ) . GetZoomLevelAsync ( ) . ContinueWith ( t =>
19802043 {
19812044 if ( ! IsDisposed )
19822045 {
@@ -1987,10 +2050,6 @@ private void OnIsVisibleChanged(object sender, DependencyPropertyChangedEventArg
19872050 TaskContinuationOptions . OnlyOnRanToCompletion ,
19882051 TaskScheduler . FromCurrentSynchronizationContext ( ) ) ;
19892052 }
1990- else if ( EnableResizeHackForIssue2779 )
1991- {
1992- resizeHackForIssue2779Enabled = true ;
1993- }
19942053 }
19952054 }
19962055
@@ -2442,33 +2501,30 @@ protected bool InternalIsBrowserInitialized()
24422501 return Interlocked . CompareExchange ( ref browserInitialized , 0 , 0 ) == 1 ;
24432502 }
24442503
2445- private void ResizeHackFor2779 ( )
2504+ private async Task ResizeHackFor2779 ( )
24462505 {
24472506 if ( EnableResizeHackForIssue2779 )
24482507 {
24492508 const int delayInMs = 50 ;
24502509
2451- CefUiThreadRunAsync ( async ( ) =>
2510+ var host = browser ? . GetHost ( ) ;
2511+ if ( host != null && ! host . IsDisposed )
24522512 {
2453- if ( browser != null )
2454- {
2455- resizeHackForIssue2779Size = new Structs . Size ( viewRect . Width - 1 , viewRect . Height - 1 ) ;
2456- browser . GetHost ( ) . WasResized ( ) ;
2457- }
2513+ resizeHackForIssue2779Size = new Structs . Size ( viewRect . Width - 1 , viewRect . Height - 1 ) ;
2514+ host . WasResized ( ) ;
24582515
24592516 await Task . Delay ( delayInMs ) ;
24602517
2461- if ( browser != null )
2518+ if ( ! host . IsDisposed )
24622519 {
2463- var host = browser . GetHost ( ) ;
24642520 resizeHackForIssue2779Size = null ;
24652521 host . WasResized ( ) ;
24662522
24672523 resizeHackForIssue2779Enabled = false ;
24682524
24692525 host . Invalidate ( PaintElementType . View ) ;
24702526 }
2471- } ) ;
2527+ }
24722528 }
24732529 }
24742530 }
0 commit comments