Avalonia exception "Unable to find view for <class name>" - c#

I have a VS solution with the following projects so that I can share UI code between iOS and Windows:
MyApp.UI.Avalonia - a .NET Standard Class Library with Avalonia nuget package
contains XAML/CS files for UI
MyApp.iOS - a Xamarin iOS project, with Avalonia and Avalonia.iOS nuget packages
Depends on
MyApp.Windows - a Windows Application project created from the Avalonia project template (with XAML files deleted)
When I run the Windows application, I get an exception in my App class at the call to AvaloniaXamlLoader.Load(this): System.IO.FileNotFoundException: 'Unable to find view for MyApp.App
It looks like it is failing when trying to find App.xaml, the corresponding XAML file to the App.cs file. It does so by looking for resource with URL something like "avares:/!AvaloniaResourceXamlInfo". When I debug this process in the Avalonia solution's ControlCatalog project, it does find a resource by this name in the shared ControlCatalog class library assembly, and inside that resource it finds all of the XAML files and Assets.
A difference I notice between my project and theirs is that when I right click the project and select Add -> Item -> User Control (Avalonia), it creates a XAML file wrapping a CS file in their project, but in my project it creates the two files merely side-by-side. What project setup am I missing to get the XAML files into this magical "!AvaloniaResourceXamlInfo" resource?
Update:
While I still get the same error, I was able to get the xaml.cs files to encapsulate the corresponding .cs files (so apparently that isn't the only issue) by adding the following to my .csproj file manually (which I found in the ControlCatalog sample project):
<ItemGroup>
<Compile Update="**\*.xaml.cs">
<DependentUpon>%(Filename)</DependentUpon>
</Compile>
<AvaloniaResource Include="**\*.xaml">
<SubType>Designer</SubType>
</AvaloniaResource>
<AvaloniaResource Include="Assets\*" />
<AvaloniaResource Include="Assets\Fonts\*" />
</ItemGroup>

Have you tried changing the property of the file?

Make sure to align Namespaces with paths in this project.
Avalonia seems to be a bit picky about it.
Despite .Net allows Namespaces and paths to be something different

The project ran without error once I manually added the following to the .csproj file of the .NET Standard library project shared by the Windows and iOS application projects:
<ItemGroup>
<Compile Update="**\*.xaml.cs">
<DependentUpon>%(Filename)</DependentUpon>
</Compile>
<EmbeddedResource Include="**\*.xaml">
<SubType>Designer</SubType>
</EmbeddedResource>
<AvaloniaResource Include="**\*.xaml">
<SubType>Designer</SubType>
</AvaloniaResource>
<AvaloniaResource Include="Assets\*" />
<AvaloniaResource Include="Assets\Fonts\*" />
</ItemGroup>
Looks like that <Compile ... tag encapsulates the cs filese into the xaml.cs files, and the rest embeds the xaml files as resources which can be found by Avalonia.

Related

Why is VS2019 still copying embedded resources to the output folder?

When i try to embed resources in a .NET Core Webservice project via EmbeddedResource in the .csproj file, these resources are also copied into the output folder, although i choose the option to NOT copy in the build action dropdown-menu.
The part where the resource is embedded looks like this:
<ItemGroup>
<EmbeddedResource Include="Resources\logging.json" />
</ItemGroup>
In another .NET Core project, which is a library, the resource gets embedded and won't be copied to the output directory.
There, the snippet looks like this:
<ItemGroup>
<EmbeddedResource Include="LicenseText\*.txt" />
</ItemGroup>
Is there an explanation to this behaviour?
I can reproduce your issue on my side. I checked the official document about EmbeddedResource item, and the metadata introduced like this
CopyToOutputDirectory Optional string. Determines whether to copy the file to the output directory. Values are: 1. Never. 2. Always. 3. PreserveNewest.
I tested by adding related metadata into .csproj file manually, but the issue remained.
<ItemGroup>
<EmbeddedResource Include="Resources\logging.json">
<CopyToOutputDirectory>Never</CopyToOutputDirectory>
</EmbeddedResource>
</ItemGroup>
I think this should be a potential issue and I have reported it to Microsoft Developer Community, hope VS product team can fix it and share the insights. Here is the link: Embedded Resources still copy to output directory even set CopyToOutputDirectory to Never.

App.config for different environments folder structure

I have multiple config files for the different environments for my C# application. They appear as subitems under App.config. The problem is I want to add a new option, in this case JMTelcom, but it appears outside the folder structure. The file seems to be working fine at compile time, but how do I make it appear next to its siblings?
<ItemGroup>
<Compile Update="App.*.config">
<DependentUpon>App.config</DependentUpon>
</Compile>
</ItemGroup>
Add/append above lines to your .csproj file should do the trick. (Assuming your project is using .net core)

Automatically nest files in .csproj class libary (DependentUpon)

I have a number of C# files I am generating. I would like them to automatically be nested under the matching C# file inside the Visual Studio solution explorer. For example, Foo.Generated.cs and Bar.Generated.cs would be nested under Foo.cs and Bar.cs, respectively.
If possible I'd like to be able to manage this in my Directory.Build.props file, so all the class libraries in my solution will have the same behavior.
Versions
.NET Core 3.1
Visual Studio 2019 (16.5.3)
Failed Attempt A:
<Compile Update="**\*Generated.cs">
<DependentUpon>$([System.String]::Copy(%(Filename)).Replace('.Generated', '.cs'))</DependentUpon>
</Compile>
Failed Attempt B:
<Compile Update="**\*Generated.cs">
<DependentUpon>%(Filename)</DependentUpon>
</Compile>
Failed Attempt C:
<Compile Update="**\*Generated.cs">
<DependentUpon>%(Filename).cs</DependentUpon>
</Compile>
The above approaches have also been tried with:
<ItemGroup>
<ProjectCapability Include="DynamicDependentFile" />
<ProjectCapability Include="DynamicFileNesting" />
</ItemGroup>
If possible I'd like to be able to manage this in my
Directory.Build.props file, so all the class libraries in my solution
will have the same behavior.
First, I think you should use Directory.Build.targets rather than Directory.Build.props. As this document shows, Directory.Build.props is imported very early in Microsoft.Common.props and Itemgroup elements are recognized after MSBuild Properties, so when you add items in Directory.Build.props, these elements will not be recognized by MSBuild.
However, Directory.Build.targets is imported very late which MSBuild already starts to recognize them at that time and with it, you can add any items that can be recognized in that file.
Solution
1) change your file to Directory.Build.targets
2) add these(yours) in it:
<Compile Update="**\*Generated.cs">
<DependentUpon>$([System.String]::Copy(%(Filename)).Replace('.Generated', '.cs'))</DependentUpon>
</Compile>
And it works in my side and hope it could help you.

