Maintain a form across query executions

I'm doing a bit of REPLing around a forms based component, but I'd like to maintain the form between query executions.
I've tried

open System.Windows.Forms
let f = Util.Cache(fun _ -> new Form())
f |> Dump //cannot access a disposed object on 2nd query run

The form shows on first query execution no problem.
But it is killed when the query is run a second time and the form becomes disposed.
(btw, my always use fresh processes setting is false)

Can it be done ?


  • Options

    LINQPad restarts the application and message loop on each query execution, which closes all forms. I can't think of any way around this.

  • Options

    Dang, I can use a Jupyter notebook to do it, but was hoping to stay in LP.
    If your subconscious throws you a possibility, do post and I'll try it.

  • Options

    Can you elaborate the scenario?

  • Options

    I'm doing a bit of work with CefSharp and I use the form browser during development efforts to help visualise things in the browser.
    I'm working on a site that requires me to log in to get at the parts of interest, and whilst I can automate the login process, I wanted to avoid having to relogin each time I REPL my query.
    So for all intents I wanted to consider the form/browser an expensive thing to create, and being able to Util.Cache it between runs would be epic.

  • Options

    You could try using WPF. It lets you create an application with a message loop that's independent of global state. It will need to run on its own thread, because app.Run blocks:

    void Main()
        // Window must be of type Window (not MyWindow) so that we can cache it.
        // We cannot usefully cache MyWindow because it's recompiled whenever
        // the query changes, changing its type.
        var window = GetWindow (() => new MyWindow());  
        // LINQPad's Uncapsulate() does the job of casting to dynamic, but is nicer to use.
        window.Dispatcher.Invoke (() => window.Uncapsulate().txtTest.Text.Dump());
    class MyWindow : Window
        public readonly Label lblTest = new Label
            Content = "Test:"
        public readonly TextBox txtTest = new TextBox
            VerticalContentAlignment = VerticalAlignment.Center
        public MyWindow()
            Title = "Test";
            Padding = new Thickness(5);
            var dock = new DockPanel();
            dock.Children.Add (lblTest);
            dock.Children.Add (txtTest);
            lblTest.SetValue (DockPanel.DockProperty, Dock.Left);
            var content = new StackPanel();
            content.Children.Add (dock);        
            Content = content;
    Window GetWindow (Func<Window> windowCreator) =>
        Util.Cache (() => CreateWindow (windowCreator));
    Window CreateWindow (Func<Window> windowCreator)
        var windowSource = new TaskCompletionSource<Window>();
        var thread = new Thread (CreateWindowCore);
        thread.SetApartmentState (ApartmentState.STA);
        return windowSource.Task.Result;
        void CreateWindowCore()
            // Create a new application so we can run a message loop
            // that's independent of the default dispatcher.
            var app = new Application();
            var window = windowCreator();
            windowSource.SetResult (window);
            app.Run (window);
  • Options

    Nice. Will give it a spin and see how I go. Thanks.

  • Options

    For anyone landing here. Joe's suggestion of WPF works great, however the WPF CefSharp browser has performance issues on high DPI machines. So the workaround is to use the CefSharp forms based browser and host it in a WPF app via a WindowsFormsHost control. Make sure the initialisation of CefSharp is done on the WPF thread not on the linqpad thread as the form will die between between restarts.

    Now things are epic. Damn linqpad is good...

Sign In or Register to comment.