How to get IEditorOperations from IVsTextView? - visual-studio

I'm developing my first Visual Studio (2015 Community) Command Menu and I'm trying to get access to IEditorOperations to delete text, send backspace etc. but I'm not sure how to. I can do:
var Service = Provider.GetService(typeof(IEditorOperationsFactoryService)) as IEditorOperationsFactoryService;
Service.GetEditorOperations(???);
I'm not sure what to pass in the ??? since I don't have access to an ITextView instead what I have is a IVsTExtView via:
IVsTextView View;
IVsTextManager Manager = (IVsTextManager)ServiceProvider.GetService(typeof(SVsTextManager));
int MustHaveFocus = 1;
Manager.GetActiveView(MustHaveFocus, null, out View);
When creating the Command Menu, VS generates a template for me with a private ctor creating the command service, binding it to the command set id etc. An overridden Initialize method, and a bunch of properties.
Any ideas?
EDIT: After help from Sergey, I managed to get a bit further. But now I get a null when I try to get the IEditorOperationsFactoryService, all the other values are valid.
static IEditorOperations GetEditorService(IServiceProvider Provider, IVsTextView VsView)
{
IEditorOperations Result;
try
{
var Model = (IComponentModel)Provider.GetService(typeof(SComponentModel));
var Editor = (IEditorOperationsFactoryService)Provider.GetService(typeof(IEditorOperationsFactoryService)); // returns null
var Adaptor = Model.GetService<IVsEditorAdaptersFactoryService>();
IWpfTextView TextView = Adaptor.GetWpfTextView(VsView);
Result = Editor.GetEditorOperations(TextView);
}
catch (Exception e)
{
System.Windows.Forms.MessageBox.Show(e.ToString());
Result = null;
}
return (Result);
}

You can get IEditorOperationsFactoryService instance from variable named Model, like this:
var Model = (IComponentModel)this.ServiceProvider.GetService(typeof(SComponentModel));
var Editor = (IEditorOperationsFactoryService)Model.GetService<IEditorOperationsFactoryService>();

You can get IWpfTextView (that implements ITextView) from IVsTextView using:
IVsTextView textView = ...;
IWpfTextView v = GetEditorAdaptersFactoryService().GetWpfTextView(textView);
private Microsoft.VisualStudio.Editor.IVsEditorAdaptersFactoryService GetEditorAdaptersFactoryService()
{
Microsoft.VisualStudio.ComponentModelHost.IComponentModel componentModel =
(Microsoft.VisualStudio.ComponentModelHost.IComponentModel)serviceProvider.GetService(
typeof(Microsoft.VisualStudio.ComponentModelHost.SComponentModel));
return componentModel.GetService<Microsoft.VisualStudio.Editor.IVsEditorAdaptersFactoryService>();
}

Related

There is a line above "List" and I get an error. How can i assign a clean "List"

void main() {
var urunler = new List(5);
urunler[0] = "Laptop";
urunler[1] = "Mouse";
urunler[2] = "Keyboard";
urunler[3] = "Monitor";
urunler[4] = "Mic";
print(urunler);
}
lib/main.dart:2:21: Error: Can't use the default List constructor. Try
using List.filled instead. var urunler = new List(5);
^ Failed to compile application.
The default 'List' constructor isn't available when null safety is
enabled.
Try this:
void main() {
var urunler = List<String>.filled(5,"",growable: false);
urunler[0] = "Laptop";
urunler[1] = "Mouse";
urunler[2] = "Keyboard";
urunler[3] = "Monitor";
urunler[4] = "Mic";
print(urunler);
}
https://api.dart.dev/stable/2.14.2/dart-core/List/List.filled.html
For a List, its better if you declare what kind of List you want to make. I dont think you can create a clean list because we need inital value for it, or you can create a blank list, and use a function to return the data inside. But from the code above, this is the best approach I can think right now.
List<String> urunler = ["Laptop", "Mouse", "Keyoboard"];

MvvmCross migration causing a Xamarin Custom iOS View Presenter issue

While creating a CustomIosViewPresenter (of type MvxIosViewPresenter), in MVVMCross 5.x, there was a Show override that I was able to use to get the IMvxIosView so as to update the UIViewController presentation style using the PresentationValues from the ViewModel.
I had this code and it worked:
// Worked before
public override void Show(IMvxIosView view, MvvmCross.ViewModels.MvxViewModelRequest request)
{
if (request.PresentationValues != null)
{
if (request.PresentationValues.ContainsKey("NavigationMode") &&
request.PresentationValues["NavigationMode"] == "WrapInModalWithNavController")
{
var vc = view as IModalPresentation;
vc.ModalPresentationAttribute = new MvxModalPresentationAttribute
{
WrapInNavigationController = true,
ModalPresentationStyle = UIModalPresentationStyle.OverFullScreen,
ModalTransitionStyle = UIModalTransitionStyle.CoverVertical
};
}
}
base.Show(view, request);
}
But after migrating to MvvmCross 7.1, the older override doesn't work anymore and I have to use this instead, but there is no view passed into the Show override, how do I get it?
I tried this code below, but view is null and it's not able to cast it this way var view = viewType as IMvxIosView;
// Doesn't work now
public override Task<bool> Show(MvxViewModelRequest request)
{
if (request.PresentationValues != null)
{
if (request.PresentationValues.ContainsKey("NavigationMode") &&
request.PresentationValues["NavigationMode"] == "WrapInModalWithNavController")
{
var viewsContainer = Mvx.IoCProvider.Resolve<IMvxViewsContainer>();
var viewType = viewsContainer.GetViewType(request.ViewModelType);
var view = viewType as IMvxIosView;
var vc = view as IModalPresentation;
vc.ModalPresentationAttribute = new MvxModalPresentationAttribute
{
WrapInNavigationController = true,
ModalPresentationStyle = UIModalPresentationStyle.OverFullScreen,
ModalTransitionStyle = UIModalTransitionStyle.CoverVertical
};
}
}
return base.Show(request);
}
The reason I need this is because without this function when I close the special flow of view controllers that need this, its not closing all the view controllers in that flow, it closes only one of them at a time.
What you would normally do with MvvmCross if you want to navigate within a Modal ViewController is firstly add a MvxModalPresentationAttribute to the modal that will host the rest of the navigation where you set WrapInNavigationController to true.
For the children, it would just be regular child navigation, no attributes needed.
If you then want to control how the modal is popping you would create your own MvxPresentationHint and register it in your presenter using AddPresentationHintHandler.
Then you would in your ViewModel where you want to change the presentation call NavigationService.ChangePresentation(your hint).
As for the Presentation Hint, it should probably just call CloseModalViewControllers and that would probably do what you want.
TLDR: Feel for the developers that will come after you and build stuff the right way
So I dug into the MvvmCross MvxIosViewPresenter source code and was able to use this new override CreateOverridePresentationAttributeViewInstance()
I needed the request object to see the presentation values so I updated the Show function that gets called before the other override as follows:
MvxViewModelRequest _request;
public override Task<bool> Show(MvxViewModelRequest request)
{
_request = request;
return base.Show(request);
}
And I was able to get the ViewController this way, in order to selectively present it as a modal:
{
var view = base.CreateOverridePresentationAttributeViewInstance(viewType);
if (_request.PresentationValues.ContainsKey("NavigationMode") &&
_request.PresentationValues["NavigationMode"] == "WrapInModalWithNavController")
{
var vc = view as IModalPresentation;
vc.ModalPresentationAttribute = new MvxModalPresentationAttribute
{
WrapInNavigationController = true,
ModalPresentationStyle = UIModalPresentationStyle.OverFullScreen,
ModalTransitionStyle = UIModalTransitionStyle.CoverVertical
};
return vc;
}
return view;
}
And then the closing of the modal was another challenge, that I was able to figure out using the TryCloseViewControllerInsideStack and ChangePresentation overrides

How do you programmatically run Static Code Analysis in Visual Studio 2017?

