How to Add an Existing Item to a Project Programmatically? - c#

How can I programmatically add an item to a project?
Something similar to
public void AddExistingItem(string projectPath, string existingItemPath)
{
//I'm making up the Project class here as an example
Project p = new Project(projectPath);
p.AddExistingItem(existingItemPath);
}
I want to mimic Visual Studio's Add Existing Item functionality.

VisualStudio project is just a XML file so you can open it using XDocument or XmlDocument and edit.

Add a reference to EnvDTE.dll, and then use ProjectItems.AddFromFile method
As you can read on this page, you must set the Embed Interop Types property of the assembly to false if you add a reference to EnvDTE.dll

Try something like this:
public void createProjectItem(DTE2 dte)
{
//Adds a new Class to an existing Visual Basic project.
Solution2 soln;
Project prj;
soln = (Solution2)_applicationObject.Solution;
ProjectItem prjItem;
String itemPath;
// Point to the first project (the Visual Basic project).
prj = soln.Projects.Item(1);
// Retrieve the path to the class template.
itemPath = soln.GetProjectItemTemplate("Class.zip", "vbproj");
//Create a new project item based on the template, in this
// case, a Class.
prjItem = prj.ProjectItems.AddFromTemplate(itemPath, "MyNewClass");
}
from: http://msdn.microsoft.com/en-us/library/vstudio/ms228774.aspx

Related

Type-safe way to get embedded resource content in .NET Core 3

I'm using .NET Core 3 preview 6 and Visual Studio 2019 16.2 for creating WinForms application.
In .NET Framework I used type-safe mechanism to load resources, something like that:
this.pictureBox1.BackgroundImage = global::MyNamespace.Properties.Resources.Image1;
this.textBox1.Text = global::MyNamespace.Properties.Resources.Script1;
But in .NET Core 3 I must write special helper class with several methods:
public static class EmbeddedResource
{
public static Image GetImage(String resourceName)
{
try
{
using (var stream = typeof(EmbeddedResource).GetTypeInfo().Assembly.GetManifestResourceStream(resourceName))
return Image.FromStream(stream);
}
catch(Exception exception)
{
throw new Exception($"Failed to read Embedded Resource {resourceName}");
}
}
public static String GetString(String resourceName)
{
try
{
using (var stream = typeof(EmbeddedResource).GetTypeInfo().Assembly.GetManifestResourceStream(resourceName))
using (var reader = new StreamReader(stream, Encoding.UTF8))
return reader.ReadToEnd();
}
catch(Exception exception)
{
throw new Exception($"Failed to read Embedded Resource {resourceName}");
}
}
}
And use it like that:
this.pictureBox1.BackgroundImage = EmbeddedResource.GetImage("MyNamespace.Image1.jpg");
this.textBox1.Text = EmbeddedResource.GetString("MyNamespace.Script1.sql");
Is there a better way (e. g. strictly-typed and resourceName error-safe) to do that?
Thank you in advance.
Visual Studio 2019 16.2 Has design-time support for Resx file for Windows Forms .NET Core Projects. It is the same feature that is supported in previous versions of Visual Studio for Windows Forms classic .NET projects.
It means you can:
Add New Item → Choose Resources File and set a name like Resources.Resx and press Add. The file will be opened in design mode. (Later to open it in design mode, just double click on it.)
Add an image to the designer by dragging an image file and dropping it into the designer. You can also add the image by click on Add Resource tool strip drop down button and choosing Add Existing File ....
Then the image will be accessible using a property which has the same name as the image. For example I created a Properties folder and created Resources.Resx under that folder, then added MyImage.jpg to the resource file, the I could use it this way:
this.BackgroundImage = Properties.Resources.MyImage;
Note - Create default Resource file for the project in Properties folder
Right click on Project → Choose Properties
In project properties window, choose Resources (left side, bottom of the list).
At the center, you will see a link This project does not contain a default resources file. Click here to create one. Click on the link and it will create a Resources.Resx file under Properties folder for your project.

Add ClassLibrary Project programmatically

