Programatically generating assemblies from OWL files with ROWLEX - c#

I have been using the ROWLEX library to handle RDF-s. It is shipped with a designtime GUI tool called OwlGrinder.exe that can generate C# helper classes (.NET assemblies to be exact) from my OWL ontologies. I wonder if anyone knows if I could do the same programatically in runtime.

ROWLEX just became open source, so now you have the chance to actually look inside the code of OwlGrinder.exe and copy the code from there. However, here is a short example:
private NC3A.SI.Rowlex.AssemblyGenerator generator;
private void RunAssemblyGeneration(XmlDocument ontologyFileInRdfXml)
{
this.generator = new NC3A.SI.Rowlex.AssemblyGenerator();
this.generator.GenerateAsync(ontologyFileInRdfXml, "myAssemblyName",
null, this.OnGenerationFinished);
}
private void OnGenerationFinished(string errorMessage)
{
if (errorMessage == null)
{
// Success
// Displaying warnings and saving result
string[] warnings = this.generator.Warnings;
this.generator.SaveResult(#"C:\myAssemblyName.dll");
// Important! One generator instance can be executed only once.
this.generator = null;
this.RejoiceOverSuccess();
}
else
{
// Failure
this.MournOverFailure();
}
}
If you want to generate assemblies in runtime, I assume that you might want to repeat that over and over again as your user demands. You have to watch out here, because .NET does not allow you to unload an assembly. Therefore you cannot get rid of the assemblies from your previous runs. The solution is that you execute the generation code every time in a new AppDomain which can be unloaded. OwlGrinder.exe does exactly this, you might want to peak inside the MainForm.cs

Yes, Mr Lame, you can programmatically generate .NET code.
There are a couple options.
Create the code as text.
You can compile any .cs or .vb source file from within an app. See the help for the Microsoft.CSharp.CSharpCodeProvider class, for a starter. You invoke the compiler programmatically, specifying the resources to embed, where to put the generated assembly, the dependencies, and so on. One scenario here is using a template.cs file, embedding a little more code into it, and then compiling it. The result is an assembly (.dll or .exe or .netmodule if you like) resulting from that code. You can then load that assembly and call into it, using reflection.
Create the code using a document object model.
The relevant feature area here is called "CodeDom" and it works like the HTML DOM for web pages, except the document object model is used to create .NET code. Programmatically you construct the code, using DOM elements.
example of the CodeDom thing:
var class1 = new System.CodeDom.CodeTypeDeclaration(className);
class1.IsClass=true;
class1.TypeAttributes = System.Reflection.TypeAttributes.Public;
class1.Comments.Add(new System.CodeDom.CodeCommentStatement("This class has been programmatically generated"));
// add a constructor to the class
var ctor= new System.CodeDom.CodeConstructor();
ctor.Attributes = System.CodeDom.MemberAttributes.Public;
ctor.Comments.Add(new System.CodeDom.CodeCommentStatement("the null constructor"));
class1.Members.Add(ctor);
// add one statement to the ctor: an assignment
// in code it will look like; _privateField = new Foo();
ctor.Statements.Add(new System.CodeDom.CodeAssignStatement(new System.CodeDom.CodeVariableReferenceExpression("_privateField"), new System.CodeDom.CodeObjectCreateExpression(fooType)));
// include a private field into the class
System.CodeDom.CodeMemberField field1;
field1= new System.CodeDom.CodeMemberField();
field1.Attributes = System.CodeDom.MemberAttributes.Private;
field1.Name= "_privateField";
field1.Type=new System.CodeDom.CodeTypeReference(fooType);
class1.Members.Add(field1);
etc etc. You can add regular methods, all sorts of statements in the code, and so on. AFAIK the CodeDom stuff supports everything the language supports. You can do lambdas and linq expressions, conditionals and control flow, anything.
You can then compile that class, and again produce an assembly that you can save to disk or keep in memory and load dynamically.

Related

What's the easiest way to create a managed visualiser in C#?

I have a background in C++ and recently I started working in C#.
I have written following pieces of code (in Visual Studio):
var list_Loads = database.GetData<Load>().ToList();
var test_list = list_Loads.Where(o => (o.Name.Substring(0, 3) == "123")).ToList();
When I run the program and I move my mouse over both lists, first I get the count, which is very useful, but when I ask for the entries, this is what I get:
0 : namespace.Load
1 : namespace.Load
2 : namespace.Load
...
Not very useful, as you can imagine :-)
So my question: how can I show the Name attributes of those objects?
I thought: no problem. I have a background in native visualisers, so it should be rather easy to turn this into useful information, but then it comes:
In order to alter the way that those objects are represented, there is the first proposal to add a [DebuggerDisplay] "tag" to the definition of that class in source code.
However, as those classes are part of a framework I'm just referring to, I don't have access to the source code and hence I can't modify this.
Then I found another solution, which comes down to: "Write an entire C# project, debug, test and install it and it might work" (see documentation on "Custom visualisers of data" on the Microsoft website).
I almost choked in my coffee: writing an entire project, just for altering the view of an object??? (While, in C++, you just create a simple .natvis file, mention the classname and some configuration, launch .nvload and that's it.
Does anybody know a simple way to alter the appearance of C# object, without needing to pass through the whole burden of creating an entire C# project?
By the way, when I try to load a natvis file in Visual Studio immediate window, this is what I get:
.nvload "C:\Temp_Folder\test.natvis"
error CS1525: Invalid expression term '.'
What am I doing wrong?
Thanks in advance
OP (my emphasis):
In order to alter the way that those objects are represented, there is the first proposal to add a [DebuggerDisplay] "tag" to the definition of that class in source code.
However, as those classes are part of a framework I'm just referring to, I don't have access to the source code and hence I can't modify this.
Does anybody know a simple way to alter the appearance of C# object, without needing to pass through the whole burden of creating an entire C# project?
If you just want to specify [DebuggerDisplay] on a type, you don't have to have access to the source code. You can make use of [assembly:DebuggerDisplay()] and control how a type appears in the debugger. The only downside is that [assembly:DebuggerDisplay()] naturally only affects the current assembly whose code your mouse is hovering over. If you wish to use the customised display in other assemblies that you own, then you must repeat the [assembly:DebuggerDisplay()] definition.
Here's an easy before-and-after example with DateTime. I picked DateTime because we generally don't have access to the source code and it has some interesting properties:
var items = new List<DateTime>
{
DateTime.Now.AddDays(-2),
DateTime.Now.AddDays(-1),
DateTime.Now
};
...which on my machine defaults to:
Maybe I'm fussy and I just want to see:
Day of the week and
Day of the year
...I can do that via:
using System.Diagnostics;
[assembly: DebuggerDisplay("{DayOfWeek} {DayOfYear}", Target = typeof(DateTime))]
...which results in:
Example:
namespace DebuggerDisplayTests
{
public class DebuggerDisplayTests
{
public DebuggerDisplayTests()
{
var items = new List<DateTime>
{
DateTime.Now.AddDays(-2),
DateTime.Now.AddDays(-1),
DateTime.Now
};
}
}
.
.
.
}
Overrides
[assembly:DebuggerDisplay()] can also be used as a means to override pre-existing [DebuggerDisplay] on a 3-rd party type. Don't like what style they have chosen? Is the type showing far too much information? Change it with [assembly:DebuggerDisplay()].

C# Recompile and reload static class duringruntime [duplicate]

Currently I am working on a project in C# where I have to implement reflection. I have created a WPF application with a GUI. This GUI contains a
combobox which contains all the classnames that implement a specific interface. The classes with the displayed classnames live in the same solution.
Next to the combobox is a button to refresh the content in the combobox. However, when I run my application, modify a classname that implements the interface, and
click on that refresh button the changes don't show up in the combobox. For example, when I change a classname it should display the new classname in stead of the old one.
I have extracted this part of my project to test it in an empty console application. Here I have an interface that is implemented by the classes
QuickSortAlgorithm, DynamicSortAlgorithm and MergeSortAlgorithm. Next I wrote the following, straight forward code, in my main class.
public static List<string> AlgoList = new List<string>();
static void Main(string[] args) {
RefreshAlgorithms();
Print();
Console.WriteLine("\nChange a classname and press a key \n");
Console.ReadKey();
Print();
Console.WriteLine("\nPress a key to exit the program \n");
Console.ReadKey();
}
private static void RefreshAlgorithms() {
AlgoList.Clear();
Type AlgorithmTypes = typeof(IAlgorithms);
foreach (var type in Assembly.GetCallingAssembly().GetTypes()) {
if (AlgorithmTypes.IsAssignableFrom(type) && (type != AlgorithmTypes)) {
AlgoList.Add(type.Name);
}
}
}
private static void Print() {
Console.WriteLine("Algorithm classes:");
foreach (var Algo in AlgoList) {
Console.WriteLine(Algo);
}
}
When I run the application is see the classnames QuickSortAlgorithm, DynamicSortAlgorithm and MergeSortAlgorithm printed. However if I change the name of the, for example,
QuickSortAlgorithm class to QuickSortAlgorithmmmmm I would expect it to print QuickSortAlgorithmmmmm once I press a key. However this is not the case and the name
QuickSortAlgorithm is still being displayed.
I get the feeling that I overlook something in the concept of reflection. Can this even be done after building the solution? If I understood correctly this concept makes it possible to implement changes on runtime. I know that
it will make my application much slower but I'm really eager to learn more about this concept. If one can explain me what I'm doing wrong I would be very happy.
That unfortunately does not work. When your assembly gets loaded, it will stay loaded as it is, changes only applying when you restart your application.
If you are using .NET Framework you can create a new AppDomain and load your assembly into this AppDomain. When you are done, you can unload the AppDomain and with it your assembly. That you can do multiple times in a running application.
void RefreshAlgorithms()
{
var appDomain = AppDomain.CreateDomain("TempDomain");
appDomain.Load(YourAssembly);
appDomain.DoCallback(Inspect);
AppDomain.Unload(appDomain);
}
void Inspect()
{
// This runs in the new appdomain where you can inspect your classes
}
Be careful though, as working with AppDomains has caveats, such as the need to use remoting when communicating with the AppDomain.
In .NET Core there is no such way available, as far as I know
Once you load a compiled .NET assembly into your application, you can't make further changes to the types in that assembly without restarting and rebuilding the application. If this were allowed, then it could lead to all kinds of weird behavior. For example, imagine if the application had a List<Foo> populated with 3 foos and then Foo.Id were changed from an int to a string. What should happen to that live data?
However, if your application doing the reflecting is different than the assembly being reflected over, it is possible to set things up such that you can watch for changes to that assembly file and re-do your reflection. The key is to abandon System.Reflection (which only works on loaded assemblies) and instead use the Mono.Cecil library.
Cecil reads in the assembly metadata without loading the code into the application, so it works well for the "reflection-only" use-case. Of course, what it can't do is actually invoke the code. The Cecil API contains many similarities to System.Reflection. For example:
var assembly = Mono.Cecil.AssemblyDefinition.ReadAssembly(Path.Combine(projectDirectory, "bin", "Debug", "Something.dll"));
var controllerTypes = assembly.MainModule.Types.Where(t => t.BaseType?.FullName == "System.Web.Mvc.Controller")
.ToArray();
Another note is that .NET Framework (not .NET Core) contains the notion of AppDomains which can be loaded an unloaded. These act like .NET "sub-processes" within the one process and have rules about what can cross their boundaries. If you really need to both reload code and execute it, then this could be a solution.
Another option could be the Roslyn scripting API, which would work well if you want to dynamically load and execute source code (vs. compiled assemblies).
It looks like you're overlooking one small step: building your code. Once you rename the class to QuickSortAlgorithmmmm, you need to save and build that assembly.
Doing so will recreate the assembly (assuming your application doesn't have an open handle on it). After that, clicking the refresh button should show the new name.
If you can't reload the assembly because it has your GUI code in it too (which is running), you may want to separate out the classes that implement the interface into their own assembly, potentially build that separately, and copy it over into a directory where your app can find it (eg. in a Plugins directory).

C# Reflection - How to reload a class on runtime?

Currently I am working on a project in C# where I have to implement reflection. I have created a WPF application with a GUI. This GUI contains a
combobox which contains all the classnames that implement a specific interface. The classes with the displayed classnames live in the same solution.
Next to the combobox is a button to refresh the content in the combobox. However, when I run my application, modify a classname that implements the interface, and
click on that refresh button the changes don't show up in the combobox. For example, when I change a classname it should display the new classname in stead of the old one.
I have extracted this part of my project to test it in an empty console application. Here I have an interface that is implemented by the classes
QuickSortAlgorithm, DynamicSortAlgorithm and MergeSortAlgorithm. Next I wrote the following, straight forward code, in my main class.
public static List<string> AlgoList = new List<string>();
static void Main(string[] args) {
RefreshAlgorithms();
Print();
Console.WriteLine("\nChange a classname and press a key \n");
Console.ReadKey();
Print();
Console.WriteLine("\nPress a key to exit the program \n");
Console.ReadKey();
}
private static void RefreshAlgorithms() {
AlgoList.Clear();
Type AlgorithmTypes = typeof(IAlgorithms);
foreach (var type in Assembly.GetCallingAssembly().GetTypes()) {
if (AlgorithmTypes.IsAssignableFrom(type) && (type != AlgorithmTypes)) {
AlgoList.Add(type.Name);
}
}
}
private static void Print() {
Console.WriteLine("Algorithm classes:");
foreach (var Algo in AlgoList) {
Console.WriteLine(Algo);
}
}
When I run the application is see the classnames QuickSortAlgorithm, DynamicSortAlgorithm and MergeSortAlgorithm printed. However if I change the name of the, for example,
QuickSortAlgorithm class to QuickSortAlgorithmmmmm I would expect it to print QuickSortAlgorithmmmmm once I press a key. However this is not the case and the name
QuickSortAlgorithm is still being displayed.
I get the feeling that I overlook something in the concept of reflection. Can this even be done after building the solution? If I understood correctly this concept makes it possible to implement changes on runtime. I know that
it will make my application much slower but I'm really eager to learn more about this concept. If one can explain me what I'm doing wrong I would be very happy.
That unfortunately does not work. When your assembly gets loaded, it will stay loaded as it is, changes only applying when you restart your application.
If you are using .NET Framework you can create a new AppDomain and load your assembly into this AppDomain. When you are done, you can unload the AppDomain and with it your assembly. That you can do multiple times in a running application.
void RefreshAlgorithms()
{
var appDomain = AppDomain.CreateDomain("TempDomain");
appDomain.Load(YourAssembly);
appDomain.DoCallback(Inspect);
AppDomain.Unload(appDomain);
}
void Inspect()
{
// This runs in the new appdomain where you can inspect your classes
}
Be careful though, as working with AppDomains has caveats, such as the need to use remoting when communicating with the AppDomain.
In .NET Core there is no such way available, as far as I know
Once you load a compiled .NET assembly into your application, you can't make further changes to the types in that assembly without restarting and rebuilding the application. If this were allowed, then it could lead to all kinds of weird behavior. For example, imagine if the application had a List<Foo> populated with 3 foos and then Foo.Id were changed from an int to a string. What should happen to that live data?
However, if your application doing the reflecting is different than the assembly being reflected over, it is possible to set things up such that you can watch for changes to that assembly file and re-do your reflection. The key is to abandon System.Reflection (which only works on loaded assemblies) and instead use the Mono.Cecil library.
Cecil reads in the assembly metadata without loading the code into the application, so it works well for the "reflection-only" use-case. Of course, what it can't do is actually invoke the code. The Cecil API contains many similarities to System.Reflection. For example:
var assembly = Mono.Cecil.AssemblyDefinition.ReadAssembly(Path.Combine(projectDirectory, "bin", "Debug", "Something.dll"));
var controllerTypes = assembly.MainModule.Types.Where(t => t.BaseType?.FullName == "System.Web.Mvc.Controller")
.ToArray();
Another note is that .NET Framework (not .NET Core) contains the notion of AppDomains which can be loaded an unloaded. These act like .NET "sub-processes" within the one process and have rules about what can cross their boundaries. If you really need to both reload code and execute it, then this could be a solution.
Another option could be the Roslyn scripting API, which would work well if you want to dynamically load and execute source code (vs. compiled assemblies).
It looks like you're overlooking one small step: building your code. Once you rename the class to QuickSortAlgorithmmmm, you need to save and build that assembly.
Doing so will recreate the assembly (assuming your application doesn't have an open handle on it). After that, clicking the refresh button should show the new name.
If you can't reload the assembly because it has your GUI code in it too (which is running), you may want to separate out the classes that implement the interface into their own assembly, potentially build that separately, and copy it over into a directory where your app can find it (eg. in a Plugins directory).

Object Teletransport

I have a object, better, a class. It is like a win form, with the parts:
class.cs, class.Designer.cs and the last class.Resx
It is an XtraReport, so what I'm doing is to get this object and serialize it into a xml file that holds enough information about its controls. The xml generated is used on another project, that uses just the xml. The problem is that it is not enough, despite the xml having all information, it still needs the origin object to resolve the controls properly. Basically:
Saving the Xml - First Solution(C# solution):
var originalReport = new MyCompleteReportDrawInDesignerMode();
original.SaveLayoutToXml(#"c:\FileToBeSerializedAndUsedInAnotherProject");
Consuming the Xml - Another solution(C# Solution)
var genericClass = new GenericClass();
genericClass.LoadLayoutFromXml(#"C:\FileGeneratedByDeserializedXML");
Both classes are child from XtraReports:
public class MyCompleteReportDrawInDesignerMode : XtraReport
public class GenericClass : XtraReport
this doest not work, since the Another Solution does not have a clue about MyCompleteReportDrawInDesignerMode. So i thought, why not teletransport the whole object and make it happen
//Build the object
var generator = GetObjectFromText(text);
//Resolve the dependecy check
var objectGenerated = generator.ResolveAssembly();
But I have no clue how to do it or if it is viable. Any thoughts ?
Update:
I wanna store the class implementation in the database and rebuild it from another application, since the xml transformation is causing information loss.
Let me introduce a little more deeper context. We are building a reporting server application. The process is basically:
1 - Desginer the XtraReport in designer mode, set the fields databindings, set the xrsubreports reportsource if any
2 - Make a xml file from it and save in local C:\ hard driver.
3 - In another application, the user uploads this file and serialize it into varbinary.
4 - The client side receives this serialized xml and restore it, then it trys to load into a generic XtraReport class.
So I would have to create and bound this assemblys at runtime, since we cannot relase a new version of our product every new report we built.
You need to make the MyCompleteReportDrawInDesignerMode class known by both solutions.
Make a separate class library assembly (separate project) that defines MyCompleteReportDrawInDesignerMode. This assembly (DLL) can then be referenced by both applications; the one that writes the report to an XML file and the one that reads this file and recreates the report.
the solution found was to create a class library visual studio solution, then we design the report, the subreports, and compile the all thing, and serialize the dll into a varbinary column in sql server. The dll is small, about 100 kbytes, so no problem.
After serialized into the database, the other application can consume the dll. In the same table, we put the namespace and class name from the main report, so you can create a instance at runtime, fill the datasource and print. I found that the xml serialization only works on the most recent devexpress versions, like: 13.1.10.
Here is the code:
Assembly local =
Assembly.LoadFile(#"C:\TempReports\5a788bc0-3e70-4f8b-8fa9-f180d23c4f03.dll");
Type t = _local.GetType("Relatórios_Teste.Reports.FluxoCaixa");
object test = Activator.CreateInstance(t);
var report = (XtraReport) test;
var controls = report.AllControls<XRSubreport>();
foreach (var control in controls)
{
if (control.Name.Equals("sub_detail"))
{
control.ReportSource.DataSource = GetSource();
control.ReportSource.DataMember = #"sp_test";
}
}
report.ShowPreview();

Visual Studio Text Editor Extension

I am trying to get started in Visual Studio (2010) extensions and I am having a hard time finding the right materials. I have the SDK, but the included samples seem to be things like adorners, windows, and icons.
I am trying to make an extension that will work directly with the text editor (to alphabetize all of my method names in a class, or make all constant names upper case for example) but I can't find a demo for this type of functionality, or even a tutorial.
Does anyone know where I can find this kind of stuff?
I had the exact same question and now have browsed the web several hours until I was being able to understand and explain how you'd need to start with such an extension.
In my following example we will create a small and dumb extension which will always add "Hello" to the beginning of a code file when an edit has been made. It's very basic but should give you an idea how to continue developing this thing.
Be warned: You have to parse the code files completely on your own - Visual Studio does not give you any information about where classes, methods or whatever are and what they contain. That's the biggest hurdle to be taken when doing a code formatting tool and will not be covered in this answer.[*]
For those who skipped to this answer, make sure you downloaded and installed the Visual Studio SDK first or you will not find the project type mentioned in step one.
Creating the project
Start by creating a new project of the type "Visual C# > Extensibility > VSIX Project" (only visible if you selected .NET Framework 4 as the target framework). Please note that you may have to select the "Editor Classifier" project type instead of the "VSIX Project" type to get it working, s. comment below.
After the project has been created, the "source.extension.vsixmanifest" file will be opened, giving you the ability to set up product name, author, version, description, icon and so on. I think this step is pretty self-explaining, you can close the tab now and restore it later by opening the vsixmanifest file.
Creating a listener class to get notified about text editor instance creations
Next, we need to listen whenever a text editor has been created in Visual Studio and bind our code formatting tool to it. A text editor in VS2010 is an instance of IWpfTextView.
Add a new class to our project and name it TextViewCreationListener. This class has to implement the Microsoft.VisualStudio.Text.Editor.IWpfTextViewCreationListener interface. You need to add a reference to Microsoft.VisualStudio.Text.UI.Wpf to your project. The assembly DLL is found in your Visual Studio SDK directory under VisualStudioIntegration\Common\Assemblies\v4.0.
You have to implement the TextViewCreated method of the interface. This method has a parameter specifying the instance of the text editor which has been created. We will create a new code formatting class which this instance is passed to later on.
We need to make the TextViewCreationListener class visible to Visual Studio by specifying the attribute [Export(typeof(IWpfTextViewCreationListener))]. Add a reference to System.ComponentModel.Composition to your project for the Export attribute.
Additionally, we need to specify with which types of files the code formatter should be bound to the text editor. We only like to format code files and not plain text files, so we add the attribute [ContentType("code")] to the listener class. You have to add a reference to Microsoft.VisualStudio.CoreUtility to your project for this.
Also, we only want to change editable code and not the colors or adornments around it (as seen in the example projects), so we add the attribute [TextViewRole(PredefinedTextViewRoles.Editable)] to the class. Again you need a new reference, this time to Microsoft.VisualStudio.Text.UI.
Mark the class as internal sealed. At least that's my recommendation. Now your class should look similar to this:
[ContentType("code")]
[Export(typeof(IWpfTextViewCreationListener))]
[TextViewRole(PredefinedTextViewRoles.Editable)]
internal sealed class TextViewCreationListener : IWpfTextViewCreationListener
{
public void TextViewCreated(IWpfTextView textView)
{
}
}
Creating a class for code formatting
Next, we need a class handling the code formatting logic, sorting methods and so on. Again, in this example it will simply add "Hello" to the start of the file whenever an edit has been made.
Add a new class called Formatter to your project.
Add a constructor which takes one IWpfTextView argument. Remember that we wanted to pass the created editor instance to this formatting class in the TextViewCreated method of our listener class (simply add new Formatter(textView); to the method there).
Save the passed instance in a member variable. It'll become handy when formatting the code later on (e.g. for retrieving the caret position). Also tie up the Changed and PostChanged events of the TextBuffer property of the editor instance:
public Formatter(IWpfTextView view)
{
_view = view;
_view.TextBuffer.Changed += new EventHandler<TextContentChangedEventArgs>(TextBuffer_Changed);
_view.TextBuffer.PostChanged += new EventHandler(TextBuffer_PostChanged);
}
The Changed event is called every time an edit has been made (e.g. typing a char, pasting code or programmatical changes). Because it also reacts on programmatical changes I use a bool determining if our extension or the user / anything else is changing the code at the moment and call my custom FormatCode() method only if our extension is not already editing. Otherwise you'll recursively call this method which would crash Visual Studio:
private void TextBuffer_Changed(object sender, TextContentChangedEventArgs e)
{
if (!_isChangingText)
{
_isChangingText = true;
FormatCode(e);
}
}
We have to reset this bool member variable in the PostChanged event handler again to false.
Let's pass the event args of the Changed event to our custom FormatCode method because they contain what has changed between the last edit and now. Those edits are stored in the array e.Changes of the type INormalizedTextChangeCollection (s. the link at the end of my post for more information about this type). We loop through all those edits and call our custom HandleChange method with the new text which this edit has produced.
private void FormatCode(TextContentChangedEventArgs e)
{
if (e.Changes != null)
{
for (int i = 0; i < e.Changes.Count; i++)
{
HandleChange(e.Changes[0].NewText);
}
}
}
In the HandleChange method we could actually scan for keywords to handle those in a specific way (remember, you have to parse any code on yourself!) - but here we just dumbly add "Hello" to the start of the file for testing purposes. E.g. we have to change the TextBuffer of our editor instance. To do so, we need to create an ITextEdit object with which we can manipulate text and apply it's changes afterwards. The code is pretty self-explaining:
private void HandleChange(string newText)
{
ITextEdit edit = _view.TextBuffer.CreateEdit();
edit.Insert(0, "Hello");
edit.Apply();
}
When compiling this add-in, an experimental hive of Visual Studio starts up with only our extension loaded. Create a new C# file and start typing to see the results.
I hope this gives you some ideas how to continue in this topic. I have to explore it myself now.
I highly recommend the documentation of the text model of the editor on MSDN to get hints about how you could do this and that.
http://msdn.microsoft.com/en-us/library/dd885240.aspx#textmodel
Footnotes
[*] Note that Visual Studio 2015 or newer come with the Rosyln Compiler Platform, which indeed already analyzes C# and VB.NET files for you (and probably other pre-installed languages too) and exposes their hierarchical syntactical structure, but I'm not an expert in this topic yet to give an answer on how to use these new services. The basic progress of starting an editor extension stays the same as described in this answer anyway. Be aware that - if you use these services - you will become dependent on Visual Studio 2015+, and the extension will not work in earlier versions.
just have a look at the "Getting started with Editor extensions" site on the MSDN http://msdn.microsoft.com/en-us/library/dd885122.aspx
Thorsten

Categories