The .cs files are not under the .xaml file - xaml

I am Newbie self learning Xamarin, I was making small projects Until I encountered this problem. every time I start new project, I get an Error:
"Could not restore Packages".
App.xaml.cs used to be under App.xaml and main.xaml.cs used to be under main.xaml. Now they 2 independent files.
1) How can I restore packages?
2) How can I associate .cs file to .xaml file?
Here is an Image of my problem
Thanks in advance

A project I am working on had the issue for awhile and this was the fix for it.
Place this XML grouping inside of your Test.csproj file.
<ItemGroup>
<!-- https://bugzilla.xamarin.com/show_bug.cgi?id=55591 -->
<None Remove="**\*.xaml" />
<Compile Update="**\*.xaml.cs" DependentUpon="%(Filename)" />
<EmbeddedResource Include="**\*.xaml" SubType="Designer" Generator="MSBuild:UpdateDesignTimeXaml" />
</ItemGroup>
Please note that in a future update, and forgive me because I don't 100% remember, an update of Visual Studio or .NetStandard fixed the issue. Our project no longer needs this fix.

Edit your ".projitems" file located on the same directory of your .xaml files of your Xamarin project, there is the asociation between the .cs files and .xaml files in this way
<Compile Include="$(MSBuildThisFileDirectory)MyPage.xaml.cs">
<DependentUpon>MyPage.xaml</DependentUpon>
<SubType>Code</SubType>
</Compile>
<ItemGroup>
<EmbeddedResource Include="$(MSBuildThisFileDirectory)MyPage.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</EmbeddedResource>
</ItemGroup>
<Compile Update="C:\Projects\MyPage.xaml.cs">
<DependentUpon>MyPage.xaml</DependentUpon>
</Compile>

I just noticed the issue on some of my former solution file and in the csproj file for one project I had one view not displaying properly.
It had this code only for the view that had not proper nesting.
<ItemGroup>
<Compile Update="Views\NotProperNesting.xaml.cs">
<DependentUpon>NotProperNesting.xaml</DependentUpon>
</Compile>
</ItemGroup>
I don't know why it was there in the 1st place, but just removed it and it worked.

Related

Add folder from solution to C# .NET project Content output

I want to include files from the solution directory, regardless of where the files are. I added this to my .csproj file:
<ItemGroup>
<Content Include="$(SolutionDir)\web\**\*" />
</ItemGroup>
But the files do not appear in the solution explorer. And they do not appear in the publish output either.
How to do this correctly?
You still need to tell MSBuild to copy the content, for example
<ItemGroup>
<Content Include="$(SolutionDir)\web\**\*">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
</ItemGroup>

How to generate files during build using msbuild

Does anyone know how to modify a csproj file in a way to generate code files during build without actually referencing the files?
A process like :
create file,
dynamically reference temporary file during build
compiled assembly has additional members, depending on the files created during build
The purpose of this is to create a way of generating code files using roslyn instead of using t4 templates, which are very awkward to use once you're trying to do something depending on attributes.
Hence i am planning on providing a way to use a special csharp file (for full syntax support) to generate files programatically based on the contents of that special file.
I've spent a couple of weeks looking into resources on the internet (with the topic msbuild), but until now it seems i didn't use the right keywords.
This one has been the most insightful one to me yet:
https://www.simple-talk.com/dotnet/.net-tools/extending-msbuild/
My guess is, that the correct build target for my purpose should be "BeforeCompile" in order to somehow populate the build process with custom code files.
Does anyone have experience with my issue, or is aware of any particular resources which deal with the task?
Solution i got it working with:
<UsingTask TaskName="DynamicCodeGenerator.DynamicFileGeneratorTask" AssemblyFile="..\DynamicCodeGenerator\bin\Debug\DynamicCodeGenerator.dll" />
<Target Name="DynamicCodeGeneratorTarget" BeforeTargets="BeforeBuild;BeforeRebuild">
<DynamicFileGeneratorTask>
<Output ItemName="Generated" TaskParameter="GeneratedFilePaths" />
</DynamicFileGeneratorTask>
<ItemGroup>
<Compile Include="#(Generated)" />
<FileWrites Include="#(Generated)" />
<!-- For clean to work properly -->
</ItemGroup>
</Target>
Unfortunately i did not get it to work with a propertygroup override as suggested
Update: This link is interesting too: https://github.com/firstfloorsoftware/xcc/blob/master/FirstFloor.Xcc/Targets/Xcc.targets
Generating the code file can be achieved by msbuild task or msbuild inline task. It is up to you to generate the proper code. One thing that you must care of is creating output item parameter in order to append it to the #(Compile) item. You can use $(IntDir) location to locate your newly generated file, and add them to the #(FileWrites) item group in order for Clean target work properly.
When you finish writing your task, you must use it in your project like this:
<UsingTask TaskName="TaskTypeFullName" AssemblyFile="YourAssembly.dll"/>
<PropertyGroup>
<!-- Here you need to experiment with [Build/Compile/SomeOther]DependsOn property -->
<BuildDependsOn>
MyCodeGenerator;
$(BuildDependsOn)
</BuildDependsOn>
</PropertyGroup>
<Target Name="MyCodeGenerator">
<YourTaskName>
<Output ItemName="Generated" TaskParameter="GeneratedFiles" />
</YourTaskName>
<ItemGroup>
<Compile Include="#(Generated)" />
<FileWrites Include="#(Generated)" /> <!-- For clean to work properly -->
</ItemGroup>
</Target>
I wanted to use a bash script to generate code for a project using dotnet core on Linux. Here is what worked for me. And thanks #stukselbax, I built this off of your answer.
<Target Name="GenerateProtocolBuffers" BeforeTargets="BeforeBuild;BeforeRebuild">
<Exec Command="./generatecode.sh" Outputs="proto/*.cs">
<Output ItemName="Generated" TaskParameter="Outputs" />
</Exec>
<ItemGroup>
<Compile Include="#(Generated)" />
<FileWrites Include="#(Generated)" />
</ItemGroup>
</Target>
Note that the script I'm using to generate the code is called generatecode.sh. Replace this with your own.