I have a VS 2017 extension and have tried using my own custom Project Template, by adding it programmatically, but things aren't going so well.
In my endeavour to find the mistake, I would like to see whether it is my custom Project Template causing the problem or not. Therefore I want to programmatically add any other existing built-in VS project such as a ClassLibrary type project template.
It seems to be located here:
C:\Program Files (x86)\Microsoft Visual Studio\2017\Professional\Common7\IDE\ProjectTemplates\CSharp\Windows\1033\
But there isn't a zip folder and I can't create one in that directory according to Windows.
I will be using something similar to the following code:
Solution2 soln = (Solution2)visualStudioInstance.Solution;
string templatePath = soln.GetProjectTemplate("ClassLibrary.zip", "CSharp");
soln.AddFromTemplate(templatePath, projPath, "MyProjectName", false);
Am I on the right track?
I've tried it and I got an exception, but perhaps it was just because the zip folder doesn't exist.
UPDATE
The exception I get is:
"Object reference not set to an instance of an object."
I get it in the last line of the following code, when I try to add a reference to calcEngineProject. calcEngineProject is null even though it enters the if-statement and should be assigned the value of projCS.Object as VSProject2.
The code is as follows:
templatePath = soln.GetProjectTemplate("ClassLibrary.zip", "CSharp");
soln.AddFromTemplate(templatePath, prjPath, "ClassLibrary1", false);
foreach (Project p in soln.Projects)
{
if (String.Compare(p.Name, "ClassLibrary1") == 0)
{
projCS = p;
break;
}
}
if (projCS != null)
{
calcEngineProject = projCS.Object as VSProject2;
}
calcEngineProject.References.Add(Path.Combine(Config.Engine.EngineBinPath, "Engines.Calculation.dll"));
Also, I saw that templatePath is this:
"C:\PROGRAM FILES (X86)\MICROSOFT VISUAL
STUDIO\2017\PROFESSIONAL\COMMON7\IDE\EXTENSIONS\EYXTAMKA.FB4\ProjectTemplates\CSharp\.NET
Standard\1033\ClassLibrary\ClassLibrary.vstemplate"
and not
\%USERPROFILE%\Documents\My Exported Templates\
as mentioned in Upgrading custom project template

programmatically extract interface using roslyn

