fabulous-dev / Fabulous

Declarative UI framework for cross-platform mobile & desktop apps, using MVU and F# functional programming
https://fabulous.dev
Apache License 2.0
1.16k stars 122 forks source link

Black screen when closing and reopening view #629

Closed JordanMarr closed 5 years ago

JordanMarr commented 5 years ago

I'm trying to get the latest version running as an Autodesk Revit add-in. I want to show a view when a the command is launched from the toolbar.
The first time it runs fine. Then I close the window and run it again and the window just shows a black screen. If I try to resize the window it gives a null ref exception.

I made this controller with a "showDialog" function to launch the window from my Revit command:

namespace Cupertino.Features.UI

open Xamarin.Forms
open Xamarin.Forms.Platform.WPF
open Fabulous
open Fabulous.XamarinForms
open Fabulous.XamarinForms.LiveUpdate

type private MainWindow() = 
    inherit FormsApplicationPage()

type private GenericApp<'model, 'msg> (program : Program<unit, 'model, 'msg>) as app =
    inherit Application ()
    let runner = 
        program
#if DEBUG
        |> Program.withConsoleTrace
#endif
        |> XamarinFormsProgram.run app

#if DEBUG
    do runner.EnableLiveUpdate()
#endif    

/// Load UI pages here.
module Controller =

    let mutable private initialized = false

    let private init() =
        if not initialized then
            let app = 
                System.Windows.Application.Current  
                |> Option.ofObj
                |> Option.defaultWith System.Windows.Application

            app.ShutdownMode <- System.Windows.ShutdownMode.OnExplicitShutdown
            if not Forms.IsInitialized then Forms.Init()
            initialized <- true

    let showDialog program =
        init()
        let win = MainWindow()
        program |> GenericApp |> win.LoadApplication
        win.ShowDialog() |> ignore

If I launch this as a standalone Windows app it renders the window fine both times:

module Cupertino.Features.UI.Main

open System

[<EntryPoint>]
[<STAThread>]
let main(_args) =

    // Launch app/view
    DrawingLogComparePage.program 
    |> Controller.showDialog     

    // Run a second time
    DrawingLogComparePage.program 
    |> Controller.showDialog     

    0

So maybe this has to do with the fact that I'm launching from within Revit. But the interesting thing is that I don't run into this issue using the old version of Fabulous (that uses Program.runWithDynamicView app instead of XamarinFormsProgram.run app).

Is there something inherently wrong with my approach? I.e. maybe I am trying to use Fabulous to open and close views, when in reality it should be used as an "app"?

TimLariviere commented 5 years ago

Migrating from the old Fabulous v0.35 to Fabulous.XamarinForms v0.40+ should not break your use case in particular. It's really just a split between multiple assemblies, basically it's the same code.

Can you please give us the version of Fabulous.XamarinForms you're using? Is it the latest one (v0.50)? Do you have any errors printed in the console output? (both for the black screen and the null ref)

One thing you could also test if you're using F.XF v0.50 is to downgrade to F.XF v0.43. Might be an issue with v0.50, or an issue with Xamarin.Forms 4.3 (v0.43 targets XF 4.2).

TimLariviere commented 5 years ago

628 seems to be more or less the same issue.

Calling this.LoadApplication(...) multiple times results in this blank/black screen.

Don't know why exactly

JordanMarr commented 5 years ago

I reverted back to F.XF v0.43 and Xamarin.Forms 4.2, but still got the black screen on second load.

So now I'm back to the latest (F.XF v0.50.3 and Xamarin.Forms v4.3.0).

On the first (successful load) I get this in the console:

