Skip to content

[VsIntegration] CPS project system for SDK-style X# projects - #2094

Merged
RobertvanderHulst merged 61 commits into
X-Sharp:TestCPSfrom
hpetriffer:feature/cps-project-system
Sep 29, 2026
Merged

RobertvanderHulst merged 61 commits into
X-Sharp:TestCPSfrom
hpetriffer:feature/cps-project-system

Conversation

@hpetriffer

Copy link
Copy Markdown
Contributor

What changed

SDK-style X# projects (<Project Sdk="…">) are now loaded by a new project system based on the Visual Studio Common Project System (CPS), the project system Visual Studio uses for SDK-style C#, VB and F# projects. Legacy X# projects stay on the classic MPFproj-based project system. Both run side by side: a project selector decides per project.

Documentation: src/VisualStudio/ProjectSystemCPS/README.md describes the whole thing: features, supported Visual Studio versions, installation requirements, how it works, source layout, building, testing, troubleshooting and known limitations.

  • New XSharp.ProjectSystemCPS (src/VisualStudio/ProjectSystemCPS, shipped in the ProjectPackage2022 VSIX):
    • the CPS project type, the project selector (SDK-style → CPS, everything else → MPFproj, registered for both project type GUIDs), and the global property XSharpCpsProjectSystem;
    • XSharpProjectAdapter, which feeds the unchanged X# code model (XProject) from CPS subscriptions and design-time builds instead of the MPFproj hierarchy and the response file, so IntelliSense works without a prior build;
    • squiggles for build errors, the Task List, X# icons, property pages (including a fix for "Conditional compilation symbols", which lost DEBUG/TRACE), and the VO designers through the adapter;
    • the shadow WinForms designer, moved from the MPFproj SDK path and made project-system independent, with a number of fixes.
  • MSBuild support files (XSharpBuildTask): XSharp.DesignTime.targets, a gated import in XSharp.CurrentVersion.targets/XSharp.CrossTargeting.targets (only when XSharpCpsProjectSystem=true), XSharp.SDK.Props, and the XAML rules in Rules (items schema, design-time data, property pages).
  • MPFproj: the SDK path is removed (ProjectPackage/NodesSDK, XSharpSdkProjectNode, the MPFproj Publish/Pack and framework-menu commands, IsSdkProject). MPFproj rejects an SDK-style project with a clear message if it ever gets one.
  • Also affects MPFproj / dev behaviour (found during the tests):
    • the CodeDOM generator wrote static field references on parsed types with : (AutoScaleMode:Font, compiler error XS9114);
    • "Add .designer file" wrote the form file in lower case for forms without a #region, and now also works for CPS projects.

Why

The MPFproj fork is a hand-written IVsHierarchy that has to reimplement everything Visual Studio offers for SDK-style projects (Dependencies tree, NuGet, launch profiles, the new properties editor, Publish/Pack, multi-targeting). CPS provides all of that; X# only has to feed its code model from it. The code model and the language service are not changed.

Installation requirements

  • The VSIX and the X# MSBuild support files must come from the same build. The X# setup has to ship the changed XSharpBuildTask targets and the Rules folder (XSharp.Build.csproj copies the rules to its output). The installer is not part of this repository.
  • With older support files (no CPS import), the selector keeps SDK-style projects away from CPS and MPFproj shows "… Please run the X# setup program again."; legacy projects are not affected. Command-line builds and MPFproj projects are unchanged, because the design-time import is gated on XSharpCpsProjectSystem.

Testing

Tested in the Visual Studio 2022 experimental instance and in Visual Studio 2026 (18.10), with the test bed in src/VisualStudio/ProjectSystemCPS.TestBed (StartExp.cmd, SelectorTestBed.sln: SDK console, legacy, WinForms and VO projects):

  • project selection (SDK → CPS, legacy → MPFproj, also after Visual Studio rewrote the .sln GUIDs);
  • IntelliSense on a never-built project with a fresh X# database; completion without a .sln;
  • build, squiggles from build errors, the Task List, the property pages and their persistence (including conditional compilation symbols);
  • Publish and Pack, project references (binlog: the global property does not reach referenced projects), multi-targeting and launch profiles;
  • all four VO designers (window, menu, DBServer, FieldSpec);
  • the shadow designer (open, save, Add New Item, "Add .designer file", waiting for a NuGet restore and the build prompt).

Notes for reviewers

  • The commits are small and one per change; each commit message explains the reason and how it was tested.
  • Visual Studio 2019: ProjectPackage.csproj (VS 2019) could not be built on my machine (the Debugger project misses Dkm types, unrelated to this PR). Some shared files changed (CommandAddDesignerFile.cs, VSXsharpCodeDomProvider.cs, XSharpFileNode.cs); please let the CI confirm the VS 2019 build.
  • GAC: the CodeDOM generator fix only becomes effective in Visual Studio with a matching X# installation, because XSharp.CodeDomProvider is loaded from the GAC.
  • ProjectSystemCPS only uses the public CPS SDK, no private assembly of the managed project system, so the VSIX is not tied to one Visual Studio build.
  • Known limitations and open issues are listed in the README (section 9), for example: IntelliSense of multi-target projects uses the first target framework; the "Include files" folder does not exist for CPS projects; the shadow designer drops Dispose from a .designer.prg when saving (the same logic existed before for MPFproj SDK projects).
  • Not part of this PR: a separate fix for the code model view ProjectExtensionMethods (no such table: m).

🤖 Generated with Claude Code

hpetriffer and others added 30 commits September 26, 2026 17:37
…WP-1 skeleton

First step of the MPFproj -> CPS migration (WP-1: project type registration & skeleton).

- New SDK-style project src/VisualStudio/ProjectSystemCPS (net48, XSharp.ProjectSystemCPS.dll),
  references only XSharpCodeModelXs (never ProjectBase/ProjectPackage). Part of
  VSIntegration2022.sln and Master.slnx.
- XSharpProjectSystemPackage registers a CPS project type for .xsproj with the reserved
  guidCpsProjectType {AB494DCE-...}, template language "XSharpCps" and the initial capability
  "XSharpCps". Only compiled with XSHARPCPS (Debug), so the Release VSIX does not register it
  and MPFproj stays the default project system (side by side via the project type GUID).