Apply an MSBuild effect across multiple projects in a solution

I've got the AssemblyInfo feature of the MSBuild Extension Pack working, so that my assemblies description and file version have the details I want in the code below ...
But I want to apply this effect across every project in a 50+ project solution!
So how can I work on all the projects ... without going through each project adding the code?
<PropertyGroup>
<CoreCompileDependsOn>
$(CoreCompileDependsOn);
AssemblyDefaults;
</CoreCompileDependsOn>
</PropertyGroup>
<PropertyGroup>
<ExtensionTasksPath>
$(MSBuildProjectDirectory)\..\packages\MSBuild.Extension.Pack.1.4.0\tools\net40\
</ExtensionTasksPath>
</PropertyGroup>
<Import Project="$(ExtensionTasksPath)\MSBuild.ExtensionPack.tasks" />
<Target Name="AssemblyDefaults">
<ItemGroup>
<AssemblyInfoFiles Include=".\Properties\AssemblyInfo.cs" />
</ItemGroup>
<AssemblyInfo
AssemblyInfoFiles="#(AssemblyInfoFiles)"
AssemblyProduct="Compiled on: $([System.Environment]::MachineName)"
AssemblyDescription="Compiled at: $([System.DateTime]::Now)"
AssemblyFileBuildNumberType="DateString"
AssemblyFileBuildNumberFormat="MMdd"
AssemblyFileRevisionType="DateString"
AssemblyFileRevisionFormat="HHmm" />
</Target>
You could create a common assembly file for all the projects and edit the csproj files to refer to the common assembly info file like:
<Compile Include="..\CommonAssemblyInfo.cs">
<Link>Properties\CommonAssemblyInfo.cs</Link>
</Compile>
More information can be found at Shared AssemblyInfo for uniform versioning across the solution

MSBuild project file: Copy item to specific location in output directory

