Is your feature request related to a problem? Please describe.
XamlProjectResolver.FindOwningProject (server/src/WinUiXaml.Workspace/XamlProjectResolver.cs) walks upward from a XAML file looking for a directory containing exactly one .csproj. It returns a bare null in several distinct situations:
- the directory contains two or more
.csproj files (ambiguous — the walk aborts immediately, it does not continue to an unambiguous ancestor, lines 68-71)
- no
.csproj is found anywhere up to the boundary — e.g. XAML linked in from a shared folder that lives outside any project
- the document falls outside every
allowedRoot
All of these collapse into the same null. ResolveAsync and ResolveFrameworkAsync both just return null, so the document is served project-less: the tolerant parser, syntax diagnostics and TextMate coloring still work, but there is no compilation — no type-aware completion, no x:Bind resolution, no hover types, no F12 into code-behind.
The user gets no indication of why, and no way to correct it. FindOwningProjectTests.MultipleProjectsInDirectory_ReturnsNullWhenAmbiguous and NoProject_ReturnsNull assert the identical observable outcome, which confirms the two states are indistinguishable to callers.
There is currently no setting anywhere in the extension or server for pinning a project.
Describe the solution you'd like
Two changes, neither of which requires MSBuild evaluation:
1. Distinguish the failure reason. Return a reason alongside the result (or add TryFindOwningProject(out var reason)) covering at least Found, Ambiguous, NoProjectFound, and OutsideAllowedRoot. Surface it in the server log and in whatever project-status affordance the client presents, so an ambiguous directory reads as "two projects here, pick one" rather than silence.
2. Let the user pin a project. A workspace-folder-scoped setting (e.g. winui-xaml.projectPath) and/or a WinUI: Select XAML Project quick-pick. This one mechanism addresses ambiguity, linked/shared XAML, and unusual layouts together — which matters, because ambiguity is likely the least common cause of a null resolution.
Optional third step — a default instead of giving up. When candidates are ambiguous, prefer the one whose TargetFramework matches net*-windows10.0.* (the WinUI head, almost certainly the one whose IntelliSense is wanted), falling back to alphabetical order. TargetFramework is normally a literal property, so this is an XML read rather than a design-time build.
Additional context
Why content-based disambiguation is not the answer. The instinct is to ask which candidate actually includes the XAML as a Page/ApplicationDefinition item. But in the realistic ambiguous scenario — two heads over one shared source tree — both are SDK-style projects whose default globs pick up **/*.xaml, so both genuinely include the file. There is no owner to discover, only a preference to record. Content-based disambiguation would cost an MSBuild evaluation per candidate and frequently return "both."
Likelihood. Multiple .csproj in one folder is uncommon for WinUI: no WinUI template produces it, and the usual app + Windows Application Packaging Project layout is App.csproj + App.wapproj, which is unaffected because the glob is *.csproj only. It shows up mainly in UWP → WinUI 3 side-by-side migrations. This is a judgment call, not a telemetry-backed measurement.
Related invalidation gap (needs verification before acting). FindOwningProject is also used for cache invalidation at server/src/WinUiXaml.LanguageServer/XamlLanguageServer.cs:558, guarded by if (owning != null). A .cs edit inside a multi-project directory therefore invalidates nothing. That is harmless for a project that was never loaded, but if such a project is a ProjectReference of a loaded app project, edits to its sources may not invalidate the app's cached workspace. There is no test covering this path, and Invalidate does have a ContainsProject check for referenced projects that should be traced before treating it as a bug. Adding an ambiguity tie-break would incidentally close this gap for those directories.
Found while reviewing the XAML language service integration in #50.
Is your feature request related to a problem? Please describe.
XamlProjectResolver.FindOwningProject(server/src/WinUiXaml.Workspace/XamlProjectResolver.cs) walks upward from a XAML file looking for a directory containing exactly one.csproj. It returns a barenullin several distinct situations:.csprojfiles (ambiguous — the walk aborts immediately, it does not continue to an unambiguous ancestor, lines 68-71).csprojis found anywhere up to the boundary — e.g. XAML linked in from a shared folder that lives outside any projectallowedRootAll of these collapse into the same
null.ResolveAsyncandResolveFrameworkAsyncboth justreturn null, so the document is served project-less: the tolerant parser, syntax diagnostics and TextMate coloring still work, but there is no compilation — no type-aware completion, nox:Bindresolution, no hover types, no F12 into code-behind.The user gets no indication of why, and no way to correct it.
FindOwningProjectTests.MultipleProjectsInDirectory_ReturnsNullWhenAmbiguousandNoProject_ReturnsNullassert the identical observable outcome, which confirms the two states are indistinguishable to callers.There is currently no setting anywhere in the extension or server for pinning a project.
Describe the solution you'd like
Two changes, neither of which requires MSBuild evaluation:
1. Distinguish the failure reason. Return a reason alongside the result (or add
TryFindOwningProject(out var reason)) covering at leastFound,Ambiguous,NoProjectFound, andOutsideAllowedRoot. Surface it in the server log and in whatever project-status affordance the client presents, so an ambiguous directory reads as "two projects here, pick one" rather than silence.2. Let the user pin a project. A workspace-folder-scoped setting (e.g.
winui-xaml.projectPath) and/or aWinUI: Select XAML Projectquick-pick. This one mechanism addresses ambiguity, linked/shared XAML, and unusual layouts together — which matters, because ambiguity is likely the least common cause of a null resolution.Optional third step — a default instead of giving up. When candidates are ambiguous, prefer the one whose
TargetFrameworkmatchesnet*-windows10.0.*(the WinUI head, almost certainly the one whose IntelliSense is wanted), falling back to alphabetical order.TargetFrameworkis normally a literal property, so this is an XML read rather than a design-time build.Additional context
Why content-based disambiguation is not the answer. The instinct is to ask which candidate actually includes the XAML as a
Page/ApplicationDefinitionitem. But in the realistic ambiguous scenario — two heads over one shared source tree — both are SDK-style projects whose default globs pick up**/*.xaml, so both genuinely include the file. There is no owner to discover, only a preference to record. Content-based disambiguation would cost an MSBuild evaluation per candidate and frequently return "both."Likelihood. Multiple
.csprojin one folder is uncommon for WinUI: no WinUI template produces it, and the usual app + Windows Application Packaging Project layout isApp.csproj+App.wapproj, which is unaffected because the glob is*.csprojonly. It shows up mainly in UWP → WinUI 3 side-by-side migrations. This is a judgment call, not a telemetry-backed measurement.Related invalidation gap (needs verification before acting).
FindOwningProjectis also used for cache invalidation atserver/src/WinUiXaml.LanguageServer/XamlLanguageServer.cs:558, guarded byif (owning != null). A.csedit inside a multi-project directory therefore invalidates nothing. That is harmless for a project that was never loaded, but if such a project is aProjectReferenceof a loaded app project, edits to its sources may not invalidate the app's cached workspace. There is no test covering this path, andInvalidatedoes have aContainsProjectcheck for referenced projects that should be traced before treating it as a bug. Adding an ambiguity tie-break would incidentally close this gap for those directories.Found while reviewing the XAML language service integration in #50.