- XSharpCpsGlobalPropertiesProvider sets XSharpCpsProjectSystem=true for projects loaded by the
  CPS project type.
- X# MSBuild: XSharp.DesignTime.targets revived; it imports VS' Microsoft.Managed.DesignTime.targets
  (managed project system: Dependencies tree, PackageReference, launch profiles, property pages)
  and removes the LanguageService/ReferencesFolder capabilities (no Roslyn workspace for X#).
  It is only imported when XSharpCpsProjectSystem is true, so MPFproj and command line builds
  are unchanged. New Rules/ProjectItemsSchema.XSharp.xaml (.prg/.prgx/.xs -> Compile, headers -> None).
- ProjectPackage2022 ships XSharp.ProjectSystemCPS.dll + pkgdef in its VSIX.
- Test bed src/VisualStudio/ProjectSystemCPS.TestBed: SDK-style CpsTestBed.xsproj, CpsTestBed.sln
  with the CPS project type GUID, StartExp.cmd (starts the VS 2022 experimental instance with the
  repository X# MSBuild files, without changing the installed X#).

Verified from the command line: normal builds unchanged; with the CPS property the managed
capabilities and rules are present and the design-time build returns the compiler switches and
resolved references. Acceptance test in the VS experimental instance still pending.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…he code model

XSharpProjectAdapter (IProjectDynamicLoadComponent + IXSharpProject, one per UnconfiguredProject,
active configuration) creates the unchanged XProject and feeds it from CPS instead of MPFproj
hierarchy walking and .rsp parsing:
- source items (evaluation) -> XProject.AddFile/RemoveFile, ModelWalker.AddProject
- XSharpProjectProperties + EvaluatedProjectReference (evaluation) -> RootNamespace, output paths,
  NS, provisional dialect, X# project references (AddProjectReference/RemoveProjectReference)
- XSharpCompilerCommandLineArgs (design-time build, CompileDesignTime without running xsc)
  -> XParseOptions.FromVsValues/ResetParseOptions and RefreshReferences/ResolveReferences,
  so parse options and references are correct before the first real build.

XSharpCommandLine maps the Xsc switches to the FromVsValues format (as XSharpProjectOptions
does for MPFproj). IntellisenseErrorStore keeps the code model errors per file (no Error List yet).
If the X# solution model is not open yet, the adapter loads the X# project package by GUID.

New rules Rules/XSharpCompilerCommandLineArgs.xaml and Rules/XSharpProjectProperties.xaml
(Context ProjectSubscriptionService), registered in XSharp.DesignTime.targets.

Verified from the command line with the design-time output of a VO dialect project
(dialect, /ns, defines, include path, references). Acceptance test in VS pending.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…icons

- Initial capabilities of the CPS project type (ProjectTypeRegistration.Capabilities), modelled on
  the managed C# project type: XSharpCps; AppDesigner; HandlesOwnReload; OpenProjectFile;
  PreserveFormatting; ProjectConfigurationsDeclaredDimensions; .NET; UseProjectEvaluationCache
  (without LanguageService, CSharp, SharedImports and EditAndContinue).
- XSharp.DesignTime.targets adds ProjectPropertiesEditor (new property editor for the XAML
  property pages of WP-4) to the managed capability set.
- The managed project system only provides project icons for C#/VB/F# (internal
  IProjectImageProvider): XSharpProjectTreePropertiesProvider sets the X# project icon and the
  X# document icon for .prg/.prgx/.xs files via IProjectTreePropertiesProvider.
  New XSharp.ProjectSystemCPS.imagemanifest (images as WPF resources in the assembly),
  shipped as ImageManifest asset in the ProjectPackage2022 VSIX.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ates

- ProjectItemsSchema.XSharp.xaml maps .rc to NativeResource and the VO binaries
  (.xsfrm/.vnfrm/.xsdbs/.vndbs/.xsmnu/.vnmnu/.xsfs/.vnfs/.xssql/.xsrep) to VOBinary.
- NativeResource/VOBinary File and BrowseObject rules restored from 58cca0e^ and registered
  in XSharp.DesignTime.targets; fixed CustomTool/SubType data sources that still used ItemType None.
- AddItemTemplatesGuid, GeneratorsTypeGuid and CmdUIContextGuid now use the X# project factory
  GUID {AA6C8D78-...} instead of the C# values, so CPS projects get the X# item templates and
  single file generators that the X# project package already registers there.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Property pages for the new property editor (capability ProjectPropertiesEditor), restored
from 58cca0e^ and registered with Context Project in XSharp.DesignTime.targets:
- LanguagePage.XSharp.xaml (Language) and DialectPage.XSharp.xaml (Dialect)
- BuildPropertyPage.XSharp.xaml and ApplicationPropertyPage.XSharp.xaml extend the managed
  Build/Application pages (OverrideMode="Extend")
- ReferencesPage.XSharp.xaml (Global Usings)

Corrected against the property names read by the Xsc task and persisted by MPFproj:
Stddefs -> StandardDefs, OtherFlags -> CommandLineOption, UseShared -> UseSharedCompilation,
INS as bool; added the missing VO17 and FOX3 dialect options.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… List and Task List

MPFproj commands (ProjectPackage) with X# projects loaded by CPS, where XProject.ProjectNode is
the XSharpProjectAdapter instead of an XSharpProjectNode:
- CommandGenerateWinForm: hard cast replaced by a type check (would throw InvalidCastException)
- CommandAddDesignerFile: only visible for MPFproj projects (needs the MPFproj file node)
- CommandEditProjectFile: only visible for MPFproj projects (CPS has its own Edit Project File)
- new helper Commands.ProjectIsMpfProjectAsync()

ProjectSystemCPS replacements for the MPFproj ErrorListManager/TaskListManager:
- IntellisenseErrorList shows the code model errors of the project in the Error List
- CommentTaskList shows the comment tasks after project/file walks in the Task List
Both refresh coalesced on the UI thread.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…pter

The VO editor panes hold the IXSharpProject of the file's XProject, which is the
XSharpProjectAdapter for CPS projects, so the VO designers are served through the adapter.

The designers (XSharpVoEditors Functions.EnsureFileNodeExists/DeleteFile) write generated
files to disk and then call HasFileNode/AddFileNode/DeleteFileNode. The adapter now registers
and unregisters these files with the code model immediately instead of ignoring the calls;
in SDK-style projects the XSharp.SDK.Props globs include them (with DependentUpon), so the
project file does not change and CPS confirms the item with the next evaluation.
HasFileNode compares full paths.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ailable

X# CPS projects had no project properties UI: CPS only offers the project designer when at least
one IVsProjectDesignerPageProvider applies (VsProjectDesignerPageService.IsProjectDesignerSupported),
and the managed project system only has providers for C#, VB and F#.

- New XSharpProjectDesignerPageProvider ([AppliesTo("XSharpCps & AppDesigner")]). It lists no
  classic COM pages: with the ProjectPropertiesEditor capability the AppDesigner editor factory
  opens the new property editor, which shows the XAML rules (managed pages + X# pages).
- ProjectPropertiesEditor is now also an initial capability of the project type, so the new
  editor does not depend on the X# targets that declare it in XSharp.DesignTime.targets.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…d legacy projects

Two X# project systems side by side, like the legacy and SDK project systems of C#/VB/F#:
legacy .xsproj stay on MPFproj ({AA6C8D78-...}), SDK-style .xsproj are loaded by CPS
({AB494DCE-...}).

- XSharpProjectSelector (IVsProjectSelector, the reserved guidProjectSelectorString) is
  registered for the MPFproj project type and sends projects with <Project Sdk>, <Import Sdk>
  or <Sdk Name> to the CPS project type. Existing solution files keep their project type GUID.
  Unreadable project files and errors fall back to MPFproj.
- ProvideProjectSelectorAttribute writes Projects\{AA6C8D78}\ProjectSelector and
  ProjectSelectors\{selector}\Package; the package registers the selector with
  IVsRegisterProjectSelector during initialization and unregisters it on dispose.
- Tools > Options > X# > Project System: "Load SDK-style projects with the new project system
  (CPS)" (default on) switches the routing off without uninstalling anything.
- Still only registered with XSHARPCPS (Debug builds).
- Test bed: Legacy/LegacyTestBed.xsproj and SelectorTestBed.sln (both projects with the MPFproj
  GUID); StartExp.cmd takes the solution as optional parameter.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…S-only solutions

Found in the log of the first VS test: "XSharpProjectAdapter: X# solution model is not open,
no code model". XSolution.Open is called by the X# project package in OnBeforeOpenSolution.
For solutions with the MPFproj project type VS loads that package before the solution opens
(it provides the project factory); for the CPS project type it is only autoloaded later, misses
OnBeforeOpenSolution and does not see the solution yet while it is still opening, so the
database was never opened and the CPS project got no code model.

- XSharpProjectAdapter: after loading the X# project package, open the solution model for the
  solution file reported by IVsSolution.GetSolutionInfo, instead of waiting 10s and giving up.
- XSharpShellLink.OnAfterOpenSolution: open the solution model before XSolution.AfterOpen()
  when it is still closed (safety net for any late package load).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…st VS test results

Found in the experimental instance: the CPS code model got parse options and references from
the design-time build, but never any source files. LinkTo without rule names subscribes to an
empty rule set, so the SourceItemsRuleSource link delivered nothing. The source item rules are
dynamic (one per item type): link with SourceItemRuleNamesSource as the rule names block, as
dotnet/project-system does. Added a log line with the evaluated project properties.

Verified in VS (SelectorTestBed.sln): the selector loads CpsTestBed through CPS and
LegacyTestBed through MPFproj; the adapter opens the solution model, adds Program.prg, the
walker parses it, the design-time build delivers 58 options and 10 references; editing the
project file removes files live.

Test bed: CpsTestBed.xsproj excludes the Legacy subfolder from its globs (it compiled the
legacy project's Start.prg as well).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…experimental instance

The X# project icon was not shown in the experimental instance: its ImageLibrary.cache dated
from 2024 and did not contain XSharp.ProjectSystemCPS.imagemanifest, because the Debug build
deploys the VSIX without refreshing that cache. StartExp.cmd now deletes the cache of the
experimental instance before starting; VS rebuilds it (verified: the manifest is in the rebuilt
cache). Normal VSIX installations refresh the cache themselves.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…Release builds

The CPS project type, the project selector and the Tools > Options page were only registered
with XSHARPCPS (Debug builds). The define and the conditional code are removed, so the Release
VSIX registers them as well.

Safety net for the shipped product: the selector only sends SDK-style projects to CPS when the
installed X# MSBuild support files contain the CPS design-time import (XSharpCpsProjectSystem in
XSharp.CurrentVersion.targets) and the XAML rules (new XSharpMsBuildSupport; folder from
XSharpMsBuildDir, the registry or Program Files (x86)\XSharp\MsBuild, like
XSharp.BeforeCommon.Props). With an older X# installation SDK-style projects stay on MPFproj
instead of loading in CPS without rules. Verified: installed X# -> false, repository overlay
(StartExp.cmd) -> true.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…system

Prerequisite for removing the MPFproj SDK path (WP-8): the shadow designer (WinForms designer
for SDK-style X# projects via a hidden companion C# project) was built on the MPFproj SDK
project node, so SDK projects loaded by CPS had no WinForms designer.

- ShadowDesigner moved from ProjectPackage to ProjectSystemCPS (namespace
  XSharp.ProjectSystem.ShadowDesigner) and made project system independent:
  ShadowDesignerBridge.TryOpen/TryResolveCompanionPaths take the .prg path and the XProject
  instead of an XSharpFileNode; services from the global service provider instead of the MPFproj
  node/package; ShadowDesignerCleanup implements IVsSolutionEvents instead of deriving from the
  MPFproj SolutionListener; no Community Toolkit dependency. Public helpers IsCpsProject and
  HasDesignerFile.
- XSharpCodeDomHelper (BuildDesignerFileName, MergeCodeCompileUnit, ...) moved from
  ProjectPackage to the shared CodeDomProvider project, so both project systems can use it.
- CPS entry points: XSharpShadowDesignerDefaultActionCommand (double click / Enter) and
  XSharpShadowDesignerViewFormCommand (View Designer) open the shadow designer for a .prg with a
  matching .Designer.prg; otherwise CPS falls back to its default action.
- MPFproj keeps working: XSharpFileNode calls the new API; the Sync Designer Changes / Sync Event
  Handlers commands now work for SDK projects in MPFproj and in CPS.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ow designer

WinForms/WinFormsTestBed.xsproj (net8.0-windows, UseWindowsForms, Core dialect, from the
CoreWinFormApp template) with Form1.prg/Form1.designer.prg, added to SelectorTestBed.sln with the
classic X# project type GUID, so it is loaded by CPS through the project selector. Double click or
View Designer on Form1.prg must open the shadow WinForms designer. CpsTestBed.xsproj excludes the
WinForms subfolder from its globs.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…DomProvider

VS test: "Could not load type 'XSharp.CodeDom.XSharpCodeDomHelper' from assembly
'XSharp.CodeDomProvider, Version=3.0.2.0'". The X# installation puts XSharp.CodeDomProvider (and
XSharp.VSParser, XSharp.Evaluator) in the GAC with the same assembly version, and the GAC copy wins
over the one in the VSIX, so the class moved there in the shadow designer port was not found.

- XSharpCodeDomHelper back in ProjectPackage/CodeDomProvider; CodeDomProvider.csproj and the VS 2019
  ProjectPackage.csproj are unchanged compared to before the port again.
- ProjectSystemCPS links the same source file as an internal copy (define XSHARP_PROJECTSYSTEMCPS),
  so the shadow designer does not depend on a GAC'd assembly version.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… globs

VS test: the shadow designer opened the first time, the second time the WinForms designer
reported that Form1.Designer.cs "is not contained within a project that supports code". The
companion C# project ({Project}.ShadowDesigner) is generated next to the X# project folder, so the
X# project's own globs never see it -- but an SDK-style X# project in a parent folder does
(here CpsTestBed, which contains the WinForms test project). After the first open the generated
.cs files were None items of that X# project, VS used it as the owning hierarchy of
Form1.Designer.cs and the designer refused it.

XSharp.SDK.Props excludes **/*.ShadowDesigner/** from the default items of every X# SDK project
(before XSharpDefaultItemExcludes captures DefaultItemExcludes, so the X# specific globs skip it
too). Verified with a dummy companion folder: installed props -> None item, fixed props -> excluded.
StartExp.cmd copies XSharp.SDK.Props into the overlay.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…icons

VS test: X# forms showed the X# document icon in CPS projects. XSharpProjectTreePropertiesProvider
now mirrors XSharpFileNode (MPFproj): a .prg is a form/user control when its SubType says so, or
when it has a matching .Designer.prg and its class inherits from Form/UserControl (same inference
as the MPFproj SDK node, cached per file timestamp) -> KnownImageIds.WindowsForm / UserControl.
VO binaries get the MPFproj icons (FormInstance, Database, MainMenuControl, ValidationRule, Report).
The item path comes from the FullPath metadata (ItemName is only the file name).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…folder on close

VS test: after closing, the saved .sln still contained the "Shadow Designer (generated)"
Solution Folder. ShadowDesignerCleanup removed the companion projects in OnQueryCloseSolution,
but not the folder they were nested in (behaviour inherited from the MPFproj implementation).
It now also removes that folder when it is empty (IVsSolution.CloseSolutionElement, like the
companion projects), so the .sln stays unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… the CPS project type GUID too

When VS saves a solution it writes the GUID of the factory that loaded the
project, so an SDK project's .sln entry flips from {AA6C8D78} (MPFproj) to
{AB494DCE} (CPS). C# SDK projects flip the same way ({FAE04EC0} ->
{9A19103F}), and VS offers no way to keep the original GUID. Routing the CPS
GUID through the same selector means those entries still load with MPFproj
when the routing option is off, the project is not SDK-style, or the
installed X# MSBuild files are too old for CPS.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…up work

The first version never found the "Shadow Designer (generated)" folder:
solution folders are virtual projects, so GetProjectEnum needs
EPF_ALLPROJECTS rather than EPF_ALLINSOLUTION. Right after the companion
project is removed the folder can still list it as a child without a name
and without a nested project, so such children, and *.ShadowDesigner
projects, no longer count as content. Each step is logged.

Verified in the Exp instance: the folder is removed and is no longer in the
saved .sln.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…arsing the form

Opening a form shortly after the solution loaded failed with an
ArgumentNullException ("e") in CSharpCodeGenerator. The project's assembly
references were still queued (XProject.ResolveReferences runs at most every
15 seconds), so System.Windows.Forms.Form could not be resolved and the
parser dropped the right-hand side of assignments. TryOpen already forced
the queued references to load, but only after parsing; it now does so
before.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
SDK-style X# projects are loaded by the CPS project system
(XSharp.ProjectSystemCPS) since the project selector routes them there and
the shadow WinForms designer was ported. MPFproj keeps the legacy projects.

Removed from ProjectPackage (VS 2022 only; VS 2019 never had it):
- NodesSDK (XSharpSdkProjectNode, SDK reference/dependency/folder nodes)
- the debug target "Framework" menu (commandDebuggerFramework.cs), the
  Publish/Pack commands with PublishDialog, and the priority command target
  that intercepted VS's own Publish/Pack. That interception also hid or
  broke Publish/Pack for X# projects loaded by CPS.
- the SDK-only parts of the file node (shadow designer redirect), project
  node (SDK project reference completion), configuration provider and
  shell events, and the matching Menus.vsct/Menus.cs symbols.

The MPFproj factory now rejects an SDK-style project with a clear message
instead of creating the removed node. That only happens when the selector
cannot use CPS (X# MSBuild support files too old).

ProjectSystemCPS: the Tools > Options switch is gone, because MPFproj can no
longer load SDK-style projects. The SDK project file check moved to the
public SdkProjectFile class, which the MPFproj factory uses as well.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
After the removal of XSharpSdkProjectNode, ProjectNode.IsSdkProject was
always false. Removed the property and every branch that depended on it or on
the project file's Sdk attribute, in ProjectBase and ProjectPackage:
- ProjectFactory.CreateSdkProject (MPFproj rejects SDK-style projects in
  XSharpProjectFactory.CreateProject)
- target framework update, rename and file refresh special cases (ProjectNode,
  FileNode, ProjectElement), project reference guid handling
- XSharpFileNode: <Compile Remove> handling on include, designer inference
  from a .Designer.prg (the CPS tree provider does this now), MarkDirty on
  remove
- XSharpProjectNode reload/upgrade checks, CommandConvertXsRuntime visibility

The legacy code paths are unchanged. ProjectBase (VS 2019) builds.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…n32Manifest property names

The Application page extension declared "usenativeversion " and
"nowin32manifest  " (with trailing spaces) as property and persisted names.
That is not a valid MSBuild property name: the checkboxes always showed
unchecked and saving wrote nothing usable. Use the names that the Xsc task
reads and MPFproj writes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The Application page offered the C# choice between "Icon and manifest" and
"Resource file". X# gets its Win32 resources from the Win32Resource item
(compiled from the .rc files); the $(Win32Resource) property is never read.
Choosing "Resource file" made the managed interceptor remove ApplicationIcon
and ApplicationManifest and write a property the build ignores. Hide
ResourceSpecificationKind and Win32Resource; Icon and Manifest stay visible
because the interceptor still evaluates the kind to IconAndManifest.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
In MPFproj the build logger fills the ErrorListManager, and
GetIntellisenseErrors returns those build errors and warnings to
XSharpErrorColorizer, which draws the squiggles. Under CPS the build errors
only reached the VS Error List, and GetIntellisenseErrors stayed empty (the
code model's own AddIntellisenseError is not called anymore), so the editor
showed no squiggles at all.

BuildErrorLoggerProvider (IBuildLoggerProviderAsync) attaches an MSBuild
logger to real builds (Build/Rebuild/Clean, not design-time builds) and
hands the errors and warnings to the adapter. Each build of a configuration
replaces its previous errors; the store merges them with the code model
errors per file. They are not added to the Error List, VS shows them there.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
"Manage Implicit Global Usings" (ImplicitUsingsEditor) only works through
ImplicitUsingsValueProvider of the managed project system, which maps the
value to <Using> items and applies to CSharp projects only. For X# the
editor read and wrote a meaningless ImplicitUsingsEditor property. The
interceptor contract lives in the private
Microsoft.VisualStudio.ProjectSystem.Managed.dll, so an X# version would tie
the VSIX to one VS build. The "Implicit global usings" switch stays; <Using>
items are edited in the project file.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… the solution file is saved

The adapter only opened the X# solution model (database) when the .sln
existed on disk, and did not try again. A project opened without a solution
(devenv project.xsproj, File > Open > Project) or a new project lives in a
solution that VS writes only when it is saved, so these projects got no
code model and no IntelliSense. XSolution.Open only needs the folder and the
name, so open it for the (future) solution file, or for the project name
when VS reports no solution file. Also load the X# project package with
IVsShell7.LoadPackageAsync instead of blocking the UI thread.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…m to referenced projects

The CPS project type sets XSharpCpsProjectSystem as a global property, and
the MSBuild task calls for project references inherit global properties.
Referenced C# and legacy X# projects were evaluated and built a second time
with different global properties (overbuild, file locks), and referenced X#
projects imported the design-time targets in a normal build. Add it to
_GlobalPropertiesToRemoveFromProjectReferences (verified: a referenced
project now sees an empty value, before it saw 'true').

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
hpetriffer and others added 28 commits September 28, 2026 15:02
The companion's Form1.cs-equivalent stub always declared
": System.Windows.Forms.Form", while the generated .Designer.cs carries the
real base type. For a user control the two partial declarations named
different base classes (CS0263).

ShadowDesignerBridge.BuildStubCSharp now generates the stub with the same
CSharpCodeProvider, the same base type references and the same namespace
imports as the designer code, so both parts always agree. The stub is where
the designer puts new members (event handler stubs, see EventHandlerSync),
so it is only rewritten while it is still an empty generated stub
(CompanionProjectWriter.IsEmptyStub), e.g. one with an outdated base class.

Verified outside VS: a user control gives ": UserControl" with its using, a
stub with a handler is kept, old and new stub formats are recognized.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…loaded project

The companion project took its target framework only from <TargetFramework>
in the .xsproj XML, so multi-targeting projects (<TargetFrameworks>) and a
TargetFramework from Directory.Build.props made the designer fail.

The bridge now passes the active target framework of the loaded project
(VSHPROPID_TargetFrameworkMoniker of its hierarchy, converted to the short
form: net8.0, net48, netcoreapp3.1, ...). Without it the writer falls back to
the project file, now including the first entry of <TargetFrameworks>. The
"-windows" suffix is still appended as before.

Verified: moniker conversion for .NETCoreApp 8.0/3.1 and .NETFramework
4.8/4.7.2; the test bed companion gets net8.0-windows.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… a blocking build

When the package references of the X# project were not resolved yet, the
bridge built the project with EnvDTE BuildProject(WaitForBuildToFinish: true)
-- a nested message pump inside the async CPS command handler. Under CPS a
build does not even refresh the code model's references: they come from the
design-time build (XSharpProjectAdapter), which runs after the NuGet restore.

ShadowDesignerBridge.EnsureReferencesAsync (called by the CPS commands before
TryOpen) now first waits asynchronously for the IntelliSense stage of the
project load (IVsOperationProgressStatusService, up to 60 s) and briefly for
the adapter to process the result. Only when the references are still
missing it offers a build as before, which now runs through
IVsSolutionBuildManager2.StartSimpleUpdateProjectConfiguration and completes
through IVsUpdateSolutionEvents. A second double click during the wait is
swallowed. TryOpen loses its refreshReferences parameter (the MPFproj .rsp
re-read); the class docs no longer mention the removed MPFproj SDK caller.

Not tested in VS: the path only runs for a project with NuGet references
before its restore has finished.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ded companion project

When the companion project was already loaded (another form of the project
was opened before), the bridge wrote the new form's .cs/.Designer.cs into its
folder and opened the designer immediately. The companion includes its files
through the SDK globs, but it did not pick them up in time -- verified in VS,
not even after 10 s -- so the designer failed with "... is not contained
within a project that supports code" and only worked on a second attempt.

TryOpen is split into TryPrepareCompanion (parse, write, add to the solution)
and TryOpenAsync: missing files are added with ProjectItems.AddFromFile, then
it waits (up to 10 s) until IVsProject.IsDocumentInProject finds them, and only
then opens the designer. For files covered by a glob CPS writes no explicit
item into the companion .csproj (verified: the .csproj stays unchanged).

Tested in VS: open a user control (loads the companion), then Form1 -> the
designer opens on the first attempt.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… in the designer

The item template wizard opens the new .prg itself, with the default editor
for .prg (the X# code editor), so a new form or user control did not open in
the designer. MPFproj redirected this in XSharpFileNode, which was removed
with the MPFproj SDK path. CPS' own mechanism (IProjectSpecificEditorProvider
with IsDefaultEditor) is not usable: it routes every open of the file to the
project specific editor, also debugger and navigation opens
(LOGVIEWID_Debugging/TextView), which the shadow designer cannot serve.

New NewFormDesignerRedirect (IVsRunningDocTableEvents, advised when the first
X# CPS project loads): on the first window of a document of a CPS X# project
that belongs to a form .prg (a .Designer.prg exists) created within the last
30 s, it waits until the code model knows the file, opens the shadow designer
and, only when that succeeded, closes the code window. Each file is
redirected once per session, so a later View Code is not affected; Add
Existing Item opens no window. XSharpShadowDesignerCommands.TryOpenAsync gets
an overload without IProjectThreadingService for it.

Tested in VS: Add New Item > UserControl in the CPS WinForms project opens the
designer and closes the code editor (about 1.4 s); in the legacy (MPFproj)
project the MPFproj designer opens as before, no redirect.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…hread

The projects of a solution load in parallel, and the adapters created their
XProjects at the same time on background threads. That raced in the code
model: with a new X# database the lazily created OrphanedFiles project was
added twice and XDatabase.Read failed with SQLite "FOREIGN KEY constraint
failed" (seen in the VS log after deleting the .vs folder). MPFproj creates
its XProjects one after the other on the UI thread; the adapter now switches
to the UI thread before it creates the model as well.

Verified in VS with a fresh database: OrphanedFiles is added once, both
models are created on the UI thread, no SQLite error.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… is saved

The comment tasks (TODO etc.) of a CPS project only showed up after the next
project walk, e.g. after a design-time build, not when the file was saved.
MPFproj walks a changed file again in XSharpProjectNode.OnFileChanged
(WalkFile(file, notify: true)), whose FileWalkComplete event refreshes the
Task List; the CPS adapter had no counterpart.

New ProjectFileSaveWatcher (IVsRunningDocTableEvents, advised when the first
X# CPS project loads): after a save of a source file of an X# CPS project it
walks the file again on a background thread, so the adapter's
FileWalkComplete handler refreshes the Task List.

It also passes the Task List comment tokens (Tools > Options) to the code
model when nobody did yet: the X# project package only sets them when an
MPFproj project opens or after the options dialog, so a solution with only
CPS projects had no comment tasks at all.

Verified in VS: the TODO entry appears right after saving (the save walk
runs on a background thread); "4 comment tokens set" with a fresh database.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…findable at startup

The project and .prg icons of CPS projects were often empty. The image
manifest refers to its PNGs with pack URIs that name XSharp.ProjectSystemCPS
by its short name. The image library resolves them when it builds its cache
at startup, usually before a CPS project has loaded the assembly; no X#
package registered a binding path, so the lookup failed and the whole
manifest was missing from ImageLibrary.cache (no GUID, no images, while e.g.
the IntelliCode manifest was there). The icons only worked when a CPS
project happened to load the assembly first.

- [ProvideBindingPath] on XSharpProjectSystemPackage: the extension folder is
  probed for loads by name, the image library finds the assembly.
- [assembly: ProvideCodeBase(AssemblyName = "XSharp.ProjectSystemCPS")] next to
  the sibling assemblies in ProjectPackage/ExternalAssemblies.cs: loads with
  the full identity work too, e.g. when ProjectPackage2022 uses
  ShadowDesignerBridge before a CPS project has loaded the assembly.

Verified in VS: after StartExp (fresh cache) the cache contains the manifest
GUID and both images, the project and document icons show.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ign-time targets path

XSharp.DesignTime.targets imports $(XSharpManagedDesignTimeTargetsPath), but
the import gates in XSharp.CurrentVersion.targets and
XSharp.CrossTargeting.targets checked the hard-coded path of
Microsoft.Managed.DesignTime.targets. With the property overridden to a file
that does not exist, the gate passed and the project failed to load (MSB4019).
The property is now defined next to XSharpDesignTimeTargetsPath and the gate
checks it.

Verified from the command line: default -> design-time targets imported;
override to a missing file -> not imported, no error (before: MSB4019);
without XSharpCpsProjectSystem -> unchanged. Project loads in VS.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…iveResource and VOBinary rules

The File rules of the X# item types were copied from the managed None rule
without PropertyPagesHidden="true" and without the TargetPath property.
Without PropertyPagesHidden the file property dialog shows an extra, empty
page for .rc files and VO binaries. Both are added as in None.xaml.

Tested in VS: Test.rc shows its properties (Build Action Native Resource),
no empty extra page.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The X# code model treats .vnsqs as a VO SQL table and .vnrep as a VO report,
like .xssql and .xsrep (FileTypeHelpers), and the icon provider already maps
them, but ProjectItemsSchema.XSharp.xaml did not: such files got no X# item
type when added to a CPS project.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The MPFproj Build page has "Suppress Resource Compiler warnings"
(SuppressRCWarnings, passed to the NativeResourceCompiler task, default true
in XSharp.props); the CPS Build page had no rule for it. Added as a bool
property in the "Errors and warnings" category with the MPFproj texts.

Tested in VS: the checkbox shows ticked by default, unticking writes the
property to the project file.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ng code model I/O

The adapter's single lock protected both its file/reference sets and the
calls into the code model. XProject.AddFile/RemoveFile do database I/O and
ResolveReferences loads the referenced assemblies, so HasFileNode, which the
VO designers call on the UI thread, could wait for that I/O.

Two locks now, always taken in the same order: modelGate serializes the
changes of the code model (the three subscriptions, AddFileNode/DeleteFileNode,
load/unload) as before; gate only protects the file set and the model field,
briefly, and HasFileNode only takes gate. ResolveReferences runs outside both
locks: XProject guards it itself (_resolvingReferences), and the ModelWalker
and the type lookups call it without these locks as well.

Tested in VS: projects load, design-time builds apply, files added through
Add New Item reach the code model, completion works.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ee properties provider

XSharpProjectTreePropertiesProvider runs synchronously on the CPS tree thread
for every node on every tree update. It called File.Exists for every .prg
(is there a .Designer.prg?), read form files completely (File.ReadAllText) to
infer Form/UserControl from the base class, and its cache grew without limit.

- The designer file check uses a listing of the *.Designer.prg files per
  folder, reused for 250 ms and read again when the folder's timestamp
  changes (on NTFS: a file was created, deleted or renamed). 250 ms covers the
  burst of one tree update; longer could miss a .Designer.prg created by Add
  New Item. ShadowDesignerBridge.HasDesignerFile stays uncached (the commands
  and NewFormDesignerRedirect need the current state).
- The base class check reads the file in 4 KB blocks only until the first
  CLASS ... INHERIT declaration, at most 64 KB.
- Both caches are cleared when they exceed 1000 entries.

Verified outside VS (reflection): Form1.prg -> Form, a UserControl whose
declaration follows after ~6 KB -> UserControl, a new .Designer.prg is found
after 0.3 s. Tested in VS: project, document, form and user control icons,
also for a user control added with Add New Item.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…rs on every Add

IntellisenseErrorStore built the complete error list of the project on every
Add and handed it to IntellisenseErrorList, which only applies the last one
per (coalesced) UI refresh. The store now only reports the change; the Error
List fetches the errors with IntellisenseErrorStore.GetAll once per refresh
(after resetting its scheduled flag, so a later change schedules the next one).

The code model does not report intellisense errors at the moment (see the
CPS migration spec, WP-6), so this matters once it does again.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
New VO\VOTestBed.xsproj in SelectorTestBed.sln (classic X# project type GUID,
the project selector sends it to CPS), made from the VO SDI Application
template (ProjectPackage/Templates/Projects/Windows/VOSdiApp): a VO window
(Help About.HELPABOUT.xsfrm), two menus (SDI Menus.*.xsmnu), their .prg/.rc
files, the VO designer templates in Properties\ and the resources.
Differences from the template: SDK-style (net48, x86, VO dialect and the
template's compiler options), no AssemblyInfo.prg (the SDK generates the
attributes), no explicit items (the X# SDK globs add .prg/.rc/VO binaries with
DependentUpon), and the X# runtime and VO SDK assemblies referenced with a
HintPath into the X# installation (XSharpPath from the registry).

CpsTestBed.xsproj keeps VO\** out of its globs, including the NativeResource
and VOBinary items. StartExp.cmd describes the test projects.

Verified: builds from the command line; in VS the selector loads it with CPS,
the code model gets all 23 files, the VO window editor opens the window and
saving regenerates the .xsfrm and .rc without changing the project file.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…disk

Under CPS nobody re-read a source file that changed on disk outside the VS
editor. The VO designers write the generated .prg directly to disk when it is
not open in an editor (menu editor: SDI Menus.prg with the new menu IDs,
window editor: Help About.prg with the new control), and the code model kept
the old types until the next project walk (found in the VS test with
VO/VOTestBed). MPFproj covers this in XSharpProjectNode.OnFileChanged
(WalkFile(file, notify: true)).

New SourceFileWatcher (one per project, created by the adapter): a
FileSystemWatcher on the project folder including subfolders. Changes to
source files of the project (adapter: in the file set and XFile.IsSource) are
collected and walked after 500 ms, one walk per file for a burst of writes;
notify: true refreshes the Task List. After a buffer overflow the whole
project is walked again. Files outside the project folder (links) are not
watched.

The watcher also sees saves from the VS editor, so the editor save walk of
ProjectFileSaveWatcher (IVsRunningDocTableEvents.OnAfterSave, 1803b79) is
removed to avoid a second walk per save. What remains of that file, setting
the comment tokens for pure CPS solutions, is now CommentTokens.EnsureSet.

Verified outside VS: 5 quick writes -> one callback 500 ms after the last,
temp file + rename (editor save) -> callback, non-source file -> none, none
after Dispose. Tested in VS: menu editor and window editor saves with the .prg
closed -> "changed on disk, walking it again" 0.5 s later, new menu item and
control in the code model and in completion; TODO saved in the editor ->
Task List entry.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ners

VO\VOTestBed gets a DBServer (Customer.prg + Customer.Customer.xsdbs, class
Customer on Customer.dbf) and FieldSpecs (Fieldspecs.prg +
Fieldspecs.FieldSpecs.xsfs), created from the X# item templates VODBServer and
VOFieldSpec (ProjectPackage/Templates/ProjectItems/VO) with
$safeitemrootname$ replaced; Fieldspecs.prg is the template's empty stub,
the FieldSpec editor fills it. The X# SDK globs add the VO binaries as
VOBinary with DependentUpon.

Tested in VS: the FieldSpec editor regenerates Fieldspecs.prg, the DBServer
editor regenerates Customer.prg and creates Customer.FieldSpecs.xsfs (added to
the code model through AddFileNode and the glob); SourceFileWatcher walks
the .prg files 0.5 s after the save; the generated code compiles; the project
file stays unchanged. The committed files are the template state.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
GenerateFieldReferenceExpression used the static selector only when the
target was exactly a CodeTypeReferenceExpression. The X# CodeDOM parser
creates the subclass XCodeTypeReferenceExpression, so code that was parsed
and generated again got a colon: "Add .designer file" wrote
"System.Windows.Forms.AutoScaleMode:Font", which the compiler rejects
(XS9114) and the shadow designer cannot convert. GeneratePropertyReference-
Expression already tested with "is"; now both do.

Checked outside VS with the dev build (DEVPATH, the GAC copy of 3.0.2
still writes the colon): an XCodeTypeReferenceExpression target gives
"AutoScaleMode.Font", SELF:button1 keeps the colon.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The tree properties provider found the base class of a form with
"CLASS name INHERIT base" on one line. The X# CodeDOM generator writes the
declaration with a line continuation ("CLASS Form1 ;" and "INHERIT ..." on
the next line), so a form lost its icon as soon as the generator wrote its
main file: "Add .designer file", or the shadow designer adding an event
handler. The regex now allows the continuation.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ner file is added

CPS calls the tree properties providers only for the nodes that changed in
a tree update. "Add .designer file" adds a .Designer.prg below an existing
.prg: that adds a child node but leaves the node of the .prg unchanged, so
its form icon only appeared after the project was loaded again. When the
list of properties providers changes, CPS calculates the properties of all
nodes again (PhysicalProjectTreeProvider.OnProjectTreePropertiesProviders-
Changed, providers compared by instance).

New XSharpProjectTreePropertiesProviderSource (IProjectTreePropertiesProvider-
DataSource, the pattern of the managed project system's TreeItemOrder-
PropertyProviderSource) supplies the provider, which is no longer a MEF
export itself. It follows the source items and publishes a new provider
only when a .Designer.prg was added or removed.

Its values carry their own version, not the versions of the source items
subscription: the tree input synchronizes its sources by their data source
versions, and with the source item versions the tree was never published
and VS hung while restoring the open documents (seen in the experimental
instance, stacks read with cdb). The first provider is published right
away.

Tested in VS: the icon changes right after "Add .designer file" and after
deleting the designer file; the solution loads normally.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The command was hidden for CPS projects: it generated the designer file
from the MPFproj file node (XSharpFileNode) and cast the project node to
XSharpProjectNode.

- Visible for .prg files of X# projects only (before, the MPFproj check
  also kept it away from C# forms). SDK-style projects rarely have a
  SubType, so for CPS projects the base classes of the first class in the
  file are followed through the code model, the same rule as
  XSharpFileNode.DetermineSubType (TypeNameToSubtype is now internal).
  Also hidden when a .designer.prg exists next to the file without being
  nested below it; the command would have overwritten it.
- VSXSharpCodeDomProvider has a second constructor with the code model
  project and the file path; without a file node it writes into an open
  editor buffer by path. The CPS project system needs no AddFileNode: the
  SDK globs include the new file and XSharp.SDK.Props nests it.
- The form is parsed first; the files are only created when the form class
  with InitializeComponent was found. Right after the solution was opened
  the references are not loaded yet and the parser cannot recognize it
  (the command left an empty designer file behind and failed silently).
  Now a message says to try again later. Exceptions are shown instead of
  only going to the activity log.

Tested in VS with a single-file form in the WinForms test project: the
designer file is created and nested, the form keeps its icon, the designer
opens it (after correcting "AutoScaleMode:Font", written by the GAC copy
of the CodeDOM generator without 5ec34de), and the project builds.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…er case

The generated form source was lowered for the "#endregion without #region"
check and only restored when that check applied. For a form without a
#region the whole form file was written back in lower case. Only the check
is case insensitive now. The bug is also on dev.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…n the blocked UI thread

CPS waits synchronously on the UI thread for the task of a command handler
(ProjectNode.ExecCommand), without pumping messages. When a form was opened
while the package references were still missing, EnsureReferencesAsync
waited for the project load inside that wait: the NuGet restore and the
design-time build after it could not finish, the wait gave up after 3 s
(the IntelliSense stage was already complete, the first design-time build
had run without the packages), the build prompt came, and after OK VS hung
for good (seen in the experimental instance, stacks read with cdb).

- Double click / Enter and View Designer report the command as handled
  right away when package references are missing, and open the designer in
  the background. When it cannot be opened, the form opens in the code
  editor, the default action CPS would have taken. With the references
  present nothing changes.
- After the load stage the references are awaited for up to 20 s instead
  of 3 s, with a status bar message.

Tested in VS with a WebView2 PackageReference restored from a local feed:
double click right after the solution opened -> no prompt, the designer
opened 1.4 s later, after the design-time build with the packages; with a
failing restore -> VS stays responsive, prompt after the wait, the build
runs, the designer opens.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…nces after a build

After the build offered by EnsureReferencesAsync, the references were
awaited for the same 20 s as during the project load. A build restores, and
the design-time build with the references follows right after it (0.2 s in
VS), so 3 s are enough. Also for a failed build: it can have restored and
failed on compile errors, then the references still come; when the restore
failed, the Designer used to open only after the full 20 s.

Tested in VS with a restore that fails (local feed renamed): prompt, OK,
the build fails, the Designer opens 3.8 s later (before: 21 s).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…stem

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…eep DEBUG and TRACE

The "Conditional compilation symbols" field of the managed Build page edits
DefineConstants with a MultiStringSelector, whose value is a list of
name/value pairs. For C# the managed DefineConstantsValueProvider
(persistence ProjectFileWithInterception, AppliesTo CSharp | FSharp)
converts it. For X# nothing did: adding MYSYM wrote
<DefineConstants>MYSYM=False</DefineConstants> into the project file, the
implicit DEBUG and TRACE were lost and MYSYM was not defined either
(verified in VS).

That value provider cannot be used for X#: its interfaces are in
Microsoft.VisualStudio.ProjectSystem.Managed.dll, which has no usable
package and a version per VS release (the part would be rejected on older
VS). So:
- BuildPropertyPage.XSharp.xaml defines DefineConstants like the managed
  page, with the persistence "XSharpDefineConstants".
- XSharpDefineConstantsPropertiesProvider (public CPS API only) wraps the
  project file provider and converts DefineConstants: the list shows the
  symbols of the project file after "$(DefineConstants);" (a value without
  the prefix is shown as a whole), a change is written as
  "$(DefineConstants);SYMBOL;...", an empty list deletes the property.
  Exported named and unnamed: the property pages import the unnamed
  contract and select by the "Name" metadata.
- KeyValuePairListEncoding: the editors' list format, internal in the
  managed project system.

Tested in VS: MYSYM added for Debug -> "$(DefineConstants);MYSYM", the
program reports DEBUG, TRACE and MYSYM; the page shows MYSYM again after
reopening; removing it deletes the property.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
README.md in src/VisualStudio/ProjectSystemCPS: what the CPS project system
for SDK-style X# projects offers, the supported Visual Studio versions, the
installation (VSIX plus matching X# MSBuild support files and rules), how it
works (project selection, capabilities, MSBuild integration, feeding the
code model, errors and Task List, property pages, icons, VO designers,
shadow WinForms designer, commands, multi-targeting), the source layout,
building, testing and debugging, troubleshooting and the known limitations.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@RobertvanderHulst
RobertvanderHulst changed the base branch from dev to TestCPS September 29, 2026 14:33
@RobertvanderHulst
RobertvanderHulst merged commit 243efc6 into X-Sharp:TestCPS Sep 29, 2026
1 check failed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants