Skip to content

Latest commit

 

History

History

connect-wpf

{
  "cells": [
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "# Embedded kernels \n",
        "\n",
        "This notebook and the C# project in this folder demonstrates how you can use .NET Interactive to embed a kernel within an app, connect to it from another kernel, and use the notebook to change the app's runtime state.\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\n",
        "## Connect to the WPF app\n",
        "\n",
        "First, let's start the WPF app and connect to it."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 1,
      "metadata": {
        "dotnet_interactive": {
          "language": "pwsh"
        }
      },
      "outputs": [],
      "source": [
        "Start-Process -NoNewWindow dotnet run"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "Once the cell above has finished running, you should see the app's window open. Next, we'll connect to it using a named pipe. The code that sets this up within the WPF app can be seen in [`App.xaml.cs`](https:/dotnet/interactive/blob/main/samples/connect-wpf/App.xaml.cs)."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 3,
      "metadata": {
        "dotnet_interactive": {
          "language": "csharp"
        }
      },
      "outputs": [
        {
          "data": {
            "text/plain": [
              "Kernel added: #!wpf"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        }
      ],
      "source": [
        "#!connect named-pipe --kernel-name wpf --pipe-name InteractiveWpf"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "The topology of connected kernels now looks like this:"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 3,
      "metadata": {
        "dotnet_interactive": {
          "language": "mermaid"
        }
      },
      "outputs": [
        {
          "data": {
            "text/html": [
              "<div class=\"mermaidMarkdownContainer\" style=\"background-color:white\">\r\n",
              "<link rel=\"stylesheet\" href=\"https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.2.0/css/all.min.css\">\r\n",
              "<div id=\"63d43123c029402ca234fff1c282a50f\"></div>\r\n",
              "<script type=\"module\">\r\n",
              "\r\n",
              "            import mermaid from 'https://cdn.jsdelivr.net/npm/[email protected]/dist/mermaid.esm.min.mjs';\r\n",
              "            let renderTarget = document.getElementById('63d43123c029402ca234fff1c282a50f');\r\n",
              "            try {\r\n",
              "                const {svg, bindFunctions} = await mermaid.mermaidAPI.render( \r\n",
              "                    'mermaid_63d43123c029402ca234fff1c282a50f', \r\n",
              "                    `flowchart LR\n",
              "    subgraph WPF app\n",
              "    embedded[\"Embedded C# kernel\"]\n",
              "    end\n",
              "    subgraph notebook\n",
              "    CompositeKernel-->n1[\"Local C# kernel\"]\n",
              "    CompositeKernel-->n2\n",
              "    n2[\"#!wpf kernel added using #!connect\"]--named pipe-->embedded\n",
              "    end`);\r\n",
              "                renderTarget.innerHTML = svg;\r\n",
              "                bindFunctions?.(renderTarget);\r\n",
              "            }\r\n",
              "            catch (error) {\r\n",
              "                console.log(error);\r\n",
              "            }\r\n",
              "</script>\r\n",
              "</div>\r\n"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        }
      ],
      "source": [
        "flowchart LR\n",
        "    subgraph WPF app\n",
        "    embedded[\"Embedded C# kernel\"]\n",
        "    end\n",
        "    subgraph notebook\n",
        "    CompositeKernel-->n1[\"Local C# kernel\"]\n",
        "    CompositeKernel-->n2\n",
        "    n2[\"#!wpf kernel added using #!connect\"]--named pipe-->embedded\n",
        "    end"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "## Change the styling of the app\n",
        "\n",
        "The notebook outputs here are displayed using custom formatters defined within the WPF app itself. Take a look at the file [`WpfFormatterMixins.cs`](https:/dotnet/interactive/blob/main/samples/connect-wpf/WpfFormatterMixins.cs).\n",
        "\n",
        "You'll also notice that you can get completions for the `App` object which is exposed to the notebook's kernel by the embedded kernel. "
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 5,
      "metadata": {
        "dotnet_interactive": {
          "language": "wpf"
        },
        "polyglot_notebook": {
          "kernelName": "wpf"
        }
      },
      "outputs": [
        {
          "data": {
            "text/html": [
              "<div><div style=\"border:2px solid #FFFFFF;background-color:#FF00FFFF;width:15px;height:15px\"></div><div><b>#FF00FFFF</b></div></div>"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        }
      ],
      "source": [
        "#!dispatcher\n",
        "using System.Windows.Media;\n",
        "\n",
        "App.MainWindow.Background = new SolidColorBrush(Colors.Fuchsia);\n",
        "App.MainWindow.Background"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 8,
      "metadata": {
        "dotnet_interactive": {
          "language": "wpf"
        },
        "polyglot_notebook": {
          "kernelName": "wpf"
        }
      },
      "outputs": [
        {
          "data": {
            "text/html": [
              "<img src=\"data:image/png;base64, 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RAQAABAiIgAAgBARAQAAhIgIAAAgREQAAAAhIgIAAAgREQAAQIiIAAAAQkQEAAAQIiIAAIAQEQEAAISICAAAIEREAAAAISICAAAIEREAAECIiAAAAEJEBAAAECIiAACAEBEBAACEiAgAACBERAAAACEiAgAACBERAABAiIgAAABCRAQAABAiIgAAgBARAQAAhIgIAAAgREQAAAAhIgIAAAgREQAAQIiIAAAAQkQEAAAQIiIAAIAQEQEAAISICAAAIEREAAAAISICAAAIEREAAECIiAAAAEJEBAAAECIiAACAEBEBAACEiAgAACBERAAAACEiAgAACBERAABAiIgAAABCRAQAABAiIgAAgBARAQAAhIgIAAAgREQAAAAhIgIAAAgREQAAQIiIAAAAQkQEAAAQIiIAAIAQEQEAAISICAAAIEREAAAAISICAAAIEREAAECIiAAAAEJEBAAAECIiAACAEBEBAACEiAgAACBERAAAACEiAgAACBERAABAiIgAAABCRAQAABAiIgAAgBARAQAAhIgIAAAgREQAAAAhIgIAAAgREQAAQIiIAAAAQkQEAAAQIiIAAIAQEQEAAISICAAAIEREAAAAISICAAAIEREAAECIiAAAAEJEBAAAECIiAACAEBEBAACEiAgAACBERAAAACEiAgAACBERAABAiIgAAABCRAQAABAiIgAAgBARAQAAhIgIAAAgREQAAAAhIgIAAAgREQAAQIiIAAAAQkQEAAAQIiIAAIAQEQEAAISICAAAIEREAAAAISICAAAIEREAAECIiAAAAEJEBAAAECIiAACAEBEBAACEiAgAACBERAAAACEiAgAACBERAABAiIgAAABCRAQAABAiIgAAgBARAQAAhIgIAAAgREQAAAAhIgIAAAgREQAAQIiIAAAAQkQEAAAQIiIAAIAQEQEAAISICAAAIEREAAAAISICAAAIEREAAECIiAAAAEJEBAAAECIiAACAEBEBAACEiAgAACBERAAAACEiAgAACBERAABAiIgAAABCRAQAABAiIgAAgBARAQAAhIgIAAAgREQAAAAhIgIAAAgREQAAQIiIAAAAQkQEAAAQIiIAAIAQEQEAAISICAAAIEREAAAAISICAAAIEREAAECIiAAAAEJEBAAAECIiAACAEBEBAACEiAgAACBERAAAACEiAgAACBERAABAiIgAAABCRAQAABAiIgAAgBARAQAAhIgIAAAgREQAAAAhIgIAAAgREQAAQIiIAAAAQkQEAAAQIiIAAIAQEQEAAISICAAAIEREAAAAISICAAAIEREAAECIiAAAAEJEBAAAECIiAACAEBEBAACEiAgAACBERAAAACEiAgAACBERAABAiIgAAABCRAQAABAiIgAAgBARAQAAhIgIAAAgREQAAAAhIgIAAAgREQAAQIiIAAAAQkQEAAAQIiIAAIAQEQEAAISICAAAIEREAAAAISICAAAIEREAAECIiAAAAEJEBAAAECIiAACAEBEBAACEiAgAACBERAAAACEiAgAACBERAABAiIgAAABCRAQAABAiIgAAgBARAQAAhIgIAAAgREQAAAAhIgIAAAgREQAAQIiIAAAAQkQEAAAQIiIAAIAQEQEAAISICAAAIEREAAAAISICAAAIEREAAECIiAAAAEJEBAAAECIiAACAEBEBAACEiAgAACBERAAAACEiAgAACBERAABAiIgAAABCRAQAABAiIgAAgBARAQAAhIgIAAAgREQAAAAhIgIAAAgREQAAQIiIAAAAQkQEAAAQIiIAAIAQEQEAAISICAAAIEREAAAAISICAAAIEREAAECIiAAAAEJEBAAAECIiAACAEBEBAACEiAgAACBERAAAACEiAgAACBERAABAiIgAAABCRAQAABAiIgAAgBARAQAAhIgIAAAgREQAAAAhIgIAAAgREQAAQIiIAAAAQkQEAAAQIiIAAIAQEQEAAISICAAAIEREAAAAISICAAAIEREAAECIiAAAAEJEBAAAECIiAACAEBEBAACEiAgAACBERAAAACEiAgAACBERAABAiIgAAABCRAQAABAiIgAAgBARAQAAhIgIAAAgREQAAAAhIgIAAAgREQAAQIiIAAAAQkQEAAAQIiIAAIAQEQEAAISICAAAIEREAAAAISICAAAIEREAAECIiAAAAEJEBAAAECIiAACAEBEBAACEiAgAACBERAAAACEiAgAACBERAABAiIgAAABCRAQAABAiIgAAgBARAQAAhIgIAAAgREQAAAAhIgIAAAgREQAAQIiIAAAAQkQEAAAQIiIAAIAQEQEAAISICAAAIEREAAAAISICAAAIEREAAECIiAAAAEJEBAAAECIiAACAEBEBAACEiAgAACBERAAAACEiAgAACBERAABAiIgAAABCRAQAABAiIgAAgBARAQAABBTF/wO8312v+a85KgAAAABJRU5ErkJggg==\" width=\"785.3333333333334\" height=\"412.6666666666667\"></img>"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        }
      ],
      "source": [
        "#!dispatcher\n",
        "using System.Windows.Media;\n",
        "using System.Windows.Controls;\n",
        "using System.Windows;\n",
        "\n",
        "var content = (Grid)App.MainWindow.Content;\n",
        "content.Background = new SolidColorBrush(Colors.RoyalBlue);\n",
        "content.UpdateLayout();\n",
        "content"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "## Change view models at runtime\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\n",
        "Create and apply a new view model to the main window."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 9,
      "metadata": {
        "dotnet_interactive": {
          "language": "wpf"
        },
        "polyglot_notebook": {
          "kernelName": "wpf"
        }
      },
      "outputs": [],
      "source": [
        "using System.ComponentModel;\n",
        "using System.Collections.ObjectModel;\n",
        "\n",
        "public class TestViewModel : INotifyPropertyChanged\n",
        "{\n",
        "    public event PropertyChangedEventHandler PropertyChanged;\n",
        "\n",
        "    private string _text = \"Initial Value from notebook view model\";\n",
        "    \n",
        "    public string Text\n",
        "    {\n",
        "        get => _text;\n",
        "        set\n",
        "        {\n",
        "            if (_text != value)\n",
        "            {\n",
        "                _text = value;\n",
        "                PropertyChanged.Invoke(this, new PropertyChangedEventArgs(nameof(Text)));\n",
        "            }\n",
        "        }\n",
        "    }\n",
        "}\n",
        "\n",
        "var vm = new TestViewModel();\n",
        "\n",
        "#!wpf\n",
        "#!dispatcher\n",
        "App.MainWindow.DataContext = vm;"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "Update the value on the data bound property."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 10,
      "metadata": {
        "dotnet_interactive": {
          "language": "wpf"
        },
        "polyglot_notebook": {
          "kernelName": "wpf"
        }
      },
      "outputs": [
        {
          "data": {
            "text/plain": [
              "Value changed!"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        }
      ],
      "source": [
        "vm.Text = \"Value changed!\""
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        " ## Dispatcher stuff\n",
        "\n",
        " Demonstate enabling and disabling running code on the dispatcher. "
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 13,
      "metadata": {
        "dotnet_interactive": {
          "language": "wpf"
        },
        "polyglot_notebook": {
          "kernelName": "wpf"
        }
      },
      "outputs": [],
      "source": [
        "#!dispatcher --enabled \n",
        "//This should work\n",
        "App.MainWindow.Title = \"Title change executed on dispatcher thread\";\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 14,
      "metadata": {
        "dotnet_interactive": {
          "language": "wpf"
        },
        "polyglot_notebook": {
          "kernelName": "wpf"
        }
      },
      "outputs": [
        {
          "ename": "Error",
          "evalue": "System.InvalidOperationException: The calling thread cannot access this object because a different thread owns it.\r\n   at System.Windows.Threading.Dispatcher.<VerifyAccess>g__ThrowVerifyAccess|7_0()\r\n   at System.Windows.Application.get_MainWindow()\r\n   at Submission#15.<<Initialize>>d__0.MoveNext()\r\n--- End of stack trace from previous location ---\r\n   at Microsoft.CodeAnalysis.Scripting.ScriptExecutionState.RunSubmissionsAsync[TResult](ImmutableArray`1 precedingExecutors, Func`2 currentExecutor, StrongBox`1 exceptionHolderOpt, Func`2 catchExceptionOpt, CancellationToken cancellationToken)",
          "output_type": "error",
          "traceback": [
            "System.InvalidOperationException: The calling thread cannot access this object because a different thread owns it.\r\n",
            "   at System.Windows.Threading.Dispatcher.<VerifyAccess>g__ThrowVerifyAccess|7_0()\r\n",
            "   at System.Windows.Application.get_MainWindow()\r\n",
            "   at Submission#15.<<Initialize>>d__0.MoveNext()\r\n",
            "--- End of stack trace from previous location ---\r\n",
            "   at Microsoft.CodeAnalysis.Scripting.ScriptExecutionState.RunSubmissionsAsync[TResult](ImmutableArray`1 precedingExecutors, Func`2 currentExecutor, StrongBox`1 exceptionHolderOpt, Func`2 catchExceptionOpt, CancellationToken cancellationToken)"
          ]
        }
      ],
      "source": [
        "\n",
        "#!dispatcher --enabled false\n",
        "//This is expected to fail\n",
        "App.MainWindow.Title = \"Not so much\";"
      ]
    }
  ],
  "metadata": {
    "kernelspec": {
      "display_name": ".NET (C#)",
      "language": "C#",
      "name": ".net-csharp"
    },
    "language_info": {
      "file_extension": ".cs",
      "mimetype": "text/x-csharp",
      "name": "polyglot-notebook",
      "pygments_lexer": "csharp",
      "version": "8.0"
    },
    "polyglot_notebook": {
      "kernelInfo": {
        "defaultKernelName": "csharp",
        "items": [
          {
            "aliases": [],
            "name": "csharp"
          },
          {
            "aliases": [],
            "languageName": "T-SQL",
            "name": "sql-adventureworks"
          },
          {
            "aliases": [],
            "name": "wpf"
          }
        ]
      }
    }
  },
  "nbformat": 4,
  "nbformat_minor": 4
}