I am looking for a way to extract an interface from a document (c# class declaration) using Roslyn.
going from the reformatter example.
MSBuildWorkspace workspace = MSBuildWorkspace.Create();
// Open the solution within the workspace.
Solution originalSolution = workspace.OpenSolutionAsync(project).Result;
// Declare a variable to store the intermediate solution snapshot at each step.
MSBuildWorkspace workspace = MSBuildWorkspace.Create();
Solution originalSolution = workspace.OpenSolutionAsync(project).Result;
Solution newSolution = originalSolution;
foreach (ProjectId projectId in originalSolution.ProjectIds)
{
// Look up the snapshot for the original project in the latest forked solution.
Project proj = newSolution.GetProject(projectId);
var comp = proj.GetCompilationAsync().Result;
///var bind = comp.
if (proj.Name.EndsWith("Core.DataLayer"))
{
foreach (DocumentId documentId in proj.DocumentIds)
{
Document document = newSolution.GetDocument(documentId);
if (IsRepositoryDocument(document))
{
//How to implement this?
var newinterface = GetInterfaceFromRespository(document);
}
}
}
}
I started out using the sample "reformat solution" that the Roslyn team provided. However I am unable to find a public API to extract an interface from a given class file.
When trying to find this functionality in the Roslyn source code I can only find internal classes. I found the relevant classes in
"src\Features\Core\Portable\ExtractInterface" of the roslyn source code, i could copy these into my project and get it working, but i would rather not.
TLDR; is there a public API that I can use from C# to extract an interface from a class programatically?
Note that this is done in a "regular" C# project and not in a visual studio extension or analyzer.
You can get all the interfaces from a C# file using the below code statements.
string code = new StreamReader(filePath).ReadToEnd();
var syntaxTree = CSharpSyntaxTree.ParseText(code);
var syntaxRoot = syntaxTree.GetRoot();
IEnumerable<InterfaceDeclarationSyntax> interfaceDeclarations = syntaxRoot.DescendantNodes().OfType<InterfaceDeclarationSyntax>();
Then you can iterate the available interfaces in the file.

VSPackage command that creates a new solution

How can I create a command in a VSPackage that creates a new solution with a new project (C# Class Library) in it, containing 1 .cs file?
It is not very straighforward but there is an interesting guide on MSDN that explains how to do it. It is for an Add-in but in a VSPackage you have the same set of Visual Studio DTE objects available (the DTE application).
You can define a method that uses GetProjectTemplate and AddFromTemplate to create two console projects. You can define in the method Initialize of your VSPackage class a OLE menu command (if that is what you are looking for):
protected override void Initialize()
{
//// Create the command for the menu item.
var aCommand = new CommandID(GuidList.GuidCmdSet, (int)PkgCmdIdList.CmdId);
var menuItemEnable = new OleMenuCommand((s, e) => createProjectsFromTemplates(), aCommand);
}
And then define a method associated to the command (createProjectsFromTemplates in this case) that creates a solution with a project:
private DTE2 _mApplicationObject;
public DTE2 ApplicationObject
{
get
{
if (_mApplicationObject != null) return _mApplicationObject;
// Get an instance of the currently running Visual Studio IDE
var dte = (DTE)GetService(typeof(DTE));
_mApplicationObject = dte as DTE2;
return _mApplicationObject;
}
}
public void createProjectsFromTemplates()
{
try
{
// Create a solution with two projects in it, based on project
// templates.
Solution2 soln = (Solution2)ApplicationObject.Solution;
string csTemplatePath;
string csPrjPath = "C:\\UserFiles\\user1\\addins\\MyCSProject";
// Get the project template path for a C# console project.
// Console Application is the template name that appears in
// the right pane. "CSharp" is the Language(vstemplate) as seen
// in the registry.
csTemplatePath = soln.GetProjectTemplate(#"Windows\ClassLibrary\ClassLibrary.vstemplate",
"CSharp");
System.Windows.Forms.MessageBox.Show("C# template path: " +
csTemplatePath);
// Create a new C# console project using the template obtained
// above.
soln.AddFromTemplate(csTemplatePath, csPrjPath, "New CSharp
Console Project", false);
}
catch (System.Exception ex)
{
System.Windows.Forms.MessageBox.Show("ERROR: " + ex.Message);
}
}
For Visual Studio versions after 10.0 the zip for template projects is not available anymore. The .vstemplate must be referenced and it is possible to find all the project templates under the folder:
C:\Program Files (x86)\Microsoft Visual Studio 1x.0\Common7\IDE\ProjectTemplates\
More info on this MSDN link.
The method should create a solution with one C# project based on the c# project template (e.g. containing class1.cs as initial file).
You can define your own template as well if you wish and create a solution based on that custom template. Here is a guide from MSDN on how to create custom templates.
hope it helps.

Accessing class members defined in another *.cs file

I'm writing an update checker for my program and I'm using xml from a remote server. The request is working fine and it does what I want. The problem is that I can't call the function from another file. (See code below)
The files
home.cs - The place i want to call the RequestVersion()
version.cs - Where the RequestVersion() is located
The code
version.cs
namespace MyName
{
class version
{
public string[] RequestVersion()
{
XmlDocument doc = new XmlDocument();
try
{
string[] version_data = new string[3];
doc.Load("link_here");
foreach (XmlNode node in doc.DocumentElement)
{
string version = node.Attributes[0].Value;
string date = node["date"].InnerText;
string changelog = node["changelog"].InnerText;
version_data[0] = version;
version_data[1] = date;
version_data[2] = changelog;
return version_data;
}
}
catch (Exception xml_ex)
{
}
return null;
}
}
}
(returns an array)
home.cs
private void checkForUpdatesToolStripMenuItem_Click(object sender, EventArgs e)
{
//This is the place from where i want to access the array!
}
And my XML structure:
<?xml version="1.0" encoding="UTF-8"?>
<SerialMate>
<release version="1.0.0">
<date>12-10-2014</date>
<changelog>Test</changelog>
</release>
</SerialMate>
(I'm not adding any new <release> tags on the xml so it always has 1)
The question
So, my question is: How do it access the array elements from the RequestVersion() within home.cs?
I don't really understand your problem, but:
version v = new version();
string[] s = v.RequestVersion();
Referencing code within other files and projects
Within the same project it makes absolutely no difference whether the code is in the same or in different files. The only things which matter are the access modifiers (public, protected, internal, and private).
If the two code pieces are in different projects, then the compiled code will be compiled into two different assemblies (*.exe or *.dll). Therefore one project will have to reference the other one. Typically the start up project (*.exe) will reference a class library project (*.dll).
If the two projects are within the same solution, you can add a so called project reference. Right click on the class library project in the solution explorer and click “Copy As Project Reference”. In the startup project, right click on “References” and click “Paste Reference”.
If the two projects are within different solutions you will have to add a reference to the class library DLL (usually the one in bin/Release) from within the startup project. Right click “References” and click “Add Reference…”. In the references dialog choose “Browse” and select the DLL.
Also make sure not to create circular dependencies (project A references project B and project B references project A). If you have such a dependency, you can usually resolve it by placing the code that has to be accessed by the two projects into a third project C. Then change the references to: A references C and B references C.
Calling the method of another class
Types (a class in your case) and their members (properties, methods, events …) must be declared as public in order to be accessible from other projects. Within the same project they can also be declared as internal. (They can also be declared as protected if you want to derive new classes.)
If a member is declared as static or if it is a constant, you can access it by specifying the type name dot the member name:
var result = MyClass.MyMethod();
If the member is an instance member you must call it from an instance of the type (an object):
MyClass obj = new MyClass();
var result = Obj.MyMethod();

Categories