I want to show c# source code with syntax highlighting and theme coloring inside a wpf control. This is for preview only and I don't need any editing capabilities.
I found some code samples on how to embed a code editor which receives a file path to load.
I loaded it with a temp file I created - and it works, well almost...
The problem is that the loaded code have parsing errors which shows up in the error list.
Is there a way to set those errors to not appear in the error list?
Here is the code:
IVsInvisibleEditorManager invisibleEditorManager = (IVsInvisibleEditorManager)ServiceProvider.GlobalProvider.GetService(typeof(SVsInvisibleEditorManager));
ErrorHandler.ThrowOnFailure(invisibleEditorManager.RegisterInvisibleEditor(csTempFilePath, pProject: null,dwFlags: (uint)_EDITORREGFLAGS.RIEF_ENABLECACHING,
pFactory: null, ppEditor: out this.invisibleEditor));
//The doc data is the IVsTextLines that represents the in-memory version of the file we opened in our invisibe editor, we need
//to extract that so that we can create our real (visible) editor.
IntPtr docDataPointer = IntPtr.Zero;
Guid guidIVSTextLines = typeof(IVsTextLines).GUID;
ErrorHandler.ThrowOnFailure(this.invisibleEditor.GetDocData(fEnsureWritable: 1, riid: ref guidIVSTextLines, ppDocData: out docDataPointer));
try
{
IVsTextLines docData = (IVsTextLines)Marshal.GetObjectForIUnknown(docDataPointer);
//Get the component model so we can request the editor adapter factory which we can use to spin up an editor instance.
IComponentModel componentModel = (IComponentModel)ServiceProvider.GlobalProvider.GetService(typeof(SComponentModel));
IVsEditorAdaptersFactoryService editorAdapterFactoryService = componentModel.GetService<IVsEditorAdaptersFactoryService>();
//Create a code window adapter.
this.codeWindow = editorAdapterFactoryService.CreateVsCodeWindowAdapter(OleServiceProvider);
IVsCodeWindowEx codeWindowEx = (IVsCodeWindowEx)this.codeWindow;
INITVIEW[] initView = new INITVIEW[1];
codeWindowEx.Initialize((uint)_codewindowbehaviorflags.CWB_DISABLESPLITTER,
VSUSERCONTEXTATTRIBUTEUSAGE.VSUC_Usage_Filter,
szNameAuxUserContext: "",
szValueAuxUserContext: "",
InitViewFlags: 0,
pInitView: initView);
ErrorHandler.ThrowOnFailure(this.codeWindow.SetBuffer((IVsTextLines)docData));
//Get our text view for our editor which we will use to get the WPF control that hosts said editor.
ErrorHandler.ThrowOnFailure(this.codeWindow.GetPrimaryView(out this.textView));
//Get our WPF host from our text view (from our code window).
IWpfTextViewHost textViewHost = editorAdapterFactoryService.GetWpfTextViewHost(this.textView);
textViewHost.TextView.Options.SetOptionValue(DefaultTextViewHostOptions.ChangeTrackingId, false);
textViewHost.TextView.Options.SetOptionValue(DefaultTextViewOptions.ViewProhibitUserInputId, true);
var dte = ContainerFactory.GetContainer().Resolve<DTE2>();
var projectItem = dte.Solution.FindProjectItem(csTempFilePath);
projectItem.Properties.Item("BuildAction").Value = prjBuildAction.prjBuildActionNone;
return textViewHost.HostControl;
}
finally
{
if (docDataPointer != IntPtr.Zero)
{
//Release the doc data from the invisible editor since it gave us a ref-counted copy.
Marshal.Release(docDataPointer);
}
}
I've tried to remove the errors from the error list manually. But it didn't work - I think it's because i can only remove errors that I added previously. Here is the code I tried using to remove the errors:
public void RemoveTempFileErrors()
{
var provider = new ErrorListProvider(ServiceProvider.GlobalProvider)
{
ProviderName = "MyProvider",
ProviderGuid = new Guid("41C0915D-A0F4-42B2-985F-D1CC5F65BFFC") // my provider guid
};
var vsTaskList1 = (IVsTaskList) Package.GetGlobalService(typeof (IVsTaskList));
uint providerCookie;
vsTaskList1.RegisterTaskProvider(provider, out providerCookie);
vsTaskList1.RefreshTasks(providerCookie);
var vsTaskList2 = (IVsTaskList2)Package.GetGlobalService(typeof(IVsTaskList));
provider.SuspendRefresh();
IVsEnumTaskItems enumerator;
vsTaskList1.EnumTaskItems(out enumerator);
IVsTaskItem[] arr = new IVsTaskItem[1];
while (enumerator.Next(1, arr, null) == 0)
{
string doc;
arr[0].Document(out doc);
if (doc == csTempFilePath)
{
vsTaskList2.RemoveTasks(providerCookie, 1, arr);
}
}
provider.ResumeRefresh();
provider.Refresh();
vsTaskList1.UnregisterTaskProvider(providerCookie);
}
I solved it partially -
The parsing errors were caused because the code was a method without a class. So i wrapped the method in a class and used an elision buffer to show only the method without the wrapper class
The elision buffer code goes like this:
var subsetSnapshot = new SnapshotSpan(textSnapshot.Lines.First().EndIncludingLineBreak, textSnapshot.Lines.Last().Start);
var projectionBufferFactory = componentModel.GetService<IProjectionBufferFactoryService>();
var projBuffer = projectionBufferFactory.CreateElisionBuffer(null,
new NormalizedSnapshotSpanCollection(subsetSnapshot), ElisionBufferOptions.None);
IVsTextBuffer bufferAdapter = editorAdapterFactoryService.CreateVsTextBufferAdapterForSecondaryBuffer(OleServiceProvider, projBuffer);
projTextView = editorAdapterFactoryService.CreateVsTextViewAdapter(OleServiceProvider);
projTextView.Initialize((IVsTextLines)bufferAdapter, IntPtr.Zero,
(uint)TextViewInitFlags.VIF_HSCROLL | (uint)TextViewInitFlags.VIF_VSCROLL | (uint)TextViewInitFlags3.VIF_NO_HWND_SUPPORT,
new[] { new INITVIEW { fSelectionMargin = 0, fWidgetMargin = 0, fVirtualSpace = 0, fDragDropMove = 0 } };
IWpfTextViewHost projTextViewHost = editorAdapterFactoryService.GetWpfTextViewHost(projTextView);
Related
Github link for the sample code I'm using
In the AdaptiveBot.cs file,
It creates a list of all the prompts available and takes user input and runs the specified prompt.
I want to modify it such that it loads only one dialog(There are 7 prompts in the sample folder and it gives a choice to load any one )
How would I go about to load only one dialog, for example just the MultiTurnPromptBot is needed to be loaded and the rest are not needed.
private void LoadDialogs()
{
System.Diagnostics.Trace.TraceInformation("Loading resources...");
//For this sample we enumerate all of the .main.dialog files and build a ChoiceInput as our rootidialog.
this.dialogManager = new DialogManager(CreateChoiceInputForAllMainDialogs());
this.dialogManager.UseResourceExplorer(this.resourceExplorer);
this.dialogManager.UseLanguageGeneration();
System.Diagnostics.Trace.TraceInformation("Done loading resources.");
}
private AdaptiveDialog CreateChoiceInputForAllMainDialogs()
{
var dialogChoices = new List<Choice>();
var dialogCases = new List<Case>();
foreach (var resource in this.resourceExplorer.GetResources(".dialog").Where(r => r.Id.EndsWith(".main.dialog")))
{
var name = Path.GetFileNameWithoutExtension(Path.GetFileNameWithoutExtension(resource.Id));
dialogChoices.Add(new Choice(name));
var subDialog = resourceExplorer.LoadType<AdaptiveDialog>(resource);
dialogCases.Add(new Case($"{name}", new List<Dialog>() { subDialog }));
}
var dialog = new AdaptiveDialog()
{
AutoEndDialog = false,
Triggers = new List<OnCondition>() {
new OnBeginDialog() {
Actions = new List<Dialog>() {
new ChoiceInput() {
Prompt = new ActivityTemplate("What declarative sample do you want to run?"),
Property = "conversation.dialogChoice",
AlwaysPrompt = true,
Style = ListStyle.List,
Choices = new ChoiceSet(dialogChoices)
},
new SendActivity("# Running ${conversation.dialogChoice}.main.dialog"),
new SwitchCondition(){
Condition = "conversation.dialogChoice",
Cases = dialogCases
},
new RepeatDialog()
}
}
}
};
return dialog;
}
You can see that LoadDialogs is instantiating a dialog manager by passing an adaptive dialog into its constructor. So instead of creating the root dialog that starts all the other dialogs, you can just pass in one of those dialogs as the root dialog since they're all adaptive dialogs anyway. You can see that the declarative dialog files are loaded like this:
this.resourceExplorer.GetResources(".dialog")
And then the adaptive dialog instances are created out of them like this:
var subDialog = resourceExplorer.LoadType<AdaptiveDialog>(resource);
So you can do something like this:
private void LoadDialogs()
{
System.Diagnostics.Trace.TraceInformation("Loading resources...");
//For this sample we enumerate all of the .main.dialog files and build a ChoiceInput as our rootidialog.
//this.dialogManager = new DialogManager(CreateChoiceInputForAllMainDialogs());
this.dialogManager = new DialogManager(this.resourceExplorer.LoadType<AdaptiveDialog>(this.resourceExplorer.GetResource("MultiTurnPrompt.main.dialog")));
this.dialogManager.UseResourceExplorer(this.resourceExplorer);
this.dialogManager.UseLanguageGeneration();
System.Diagnostics.Trace.TraceInformation("Done loading resources.");
}
TL;DR: Replace this line:
this.dialogManager = new DialogManager(CreateChoiceInputForAllMainDialogs());
With this line:
this.dialogManager = new DialogManager(this.resourceExplorer.LoadType<AdaptiveDialog>(this.resourceExplorer.GetResource("MultiTurnPrompt.main.dialog")));
I'm working from the docs on trying to create a sheet with a view on it using the Revit API in C#
here is the docs URL link. You can find the code at the bottom in the first C# block.
I get a red squiggly under the view3D.Id:
Viewport.Create(doc, viewSheet.Id, view3D.Id, new XYZ(location.U, location.V, 0));
I can't find that it was deprecated nor can I figure out how to resolve it. I'm a bit confused about why it's trying to grab its own elementID. Also, just getting into the revit-API. it seems like "views" in Revit are called "viewports" in the API. i need to read more on this.
here is the entire code block:
private void CreateSheetView(Autodesk.Revit.DB.Document document, View3D view3D)
{
// Get an available title block from document
FilteredElementCollector collector = new FilteredElementCollector(document);
collector.OfClass(typeof(FamilySymbol));
collector.OfCategory(BuiltInCategory.OST_TitleBlocks);
FamilySymbol fs = collector.FirstElement() as FamilySymbol;
if (fs != null)
{
using (Transaction t = new Transaction(document, "Create a new ViewSheet"))
{
t.Start();
try
{
// Create a sheet view
ViewSheet viewSheet = ViewSheet.Create(document, fs.Id);
if (null == viewSheet)
{
throw new Exception("Failed to create new ViewSheet.");
}
// Add passed in view onto the center of the sheet
UV location = new UV((viewSheet.Outline.Max.U - viewSheet.Outline.Min.U) / 2,
(viewSheet.Outline.Max.V - viewSheet.Outline.Min.V) / 2);
//viewSheet.AddView(view3D, location);
Viewport.Create(document, viewSheet.Id, view3D.Id, new XYZ(location.U, location.V, 0));
^ERROR HAPPENS IN LINE ABOVE AT view3D.Id
// Print the sheet out
if (viewSheet.CanBePrinted)
{
TaskDialog taskDialog = new TaskDialog("Revit");
taskDialog.MainContent = "Print the sheet?";
TaskDialogCommonButtons buttons = TaskDialogCommonButtons.Yes | TaskDialogCommonButtons.No;
taskDialog.CommonButtons = buttons;
TaskDialogResult result = taskDialog.Show();
if (result == TaskDialogResult.Yes)
{
viewSheet.Print();
}
}
t.Commit();
}
catch
{
t.RollBack();
}
}
}
}
The Building Coder discussion of exact viewport positioning includes some woking sample calls to ViewSheet.Create and Viewport.Create.
I am creating a designer surface and loading the controls to a runtime.
I am having issues when deserializing/loading the controls to the runtime.
All methods I have tried seem to have some type of issue.
Issued faced for example:
Controls are still bound of the design-time
Not all properties deserialize with all the properties, namely nested properties.
Control associations does seem to be followed, i.e. Button in a Panel, will not be in the panel anymore, even though the property is still the parent after loading.
I have created a sample Project on git here: Surface Designer Test
There are the main code snippets:
Serialization from the design-time
private void LoadRuntime(int type)
{
var controls = surface.ComponentContainer.Components;
SerializationStore data = (SerializationStore)surface.
_designerSerializationService.Serialize(controls);
MemoryStream ms = new MemoryStream();
data.Save(ms);
SaveData.Data = ms.ToArray();
SaveData.LoadType = type;
new RuntimeForm().Show();
}
public object Serialize(System.Collections.ICollection objects)
{
ComponentSerializationService componentSerializationService =
_serviceProvider.GetService(typeof(ComponentSerializationService)) as
ComponentSerializationService;
SerializationStore returnObject = null;
using (SerializationStore serializationStore =
componentSerializationService.CreateStore())
{
foreach (object obj in objects)
{
if (obj is Control control)
{
componentSerializationService.SerializeAbsolute(serializationStore, obj);
}
returnObject = serializationStore;
}
}
return returnObject;
}
Deserialization in runtime
Here is attempt with reflection:
MemoryStream ms = new MemoryStream(SaveData.Data);
Designer d = new Designer();
var controls = d._designerSerializationService.Deserialize(ms);
ms.Close();
if (SaveData.LoadType == 1)
{
foreach (Control cont in controls)
{
var ts = Assembly.Load(cont.GetType().Assembly.FullName);
var o = ts.GetType(cont.GetType().FullName);
Control controlform = (Control)Activator.CreateInstance(o);
PropertyInfo[] controlProperties = cont.GetType().GetProperties();
foreach (PropertyInfo propInfo in controlProperties)
{
if (propInfo.CanWrite)
{
if (propInfo.Name != "Site" && propInfo.Name != WindowTarget")
{
try
{
var obj = propInfo.GetValue(cont, null);
propInfo.SetValue(controlform, obj, null);
}
catch { }
}
else { }
}
}
Controls.Add(controlform);
}
}
Here is attempt with loading controls directly (still bound to the design-time):
MemoryStream ms = new MemoryStream(SaveData.Data);
Designer d = new Designer();
var controls = d._designerSerializationService.Deserialize(ms);
foreach (Control cont in controls)
Controls.Add(cont);
I feel like I am missing a concept from the System.ComponentModel.Design framework.
I also do not believe there is a need to write a custom serializer for each control, as surely the already have this has Visual Studio is able to serialize all their properties as they are changed in the PropertyGrid and load them back when you run the program.
I'd love to serialize the designer into a .cs file, but how? How do you serialize controls/form and changed properties to a file like the VS designer, I tried and looked only to find xml and binary serializer. My ideal solution would be build a designer.cs with the CodeDom.
What is the correct way do accomplish this serialization between design-time and run-time?
Assuming you have a DesignSurface to show a Form as root component of the designer and having some components created at run-time by using CreateComponent method of IDesignerHost, here is how I approach the problem:
Get an instance of IDesignerHost from DesignSurface
Create new DesignerSerializationManager
Get an instance of TypeCodeDomSerializer from serialization manager
Serialize the RootComponent of the IDesignerHost
Create an instance of CSharpCodeProvider
Generate code by calling GenerateCodeFromType and passing the serialized root component.
You can also extend the example a bit and use ISelectionService to get notified about selected components and change properties at run-time using a PropertyGrid:
Example - Generate C# code from DesignSurface at runtime
Here in this example, I'll show how you can host a windows forms designer at run-time and design a form containing some controls and components and generate C# code at run-time and run the generated code.
Please note: It's not a production code and it's just an example as a
proof of concept.
Create the DesignSurface and host the designer
You can create the design surface like this:
DesignSurface designSurface;
private void Form1_Load(object sender, EventArgs e)
{
designSurface = new DesignSurface(typeof(Form));
var host = (IDesignerHost)designSurface.GetService(typeof(IDesignerHost));
var root = (Form)host.RootComponent;
TypeDescriptor.GetProperties(root)["Name"].SetValue(root, "Form1");
root.Text = "Form1";
var button1 = (Button)host.CreateComponent(typeof(Button), "button1");
button1.Text = "button1";
button1.Location = new Point(8, 8);
root.Controls.Add(button1);
var timer1 = (Timer)host.CreateComponent(typeof(Timer), "timer1");
timer1.Interval = 2000;
var view = (Control)designSurface.View;
view.Dock = DockStyle.Fill;
view.BackColor = Color.White;
this.Controls.Add(view);
}
Generate C# code using TypeCodeDomSerializer and CSharpCodeProvider
This is how I generate code from design surface:
string GenerateCSFromDesigner(DesignSurface designSurface)
{
CodeTypeDeclaration type;
var host = (IDesignerHost)designSurface.GetService(typeof(IDesignerHost));
var root = host.RootComponent;
var manager = new DesignerSerializationManager(host);
using (manager.CreateSession())
{
var serializer = (TypeCodeDomSerializer)manager.GetSerializer(root.GetType(),
typeof(TypeCodeDomSerializer));
type = serializer.Serialize(manager, root, host.Container.Components);
type.IsPartial = true;
type.Members.OfType<CodeConstructor>()
.FirstOrDefault().Attributes = MemberAttributes.Public;
}
var builder = new StringBuilder();
CodeGeneratorOptions option = new CodeGeneratorOptions();
option.BracingStyle = "C";
option.BlankLinesBetweenMembers = false;
using (var writer = new StringWriter(builder, CultureInfo.InvariantCulture))
{
using (var codeDomProvider = new CSharpCodeProvider())
{
codeDomProvider.GenerateCodeFromType(type, writer, option);
}
return builder.ToString();
}
}
For example:
var code = GenerateCSFromDesigner(designSurface);
Run the code sing CSharpCodeProvider
Then to run it:
void Run(string code, string formName)
{
var csc = new CSharpCodeProvider();
var parameters = new CompilerParameters(new[] {
"mscorlib.dll",
"System.Windows.Forms.dll",
"System.dll",
"System.Drawing.dll",
"System.Core.dll",
"Microsoft.CSharp.dll"});
parameters.GenerateExecutable = true;
code = $#"
{code}
public class Program
{{
[System.STAThread]
static void Main()
{{
System.Windows.Forms.Application.EnableVisualStyles();
System.Windows.Forms.Application.SetCompatibleTextRenderingDefault(false);
System.Windows.Forms.Application.Run(new {formName}());
}}
}}";
var results = csc.CompileAssemblyFromSource(parameters, code);
if (!results.Errors.HasErrors)
{
System.Diagnostics.Process.Start(results.CompiledAssembly.CodeBase);
}
else
{
var errors = string.Join(Environment.NewLine,
results.Errors.Cast<CompilerError>().Select(x => x.ErrorText));
MessageBox.Show(errors);
}
}
For example:
Run(GenerateCSFromDesigner(designSurface), "Form1");
I have a situation where a user can upload a word document which contains placeholders for certain properties (i.e. in MS Word the user has gone to Insert > Quick Parts > Document Properties and chosen a property). The specific properties I want to support are Title, Author, Company and Publish Date.
Title and Author are set as Package Properties, and Company is set as an Extended File Property. These are set with the below code, which works correctly:
private static void SetDocumentProperties(ReportTemplateModel model, WordprocessingDocument wordDocument)
{
//these properties always exist
wordDocument.PackageProperties.Title = model.Title;
wordDocument.PackageProperties.Creator = model.Author;
wordDocument.PackageProperties.Created = DateTime.Now;
wordDocument.PackageProperties.Modified = DateTime.Now;
//these properties can be null
if (wordDocument.ExtendedFilePropertiesPart == null)
{
wordDocument.AddNewPart<ExtendedFilePropertiesPart>();
}
if (wordDocument.ExtendedFilePropertiesPart.Properties == null)
{
wordDocument.ExtendedFilePropertiesPart.Properties = new Properties(new Company(model.SiteName));
}
else
{
wordDocument.ExtendedFilePropertiesPart.Properties.Company = new Company(model.SiteName);
}
}
My problem is that I can't work out how the set the Publish Date property. I have tried adding it as a Custom File Property using the below code (which is adapted from https://www.snip2code.com/Snippet/292005/WDSetCustomProperty), but this does not work. I've read a few things about setting custom properties, but I'm confused how they're meant to work. I'm also unsure if the Publish Date should actually be set as a custom property, or some other type of property.
var customProps = wordDocument.CustomFilePropertiesPart;
if (customProps == null)
{
customProps = wordDocument.AddCustomFilePropertiesPart();
customProps.Properties = new DocumentFormat.OpenXml.CustomProperties.Properties();
}
var properties1 = new DocumentFormat.OpenXml.CustomProperties.Properties();
//I have tried both of these lines, neither worked.
//properties1.AddNamespaceDeclaration("op", "http://schemas.openxmlformats.org/officeDocument/2006/custom-properties");
properties1.AddNamespaceDeclaration("vt", "http://schemas.openxmlformats.org/officeDocument/2006/docPropsVTypes");
var customDocumentProperty1 = new DocumentFormat.OpenXml.CustomProperties.CustomDocumentProperty()
{
FormatId = "{D5CDD505-2E9C-101B-9397-08002B2CF9AE}",
PropertyId = 2,
Name = "Publish Date"
};
customDocumentProperty1.Append(new DocumentFormat.OpenXml.VariantTypes.VTLPWSTR { Text = DateTime.Today.ToShortDateString() });
properties1.Append(customDocumentProperty1);
part.Properties = properties1;
What type of property should the Publish Date be set as, and what is the right syntax for setting this?
Update: I have found that Publish Date is a CoverPageProperty which can be created using the below snippet, but I still haven't found how to set it correctly within the document.
var coverPageProps = new DocumentFormat.OpenXml.Office.CoverPageProps.CoverPageProperties
{
PublishDate = new PublishDate(DateTime.Today.ToShortDateString())
};
Adding the below code to my SetDocumentProperties method seems to work. I must admit I don't fully understand the below code, so any explanation would still be welcome. Additionally, if anyone has a solution which doesn't include writing XML as a string inside C# I would much prefer to avoid that.
const string publishDatePartId = "publishDatePart";
var publishDateXmlPart = wordDocument.MainDocumentPart.AddNewPart<CustomXmlPart>("application/xml", publishDatePartId);
var writer = new XmlTextWriter(publishDateXmlPart.GetStream(FileMode.Create), System.Text.Encoding.UTF8);
writer.WriteRaw($"<CoverPageProperties xmlns=\"http://schemas.microsoft.com/office/2006/coverPageProps\">" +
$"<PublishDate>{DateTime.Today.ToShortDateString()}</PublishDate>" +
$"</CoverPageProperties>");
writer.Flush();
writer.Close();
var customXmlPropertiesPart = publishDateXmlPart.AddNewPart<CustomXmlPropertiesPart>(publishDatePartId);
customXmlPropertiesPart.DataStoreItem = new DocumentFormat.OpenXml.CustomXmlDataProperties.DataStoreItem()
{
//I don't know what this ID is, but it seems to somehow relate to the Publish Date
ItemId = "{55AF091B-3C7A-41E3-B477-F2FDAA23CFDA}"
};
I'm working on a project where we've split up C# code into functions and stored these functions within IElisonBuffers. I've got Intellisense hooked up, and the buffers interact with other extensions fine as shown below:
However, I cannot get syntax highlighting to work within these editors.
I embed these editors via the following steps:
Create an IVsInvisibleEditor for the file.
Get the IVsTextLines for this IVsInvisibleEditor
Create an IVsCodeWindow and set the buffer for this IVsCodeWindow to be the IVsTextLines from the IVsInvisibleEditor
Get an IWpfTextViewHost from this code window. This brings me back to "WPF Land" where I'm able to interact with traditional spans.
Create a SnapshotSpan of the IWpfTextViewHost's text view. This SnapshotSpan contains a single function.
Create an IElisionBuffer containing the SnapshotSpan.
Create an IVsTextBuffer via IVsEditorAdaptersFactoryService.CreateVsTextBufferAdapterForSecondaryBuffer() passing in the IElisionBuffer.
Now I cast the IVsTextBuffer to IVsTextLines and call SetLanguageServiceID() passing in the C# GUID: 694DD9B6-B865-4C5B-AD85-86356E9C88DC.
I double check that it was set correctly via GetLanguageServiceID() and everything looks alright.
I create an IVsTextView and initialize it with the new IVsTextBuffer.
I then get the IWpfTextViewHost for this IVsTextView.
Are there any special steps that need to be taken care of when setting up the language service ID for an IElisionBuffer?
For the sake of completeness this is the code I'm using:
public CustomEditorViewModel CreateEditor(string filePath, int start, int end) {
IVsInvisibleEditor invisibleEditor;
ErrorHandler.ThrowOnFailure(this._InvisibleEditorManager.RegisterInvisibleEditor(
filePath
, pProject: null
, dwFlags: (uint)_EDITORREGFLAGS.RIEF_ENABLECACHING
, pFactory: null
, ppEditor: out invisibleEditor));
var docDataPointer = IntPtr.Zero;
Guid guidIVsTextLines = typeof(IVsTextLines).GUID;
ErrorHandler.ThrowOnFailure(
invisibleEditor.GetDocData(
fEnsureWritable: 1
, riid: ref guidIVsTextLines
, ppDocData: out docDataPointer));
IVsTextLines docData = (IVsTextLines)Marshal.GetObjectForIUnknown(docDataPointer);
//Createa a code window adapter
var codeWindow = _EditorAdapterFactory.CreateVsCodeWindowAdapter(VisualStudioServices.OLEServiceProvider);
//Associate our IVsTextLines with our new code window
ErrorHandler.ThrowOnFailure(codeWindow.SetBuffer(docData));
//Get our text view for our editor which we will use to get the WPF control that hosts that editor.
IVsTextView textView;
ErrorHandler.ThrowOnFailure(codeWindow.GetPrimaryView(out textView));
//This is our TextViewHost
//It transports us back into the land of WPF
IWpfTextViewHost textViewHost = _EditorAdapterFactory.GetWpfTextViewHost(textView);
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//Now we need to subset TextBuffer somehow...
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
int length = end - start;
SnapshotSpan subsetSnapshot = new SnapshotSpan(textViewHost.TextView.TextSnapshot, start, length);
var CSharpType = _contentTypeRegistry.GetContentType("CSharp");
var projBuffer = _ProjectionBufferFactory.CreateElisionBuffer(
null
, new NormalizedSnapshotSpanCollection(subsetSnapshot)
, ElisionBufferOptions.None
,CSharpType);
IVsTextBuffer bufferAdapter = _EditorAdapterFactory.CreateVsTextBufferAdapterForSecondaryBuffer(VisualStudioServices.OLEServiceProvider, projBuffer);
//My attempt at getting syntax coloring to work:
Guid CSharpLanguageServiceId = new Guid("694DD9B6-B865-4C5B-AD85-86356E9C88DC");
IVsTextLines buffer = (IVsTextLines)bufferAdapter;
buffer.SetLanguageServiceID(ref CSharpLanguageServiceId);
IVsTextView projTextView = _EditorAdapterFactory.CreateVsTextViewAdapter(VisualStudioServices.OLEServiceProvider);
projTextView.Initialize(
(IVsTextLines)bufferAdapter
, IntPtr.Zero
, (uint)TextViewInitFlags.VIF_HSCROLL | (uint)TextViewInitFlags.VIF_VSCROLL | (uint)TextViewInitFlags3.VIF_NO_HWND_SUPPORT,
new[] { new INITVIEW { fSelectionMargin = 0, fWidgetMargin = 0, fVirtualSpace = 0, fDragDropMove = 0 } }
);
return _EditorAdapterFactory.GetWpfTextViewHost(projTextView);
}
Make the content type of your elision buffer be, or derive from, the content type "projection". That's the hint that taggers should project through that.