'Revit.exe' (CLR v4.0.30319: DefaultDomain): Loaded 'D:\_vsts\CupertinoTools\Source\Cupertino.Commands\bin\DebugBeta\EPPlus.dll'. Skipped loading symbols. Module is optimized and the debugger option 'Just My Code' is enabled.
'Revit.exe' (CLR v4.0.30319: DefaultDomain): Loaded 'D:\_vsts\CupertinoTools\Source\Cupertino.Commands\bin\DebugBeta\Xamarin.Forms.Platform.WPF.dll'. Skipped loading symbols. Module is optimized and the debugger option 'Just My Code' is enabled.
'Revit.exe' (CLR v4.0.30319: DefaultDomain): Loaded 'D:\_vsts\CupertinoTools\Source\Cupertino.Commands\bin\DebugBeta\Xamarin.Forms.Core.dll'. Skipped loading symbols. Module is optimized and the debugger option 'Just My Code' is enabled.
'Revit.exe' (CLR v4.0.30319: DefaultDomain): Loaded 'C:\WINDOWS\Microsoft.Net\assembly\GAC_MSIL\System.ValueTuple\v4.0_4.0.0.0__cc7b13ffcd2ddd51\System.ValueTuple.dll'. Skipped loading symbols. Module is optimized and the debugger option 'Just My Code' is enabled.
'Revit.exe' (CLR v4.0.30319: DefaultDomain): Loaded 'D:\_vsts\BenjaminMoore.ColorSuite\ProductSelector\Product\Source\ProductSelector\bin\Debug2019\ProductSelector.Domain.dll'. Symbols loaded.
'Revit.exe' (CLR v4.0.30319: DefaultDomain): Loaded 'D:\_vsts\CupertinoTools\Source\Cupertino.Commands\bin\DebugBeta\Fabulous.XamarinForms.dll'. Skipped loading symbols. Module is optimized and the debugger option 'Just My Code' is enabled.
'Revit.exe' (CLR v4.0.30319: DefaultDomain): Loaded 'D:\_vsts\CupertinoTools\Source\Cupertino.Commands\bin\DebugBeta\Fabulous.XamarinForms.LiveUpdate.dll'. Skipped loading symbols. Module is optimized and the debugger option 'Just My Code' is enabled.
'Revit.exe' (CLR v4.0.30319: DefaultDomain): Loaded 'D:\_vsts\CupertinoTools\Source\Cupertino.Commands\bin\DebugBeta\Fabulous.LiveUpdate.dll'. Skipped loading symbols. Module is optimized and the debugger option 'Just My Code' is enabled.
'Revit.exe' (CLR v4.0.30319: DefaultDomain): Loaded 'D:\_vsts\CupertinoTools\Source\Cupertino.Commands\bin\DebugBeta\en\FSharp.Core.resources.dll'. Module was built without symbols.
'Revit.exe' (CLR v4.0.30319: DefaultDomain): Loaded 'C:\WINDOWS\Microsoft.Net\assembly\GAC_MSIL\System.Console\v4.0_4.0.0.0__b03f5f7f11d50a3a\System.Console.dll'. Module was built without symbols.
'Revit.exe' (CLR v4.0.30319: DefaultDomain): Loaded 'C:\WINDOWS\Microsoft.Net\assembly\GAC_MSIL\System.IO\v4.0_4.0.0.0__b03f5f7f11d50a3a\System.IO.dll'. Skipped loading symbols. Module is optimized and the debugger option 'Just My Code' is enabled.

On the second load, I get this in the console:

System.Windows.Media.Animation Warning: 6 : Unable to perform action because the specified Storyboard was never applied to this object for interactive control.; Action='Stop'; Storyboard='System.Windows.Media.Animation.Storyboard'; Storyboard.HashCode='48512956'; Storyboard.Type='System.Windows.Media.Animation.Storyboard'; TargetElement='Autodesk.Internal.Windows.ToolTip'; TargetElement.HashCode='18585321'; TargetElement.Type='Autodesk.Internal.Windows.ToolTip'

If I then try to resize the black screen I get the following null ref exception:

An unhandled exception of type 'System.NullReferenceException' occurred in Xamarin.Forms.Platform.WPF.dll
Object reference not set to an instance of an object.

Stack trace:

" at Xamarin.Forms.Platform.WPF.WPFPlatformServices.GetNamedSize(NamedSize size, Type targetElementType, Boolean useOldSizes)\r\n at Xamarin.Forms.Label.Xamarin.Forms.Internals.IFontElement.FontSizeDefaultValueCreator()\r\n at Xamarin.Forms.FontElement.FontSizeDefaultValueCreator(BindableObject bindable)\r\n at Xamarin.Forms.BindableObject.CreateAndAddContext(BindableProperty property)\r\n at Xamarin.Forms.BindableObject.GetValue(BindableProperty property)\r\n at Xamarin.Forms.Label.get_FontSize()\r\n at Xamarin.Forms.Platform.WPF.FontExtensions.IsDefault(IFontElement self)\r\n at Xamarin.Forms.Platform.WPF.LabelRenderer.UpdateFont()\r\n at Xamarin.Forms.Platform.WPF.LabelRenderer.OnElementChanged(ElementChangedEventArgs1 e)\r\n at Xamarin.Forms.Platform.WPF.ViewRenderer2.SetElement(VisualElement element)\r\n at Xamarin.Forms.Platform.WPF.Platform.CreateRenderer(VisualElement element)\r\n at Xamarin.Forms.Platform.WPF.LayoutRenderer.<>c__DisplayClass5_0.b__0()\r\n at Xamarin.Forms.Platform.WPF.LayoutRenderer.OnElementChanged(ElementChangedEventArgs1 e)\r\n at Xamarin.Forms.Platform.WPF.ViewRenderer2.SetElement(VisualElement element)\r\n at Xamarin.Forms.Platform.WPF.Platform.CreateRenderer(VisualElement element)\r\n at Xamarin.Forms.Platform.WPF.Platform.GetOrCreateRenderer(VisualElement element)\r\n at Xamarin.Forms.Platform.WPF.PageRenderer.UpdateContent()\r\n at Xamarin.Forms.Platform.WPF.PageRenderer.OnElementChanged(ElementChangedEventArgs1 e)\r\n at Xamarin.Forms.Platform.WPF.ViewRenderer2.SetElement(VisualElement element)\r\n at Xamarin.Forms.Platform.WPF.Platform.CreateRenderer(VisualElement element)\r\n at Xamarin.Forms.Platform.WPF.Platform.GetOrCreateRenderer(VisualElement element)\r\n at Xamarin.Forms.Platform.WPF.FormsContentLoader.CreateOrResizeContent(FrameworkElement parent, VisualElement visualElement)\r\n at Xamarin.Forms.Platform.WPF.FormsContentLoader.OnSizeContentChanged(FrameworkElement parent, Object page)\r\n at System.Windows.RoutedEventArgs.InvokeHandler(Delegate handler, Object target)\r\n at System.Windows.RoutedEventHandlerInfo.InvokeHandler(Object target, RoutedEventArgs routedEventArgs)\r\n at System.Windows.EventRoute.InvokeHandlersImpl(Object source, RoutedEventArgs args, Boolean reRaised)\r\n at System.Windows.UIElement.RaiseEventImpl(DependencyObject sender, RoutedEventArgs args)\r\n at System.Windows.FrameworkElement.OnRenderSizeChanged(SizeChangedInfo sizeInfo)\r\n at System.Windows.ContextLayoutManager.fireSizeChangedEvents()\r\n at System.Windows.ContextLayoutManager.UpdateLayout()\r\n at System.Windows.Interop.HwndSource.Process_WM_SIZE(UIElement rootUIElement, IntPtr hwnd, WindowMessage msg, IntPtr wParam, IntPtr lParam)\r\n at System.Windows.Interop.HwndSource.LayoutFilterMessage(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam, Boolean& handled)\r\n at MS.Win32.HwndWrapper.WndProc(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam, Boolean& handled)\r\n at MS.Win32.HwndSubclass.DispatcherCallbackOperation(Object o)\r\n at System.Windows.Threading.ExceptionWrapper.InternalRealCall(Delegate callback, Object args, Int32 numArgs)\r\n at System.Windows.Threading.ExceptionWrapper.TryCatchWhen(Object source, Delegate callback, Object args, Int32 numArgs, Delegate catchHandler)\r\n at System.Windows.Threading.Dispatcher.LegacyInvokeImpl(DispatcherPriority priority, TimeSpan timeout, Delegate method, Object args, Int32 numArgs)\r\n at MS.Win32.HwndSubclass.SubclassWndProc(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam)\r\n at MS.Win32.UnsafeNativeMethods.CallWindowProc(IntPtr wndProc, IntPtr hWnd, Int32 msg, IntPtr wParam, IntPtr lParam)\r\n at MS.Win32.HwndSubclass.DefWndProcWrapper(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam)\r\n at MS.Win32.UnsafeNativeMethods.CallWindowProc(IntPtr wndProc, IntPtr hWnd, Int32 msg, IntPtr wParam, IntPtr lParam)\r\n at MS.Win32.HwndSubclass.SubclassWndProc(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam)"

JordanMarr commented 5 years ago

After reading many posts about Xamarin Forms and black screens, I have to conclude that this is more of a Xamarin issue than a Fabulous one. I also am thinking that perhaps I should not complicate my current project with Xamarin over WPF. As much as I'd love to use Fabulous, maybe Elmish.WPF would be a better fit due to having one less dependency to deal with.

TimLariviere commented 5 years ago

@JordanMarr If you're really motivated, you can take a look at Fabulous.WPF It's Fabulous but directly using WPF instead of Xamarin.Forms.

Currently it's only a proof of concept and supports a very limited number of controls. But it can easily support more.

Otherwise Elmish.WPF.Dynamic is somewhat like Fabulous.WPF.

JordanMarr commented 5 years ago

Thanks! I will definitely check out Fabulous.WPF.