In the process of cleaning up the folder/file structure on a project I inherited, I'm running into a problem with organizing the required external libraries. I want to keep them in their own .\dll\ folder, but they're not being copied to the build directory properly. They should be in the root build directory, but they're being moved to a subfolder instead.
My .csproj file contains the following xml:
<Project>
<ItemGroup>
<None Include="dlls\libraryA.dll">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup>
</Project>
Then, on build, the libraryA.dll file is copied to the bin\Debug\dll\ folder, but I want it in the bin\Debug\ folder.
I tried this and msbuild always wants to copy the files using their directory path, but there is a workaround...
Edit the csproj file and after this line:
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
Add these lines:
<PropertyGroup>
<PrepareForRunDependsOn>$(PrepareForRunDependsOn);MyCopyFilesToOutputDirectory</PrepareForRunDependsOn>
</PropertyGroup>
<Target Name="MyCopyFilesToOutputDirectory">
<Copy SourceFiles="#(None)" DestinationFolder="$(OutDir)" />
</Target>
The copy of the output files happens in the PrepareForRun target. This adds your own target to the list of targets that are executed as part of PrepareForRun.
This example copies all items in the None item group. You could create your own item group (e.g. MyFiles) and do the copy on that item group if you have other "None" files you don't want copied. When I tried this I had to change the item group name by editing the csproj file directly. Visual Studio did not allow me to set the item group of a file from the UI, but after I edited the csproj and changed it, Visual Studio displayed my custom item group name correctly.
If you only want to change it for one file, it may be easier to use the property:
<None Include="dlls\libraryA.dll">
<Link>%(Filename)%(Extension)</Link>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
Including content files in .csproj that are outside the project cone
This approach works
If you need to force copy of a specific file/nuget package into an asp.net core project (2.2), add at the end of your csproj :
<!-- Force copy MathNet because we need it in compilation -->
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="Build">
<PropertyGroup>
<ErrorText>This project references NuGet package(s) that are missing on this computer. The missing file is {0}.</ErrorText>
</PropertyGroup>
<Error Condition="!Exists('..\packages\MathNet.Numerics.4.8.1\lib\netstandard2.0\MathNet.Numerics.dll')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\MathNet.Numerics.4.8.1\lib\netstandard2.0\MathNet.Numerics.dll'))" />
</Target>
<ItemGroup>
<ContentWithTargetPath Include="..\packages\MathNet.Numerics.4.8.1\lib\netstandard2.0\MathNet.Numerics.dll">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<TargetPath>MathNet.Numerics.dll</TargetPath>
</ContentWithTargetPath>
</ItemGroup>
In SDK-style csproj you can write something like:
<Target Name="CopyFilesTargetName" AfterTargets="Build">
<Copy SourceFiles="$(OutDir)\dlls\Some.dll;$(OutDir)\dlls\SomeOther.dll" DestinationFolder="$(OutDir)" />
</Target>
You can also use <Move instead of <Copy to move files

Can I use both wildcard and Link element inside the Compile element?

In the .csrpoj file, If I have
<Compile Include="c:\path\File1.cs">
<Link>Dir1\File1.cs</Link>
</Compile>
Then Visual Studio shows that file as a shortcut under Dir1 folder in the Solution Explorer.
If I have
<Compile Include="c:\path\*.cs"></Compile>
Then all .cs files show up as shortcuts in Solution Explorer at top level:
Is there a way to include all files in some folder and make then show up under a sub-folder? Omitting the filename in Link element does not work:
<Compile Include="c:\path\*.cs">
<Link>Dir1\</Link>
</Compile>
The files still show up at top level.
How do I include all files in a folder and still use the Link element? The reason I need this is, I need to include files from multiple folders and some of them have the same name. Two files at top level cannot have the same name.
Any other way to achieve this?
Others have suggested the using the Link attribute with placeholders, which indeed works. However, Microsoft has implemented a new attribute (which isn't in any of my code completion suggestions), named LinkBase, shown below.
<ItemGroup>
<Compile Include="..\SomeDirectory\*.cs" LinkBase="SomeDirectoryOfYourChoosing" />
</ItemGroup>
Sources:
https://github.com/Microsoft/msbuild/issues/2795
https://github.com/dotnet/sdk/pull/1246
Link Additional Files in Visual Studio
<Content Include="..\..\SomeDirectory\**\*.xml">
<Link>SomeLinkDirectoryOfYourChoosing\%(Filename)%(Extension)</Link>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
For the sake of others, here's the answer plus the comment from Dean and Miserable Variable, which I found useful:
I have two projects, and I need to include *.xsd from one in the other, without copying the files or having to update the referencing csproj file every time a new XSD is added to the first.
The solution was to add the following to the csproj file
<Content Include="..\BusinessLayer\Schemas\*.xsd">
<Link>Contract\Schemas\xxx.xsd</Link>
</Content>
Note xxx.xsd, you have to give a dummy filename in the Link element. It just gets replaced.
Also, you can include all sub folders with:
<Content Include="..\BusinessLayer\Schemas\**\*.xsd">
<Link>Contract\Schemas\ThisTextDoesntMatter</Link>
</Content>
And files of all type (useful for pulling in CSS/JS/Style folders from 3rd parties) with:
<Content Include="..\PresentationLayer\CustomerStyle\**\*.*">
<Link>CustomerStyle\placeHolder</Link>
</Content>
To include subfolders:
<ItemGroup>
<Compile Include="..\SomeExternalFolder\**\*.cs" LinkBase="YourProjectFolder" />
</ItemGroup>