I'm working on a solution to localize legacy applications. I've written a Visual studio add-in using EnvDte that automates the process of setting the "Localizable" flag for every form in the solution to true, which is a critical step for extracting resources on form designers. I am now trying to deal with any text that is set programmatically, text that trigger the Globalization (CA13##) warnings.
designer.Visible = true;
var host = (IDesignerHost)designer.Object;
var provider = TypeDescriptor.GetProvider(host.RootComponent);
var typeDescriptor = provider.GetExtendedTypeDescriptor(host.RootComponent);
if (typeDescriptor == null)
continue;
var propCollection = typeDescriptor.GetProperties();
var propDesc = propCollection["Localizable"];
if (propDesc != null && host.RootComponent != null &&
(bool?)propDesc.GetValue(host.RootComponent) != true)
{
try
{
propDesc.SetValue(host.RootComponent, true);
}
catch (Exception ex)
{
// log the error
}
// save changes
}
I've been able to run it manually from the menu using: Analyze -> Run Code Analysis -> On Solution to get a list of issues, but I would like to automate this step with another add-in that runs and extracts the results.
Are there any resources that point to accessing the build warnings or the results of the code analysis?
Are there any solutions that already do this using EnvDte or Roslyn?
Ok, I've managed to glean enough information to put together the add-in. Put simply, you use _dte.ExecuteCommand()
Initialize the command:
// nothing to see here...
_package = package ?? throw new ArgumentNullException(nameof(package));
var commandService = ServiceProvider.GetService(typeof(IMenuCommandService)) as OleMenuCommandService;
if (commandService == null)
return;
_dte = (DTE2)ServiceProvider.GetService(typeof(DTE));
var menuCommandId = new CommandID(CommandSet, CommandId);
var menuItem = new MenuCommand(MenuItemCallback, menuCommandId);
commandService.AddCommand(menuItem);
_events = _dte.Events.BuildEvents;
// since static code analysis is a sort of build you need to hook into OnBuildDone
_events.OnBuildDone += OnBuildDone;
Trigger the analysis
private void MenuItemCallback(object sender, EventArgs e)
{
_dte.ExecuteCommand("Build.RunCodeAnalysisonSolution");
}
Extract errors in the OnBuildDone event
private void OnBuildDone(vsBuildScope scope, vsBuildAction action)
{
Dispatcher.CurrentDispatcher.InvokeAsync(new Action(() =>
{
_dte.ExecuteCommand("View.ErrorList", " ");
var errors = _dte.ToolWindows.ErrorList.ErrorItems;
for (int i = 1; i <= errors.Count; i++)
{
ErrorItem error = errors.Item(i);
var code = error.Collection.Item(1);
var item = new
{
error.Column,
error.Description,
error.ErrorLevel,
error.FileName,
error.Line,
error.Project
};
error.Navigate(); // you can navigate to the error if you wanted to.
}
});
}

Persistent Dashboard Widget Preferences

I'm building a Dashboard Widget and I'm attempting to store preferences that persist across "sessions" (i.e., a user closing the widget and opening it again).
I've tried:
function setEmail(event)
{
var preferenceKey = "email";
var preferenceValue = $F("email");
widget.setPreferenceForKey(preferenceValue, preferenceKey);
}
function getEmail() {
var preferenceForKey = "email";
preferenceForKey = widget.preferenceForKey(preferenceForKey);
return preferenceForKey;
}
This works fine for the current session, but if the widget is closed and opened again, the data is lost.
Thanks!
This seems to do the trick:
// Values you provide
var preferenceKey = "key"; // replace with the key for a preference
var preferenceValue = "value"; // replace with a preference to save
// Preference code
widget.setPreferenceForKey(preferenceValue, preferenceKey);

Is it possible to rename Outlook Category programmatically?

We are developing Outlook 2007 add-in. For testing outlook category renaming I've added the following code block
var session = Application.Session;
var categories = session.Categories;
var category1 = session.Categories[1];
//catefory1.Name is "Group1" before executing line below
category1.Name = "TEST!!!";
Marshal.ReleaseComObject(category1);
Marshal.ReleaseComObject(categories);
Marshal.ReleaseComObject(session);
to the end of add-in private void ThisAddIn_Startup(object sender, EventArgs e) method.
Category is renamed but if Outlook is closed, the above lines are commented, and outlook is started again - the category name is not "TEST!!!" as I expected. It is "Group1" as is was before renaming. Is it possible to rename outlook category "forever" by code? Microsoft.Office.Interop.Outlook.Category has no Save() or Update() or Persist() methods.
P.S. We are developing Outlook 2007 add-in using Visual Studio 2008, .net 3.5, C# 3.
The problem is reproduced with Outlook 2007 SP1 and SP2. Other outlook versions were not tested.
I have solved the problem (the problem itself seems to be Outlook 2007 bug) using a hack.
The following links helped me to create the hack (oops, not enough reputation to post more then 1 link):
http ://blogs.officezealot.com/legault/archive/2009/08/13/21577.aspx
http://www.officekb.com/Uwe/Forum.aspx/outlook-prog-addins/3142/Apply-Categories-to-other-users-Outlook-2007
http ://help.wugnet.com/office/set-master-category-list-Outlook-2007-ftopict1095935.html
http ://forums.slipstick.com/showthread.php?t=18189
http ://msdn.microsoft.com/en-us/library/ee203806%28EXCHG.80%29.aspx
The hack itself is show below:
using System;
using System.Text;
using System.Xml;
using System.IO;
using Microsoft.Office.Interop.Outlook;
namespace OutlookHack
{
public static class OutlookCategoryHelper
{
private const string CategoryListStorageItemIdentifier = "IPM.Configuration.CategoryList";
private const string CategoryListPropertySchemaName = #"http://schemas.microsoft.com/mapi/proptag/0x7C080102";
private const string CategoriesXmlElementNamespace = "CategoryList.xsd";
private const string XmlNamespaceAttribute = "xmlns";
private const string CategoryElement = "category";
private const string NameAttribute = "name";
public static void RenameCategory(string oldName, string newName, Application outlookApplication)
{
MAPIFolder calendarFolder = outlookApplication.Session.GetDefaultFolder(
OlDefaultFolders.olFolderCalendar);
StorageItem categoryListStorageItem = calendarFolder.GetStorage(
CategoryListStorageItemIdentifier, OlStorageIdentifierType.olIdentifyByMessageClass);
if (categoryListStorageItem != null)
{
PropertyAccessor categoryListPropertyAccessor = categoryListStorageItem.PropertyAccessor;
string schemaName = CategoryListPropertySchemaName;
try
{
// next statement raises Out of Memory error if property is too big
var xmlBytes = (byte[])categoryListPropertyAccessor.GetProperty(schemaName);
// the byte array has to be translated into a string and then the XML has to be parsed
var xmlReader = XmlReader.Create(new StringReader(Encoding.UTF8.GetString(xmlBytes)));
// xmlWriter will write new category list xml with renamed category
XmlWriterSettings settings = new XmlWriterSettings { Indent = true, IndentChars = ("\t") };
var stringWriter = new StringWriter();
var xmlWriter = XmlWriter.Create(stringWriter, settings);
xmlReader.Read(); // read xml declaration
xmlWriter.WriteNode(xmlReader, true);
xmlReader.Read(); // read categories
xmlWriter.WriteStartElement(xmlReader.Name, CategoriesXmlElementNamespace);
while (xmlReader.MoveToNextAttribute())
{
if (xmlReader.Name != XmlNamespaceAttribute) // skip namespace attr
{
xmlWriter.WriteAttributeString(xmlReader.Name, xmlReader.Value);
}
}
while (xmlReader.Read())
{
switch (xmlReader.NodeType)
{
case XmlNodeType.Element: // read category
xmlWriter.WriteStartElement(CategoryElement);
while (xmlReader.MoveToNextAttribute())
{
if ((xmlReader.Name == NameAttribute) && (xmlReader.Value == oldName))
{
xmlWriter.WriteAttributeString(NameAttribute, newName);
}
else
{
xmlWriter.WriteAttributeString(xmlReader.Name, xmlReader.Value);
}
}
xmlWriter.WriteEndElement();
break;
case XmlNodeType.EndElement: // categories ended
xmlWriter.WriteEndElement();
break;
}
}
xmlReader.Close();
xmlWriter.Close();
xmlBytes = Encoding.UTF8.GetBytes(stringWriter.ToString());
categoryListPropertyAccessor.SetProperty(schemaName, xmlBytes);
categoryListStorageItem.Save();
}
catch (OutOfMemoryException)
{
// if error is "out of memory error" then the XML blob was too big
}
}
}
}
}
This helper method must be called prior to category renaming, e.g.:
var session = Application.Session;
var categories = session.Categories;
var category1 = session.Categories[1];
//catefory1.Name is "Group1" before executing line below
OutlookCategoryHelper.RenameCategory(category1.Name, "TEST!!!", Application);
category1.Name = "TEST!!!";
Marshal.ReleaseComObject(category1);
Marshal.ReleaseComObject(categories);
Marshal.ReleaseComObject(session);
This is an Outlook bug introduces with Outlook 2007 SP2.
"Consider the following scenario. You have a custom application that can be run to create new categories in Outlook 2007.
You run the application to create a new category in Outlook 2007. Then, if you restart Outlook 2007, the category that you created is removed unexpectedly. This problem occurs after you install the Februarycumulative update or SP2."
There is a hotfix available since June 30, 2009:
http://support.microsoft.com/default.aspx/kb/970944/en
Regards,
Tim

Resources