How are preprocessors linked to different target frameworks?

I'm following along with a talk by Immo Landwerth, in a .NET standard project, I saw him switching between projects (which are not typically projects under the solution) from the top left drop-down menu, here is a gif: https://image.ibb.co/mmjoHU/pre.gif
To reproduce the same thing I created a class library in .NET Framework to see the goings, but the project failed to load (with a modified csproj file to be the same as the demo's csproj), then I created a .NET standard library and modified the .csproj file to this (the same as the demo's csproj):
<Project Sdk="MSBuild.Sdk.Extras">
<PropertyGroup>
<TargetFrameworks>netstandard1.4;net461;uap10.0</TargetFrameworks>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="System.ValueTuple" Version="4.3.0" />
</ItemGroup>
<ItemGroup Condition=" '$(TargetFramework)' == 'net461' ">
<Reference Include="System.Device" />
</ItemGroup>
</Project>
I could see the three target frameworks:netstandard1.4;net461;uap10.0. but really couldn't understand how they got mapped to the preprocessors: NET461, WINDOWS_UWP. which work on the Immo's project, but didn't work with my modified .NET standard library and the three targets didn't appear.
Looks like conditional compilation symbols with linked .cs files to me.
In the Properties > Build tab, you should see a textbox labelled "Conditional compilation symbols". Any strings you put in this textbox can be used to conditionally execute code with #if and #elif. There are also symbols that the build system is already aware of (some are listed here).
I'm assuming these projects also share the same .cs files, which explains the #if/#elif/#else conditions "flipping" within the same file (when you add a file to a project, choose add it as a link to an existing file, then a copy is not made).
I have done this exact thing on multiple projects for different configurations and the behavior matches the .gif you posted.

How to determine behavior of binaries in NuGet package

There is this big solution I'm working on, where I turned a lot of the projects into NuGet packages. The packages were created via a .nuproj file in a separate solution in VS.
Everything works fine, except for the following:
At bootstrap I load some catalogs for MEF to be able to import them, which worked perfectly when I worked with the original projects, but now the needed DLLs (which come from the a package) don't make it to the bin\Debug\Modules folder.
Is there a way to make NuGet copy its content to the Modules folder? (and not to the root path)
I tried using the different kinds of sub-folders inside the package with no success.
I found that the best solution for this matter is the following:
Take the files that need to be loaded and put them on the content folder. This can be done simply:
<ItemGroup>
<Content Include=" {here go the needed files} " />
</ItemGroup>
The content folder just holds the files, but it does not copy them to the output folder on the client project. In order to copy them to the desired output, a .targets file can be used, just like the following:
<?xml version="1.0" encoding="utf-8" ?>
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Target Name="CopyToOutput" AfterTargets="Build">
<ItemGroup>
<FilesToCopy Include="$(MSBuildThisFileDirectory)..\content\**\*.*"/>
</ItemGroup>
<Copy
SourceFiles="#(FilesToCopy)"
DestinationFiles="#(FilesToCopy->'$(OutDir)/%(RecursiveDir)%(FileName)%(Extension)')"/>
</Target>
</Project>
Keep in mind that the targets file name and the ID of the NuGet have to be equal for the targets file to be added to the project.
You should be able to use a target of content/Modules. Anything in the content directory is copied in to the bin directory on build.
If you were trying to use the special "convention based" folders, like lib/net45, those are directories that cause Visual Studio to automatically create an assembly reference when the package is installed. You shouldn't use those for regular content files.
See the documentation for more details.

Categories