Innovative views on .xaml projects

Weekend fun with VS Code extensions:

  • recursive transclusion of invoked workflow files
  • transformation into an AST syntax tress
  • copy for LLM as markdown (or .xaml or pseudocode or..)
  • Jump-to list
  • canvas-inspired, tree and .xaml view

Seems that I can reduce token use by a factor of 4 when a coding agent is interacting with a UiPath Studio project.
copy-as for quick pasting ito Claude Code was the major motivation.

Visually I overcome the most annoying visual-coding paradigm by

  • right-aligned
  • text
  • no-wrap (overflow to the right side)

Super-fast! On startup I am caching and need to wait a few seconds. After that I can jump around and scroll quickly.

Pictured: REFramework





personal hobby project, not available for anybody, “spike implementation” only.

Edit: alpha preview at CPMForge Workflow Lens - Visual Studio Marketplace

Ah, I forgot: Wireshark-inspired filter.
Not matching filters (include and exclude logic) are slightly dimmed.

Again, motivation is to copy to a coding agent.

  • Opening in my viewer Main.xaml
  • selecting InitAllSettings
  • and then “Copy-as” for LLM I get the following clipboard entry.

Again-again: I am viewing Main.xaml – and get the recursive transcluded invoked workflows.

As about every of my projects nowadays has .cs files it even works with reading coded-workflows into the AST :slight_smile:

<workflow-fragment>
<source file="Main.xaml" lines="612-740" />
<location>General Business Process › Initialization › Try initializing settings and applications › If first run, read local configuration file</location>
<author-notes>
- General Business Process: [Process title] [Process description] [Additional information (e.g., author, contact information and applications involved and required external setup)]
- Initialization: Read configuration file and initialize applications used in the process.
- If first run, read local configuration file: An uninitialized Config dictionary indicates that it is the first run of the process.
</author-notes>
<activity>
If first run, read local configuration file [If]
  # An uninitialized Config dictionary indicates that it is the first run of the process.
  Condition = Config is Nothing
  Then: First run:
    Log Message screen resolution [LogMessage]
      Level = "Info"
      Message = "The primary screen resolution is: "+Screen.PrimaryScreen.Bounds.Width.ToString+" x "+ Screen.PrimaryScreen.Bounds.Height.ToString
    Invoke InitAllSettings workflow [InvokeWorkflowFile]
      UnSafe = "False"
      invoke Framework/InitAllSettings.xaml
        in_ConfigFile : x:String -> Data\Config.xlsx
        in_ConfigSheets : s:String[] -> {"Settings", "Constants"}
        out_Config : scg:Dictionary(x:String, x:Object) <- Config
      Workflow:
        Initialize All Settings [Sequence]
          # Initialize, populate and output a configuration Dictionary to be used throughout the project. 
          # Settings and constants are read from the local configuration file, and assets are fetched from Orchestrator. 
          # Asset values overwrite settings and constant values if they are defined with the same name.
          Log Message (Initialize All Settings) [LogMessage]
            Level = "Trace"
            Message = "Initializing settings..."
          Assing out_Config (initialization) [Assign]
            To = out_Config
            Value = New Dictionary(of String, Object)
          For each configuration sheet [ForEach]
            Values = in_ConfigSheets
            Body:
              Get local settings and constants [Sequence]
                # Read settings and constants from the configuration file and add them to the Config dictionary.
                var dt_SettingsAndConstants : sd:DataTable
                Read range (Settings and Constants sheets) [ReadRange]
                  AddHeaders = "True"
                  DataTable = Dt_SettingsAndConstants
                  SheetName = Sheet
                  WorkbookPath = in_ConfigFile
                For each configuration row [ForEachRow]
                  DataTable = Dt_SettingsAndConstants
                  Body:
                    If configuration row is not empty [If]
                      # Read non-empty rows in the sheet.
                      Condition = Not String.IsNullOrWhiteSpace(row("Name").ToString.Trim)
                      Then:
                        Add Config key/value pair [Assign]
                          To = out_Config(Row("Name").ToString.Trim)
                          Value = Row("Value")
          Try initializing assets [TryCatch]
            Try:
              Get Orchestrator assets [Sequence]
                # Get from Orchestrator the values of assets listed in the Assets sheet.
                var dt_Assets : sd:DataTable
                Read range (Assets sheet) [ReadRange]
                  AddHeaders = "True"
                  DataTable = dt_Assets
                  SheetName = "Assets"
                  WorkbookPath = in_ConfigFile
                For each asset row [ForEachRow]
                  DataTable = dt_Assets
                  Body:
                    Try retrieving asset from Orchestrator [TryCatch]
                      Try:
                        Get asset from Orchestrator [Sequence]
                          var AssetValue : x:Object
                          Get Orchestrator asset [GetRobotAsset]
                            AssetName = row("Asset").ToString
                            CacheStrategy = "None"
                            FolderPath = row("OrchestratorAssetFolder").ToString
                            Value = AssetValue
                          Assign asset value in Config [Assign]
                            To = out_Config(row("Name").ToString)
                            Value = AssetValue
                      Catches:
                        Catch
                          Body [Sequence]
                            If asset name is specified, but it cannot be retrieved [If]
                              # Logs a message and throw exception in case the asset is specified in the Config file, but it could not be loaded from Orchestrator.
                              Condition = Not String.IsNullOrWhiteSpace(Row("Name").ToString.Trim)
                              Then:
                                Throw AssetFailedToLoad Exception [Throw]
                                  Exception = new Exception("Loading asset " + Row("Asset").ToString + " failed: " + Exception.Message)
            Catches:
              Catch
                Rethrow loading asset exception [Rethrow]
    If in_OrchestratorQueueName is specified [If]
      # Overwrite queue name from in configuration file in case the argument in_OrchestratorQueueName is specified.
      # This provides backward compatibility with < 2018.3.
      Condition = Not String.IsNullOrWhiteSpace(in_OrchestratorQueueName)
      Then:
        Assign OrchestratorQueueName [Assign]
          To = Config("OrchestratorQueueName")
          Value = in_OrchestratorQueueName
    If in_OrchestratorQueueFolder is specified [If]
      # Overwrite folder name from in configuration file in case the argument in_OrchestratorQueueFolder is specified.
      # This provides backward compatibility with < 2018.3.
      Condition = Not String.IsNullOrWhiteSpace(in_OrchestratorQueueFolder)
      Then:
        Assign OrchestratorQueueFolder [Assign]
          To = Config("OrchestratorQueueFolder")
          Value = in_OrchestratorQueueFolder
    Invoke KillAllProcesses workflow (first run) [InvokeWorkflowFile]
      # Kills all Windows processes representing applications used in this business process to assure that the execution starts in a clean state.
      # Since the applications are assumed to be already closed, CloseAllApplications is skipped and just KillAllProcess is invoked.
      UnSafe = "False"
      invoke Framework/KillAllProcesses.xaml
      Workflow:
        Kill All Processes [Sequence]
          # Use the Kill Process activity to force the termination of the Windows processes representing applications used in the business process being automated.
          # Note that killing processes might have undesirable outcomes, such as losing unsaved changes to files.
          Log message (Kill processes) [LogMessage]
            Level = "Trace"
            Message = "Killing processes..."
    Add Log Fields (BusinessProcessName) [AddLogFields]
      # Add the process name to the logs generated after this point. 
      # This log field can be used to create reports and visualizations about the process.
      Fields = Config("logF_BusinessProcessName").ToString
</activity>
<variables-in-scope>
- Config : scg:Dictionary(x:String, x:Object)  (declared in "General Business Process")
- dt_Assets : sd:DataTable  (declared in "Get Orchestrator assets")
- AssetValue : x:Object  (declared in "Get asset from Orchestrator")
</variables-in-scope>
<workflow-arguments-used>
- In in_OrchestratorQueueName : x:String
- In in_OrchestratorQueueFolder : x:String
</workflow-arguments-used>
<invoked-workflows>
- Framework/InitAllSettings.xaml
- Framework/KillAllProcesses.xaml
</invoked-workflows>
</workflow-fragment>