Based on this Code I've build the basics of a function to give each user a predefined set of favorites.
However this particular code creates a new AOT element for each favorite of each user. I would like to configure the menu items manually and simply distribute them with the script.
How can I (in X++) get a reference to an existing \Menu Items\Display node and add that to an object of the Menu class?
This is what I have so far:
MyFavorites obj = new MyFavorites();
Menu menuNode;
MenuFunction mf;
TreeNode treeNode;
info("Applying favorites...");
menuNode = obj.getOrCreateRoot();
if (menuNode == null) return;
treeNode = menuNode.AOTfindChild("Administrator");
if (!treeNode)
{
menuNode.addSubmenu("Administrator");
treeNode = menuNode.AOTfindChild("Administrator");
info("Created submenu");
}
else info("Found submenu");
menuNode = treeNode;
// Here I need help. I don't want to recreate all these AOT nodes every time the script is run.
mf = new MenuFunction("Fav_AllUsers",MenuItemType::Display);
mf.AOTsave();
menuNode.addMenuitem(mf);
Here's a quick job I wrote that adds "SalesTable" menu to your favorites.
Also here's a link that shows how to copy favorites between users
A thing to note is the table SysPersonalization, which stores a blob of the data so you'll have to use either the object UserMenuList, Menu, or that table to accomplish what you want. This should get you started though.
static void Job4(Args _args)
{
TreeNode treeNode;
TreeNode menuToAdd = TreeNode::findNode(#"\Menu Items\Display\SalesTable");
TreeNodeIterator iterator;
UserMenuList userMenu;
Menu menuNode;
treeNode = infolog.userNode();
iterator = treeNode.AOTiterator();
treeNode = iterator.next();
if (treeNode)
{
userMenu = treeNode;
// find 'My Favorites' user menu;
treeNode = userMenu.AOTfindChild("#SYS95713");
// Note menuNode is a different object than userMenu
menuNode = treeNode;
menuNode.addMenuitem(menuToAdd);
}
}
Related
To make it clear, I'm creating a treeview that will instantiate itself after the user creates a folder and said folder will be added as treeitem.
I currently have this:
TreeView treeView = new TreeView();
// Create new folder
MenuItem menuItem1 = new MenuItem("Create New Folder");
menuItem1.setOnAction(e -> {
System.out.println("Please name your directory:");
Scanner in = new Scanner(System.in);
String strFolder = in. nextLine();
createFolder(strFolder); // Create folder
TreeItem rootFolder = new TreeItem(strFolder); // Create new TreeItem
treeView.setRoot(rootFolder); // Replace old folder with new one
// rootFolder.getChildren().add(rootFolder);
// rootItem.getChildren().add(rootFolder);
});
After the treeView, I declared a new Menu Item that which will trigger an event after being clicked on.
The event will ask the user for a name to use as the root folder for the treeView. Now thats working fine.
Now what I'm having troubles with, is how to create more folders inside the root folder created and display them as subfolders in the treeView?
So far my code only does replace the old root folder by the new one created. Instead of setting the root folder again, how can i make it so it just adds those folders inside the first one and display them - again - in the treeView as subfolders?
Did I explain myself?
Thanks.
Simply add TreeItem(s) to the child list of the TreeItem. The following example replaces the root, if no items are selected and otherwise adds the new item as a child of the selected one:
TreeView<String> treeView = new TreeView<>(); // never use raw type without good reason
// Create new folder
MenuItem menuItem1 = new MenuItem("Create New Folder");
menuItem1.setOnAction(e -> {
TextInputDialog dialog = new TextInputDialog(); // replacing console input with dialog here
dialog.setHeaderText("Please name your directory:");
String strFolder = dialog.showAndWait().orElse(null);
if (strFolder != null) {
TreeItem<String> newFolder = new TreeItem<>(strFolder); // Create new TreeItem
TreeItem<String> selection = treeView.getSelectionModel().getSelectedItem();
createFolder(strFolder); // Create folder ; TODO: make dependent on parent???
if (selection == null) {
treeView.setRoot(newFolder); // Replace old folder with new one
} else {
selection.getChildren().add(newFolder);
selection.setExpanded(true); // make sure we're able to see the new child
}
}
});
I'm trying to create my first extension for visual studio and so far I've been following this tutorial to get me started (http://www.diaryofaninja.com/blog/2014/02/18/who-said-building-visual-studio-extensions-was-hard).
Now I have a custom menu item appearing when I click on a file in the solution explorer.
What I need now for my small project is to get the path of the file selected in the solution explorer but I can't understand how can I do that.
Any help?
---------------------------- EDIT ------------------------------
As matze said, the answer is in the link I posted. I just didn't notice it when I wrote it.
In the meanwhile I also found another possible answer in this thread: How to get the details of the selected item in solution explorer using vs package
where I found this code:
foreach (UIHierarchyItem selItem in selectedItems)
{
ProjectItem prjItem = selItem.Object as ProjectItem;
string filePath = prjItem.Properties.Item("FullPath").Value.ToString();
//System.Windows.Forms.MessageBox.Show(selItem.Name + filePath);
return filePath;
}
So, here are two ways to get the path to the selected file(s) :)
For future reference:
//In your async method load the DTE
var dte2 = await ServiceProvider.GetGlobalServiceAsync(typeof(SDTE)) as DTE2;
var selectedItems = dte2.SelectItems;
if(selectedItems.MultiSelect || selectedItems.Count > 1){ //Use either/or
for(short i = 1; i <= selectedItems.Count; i++){
//Get selected item
var selectedItem = selectedItems[i];
//Get associated project item (selectedItem.ProjectItem
//If selectedItem is a project, then selectedItem.ProjectItem will be null,
//and selectedItem.Project will not be null.
var projectItem = selectedItem.ProjectItem;
//Get project for ProjectItem
var project = projectItem.ContainingProject;
// Or get project object if selectedItem is a project
var sproject = selectedItem.Project;
//Is selectedItem a physical folder?
var isFolder = projectItem.Kind == EnvDTE.Constants.vsProjectItemKindPhysicalFolder;
//Else, get item's folder
var itemFolder = new FileInfo(projectItem.Properties.Item("FullPath").ToString()).Directory;
//Find config file
var configFiles itemFolder.GetFiles("web.config");
var configfile = configFiles.length > 0 ? configFiles[0] : null;
//Turn config file into ProjectItem object
var configItem = dte2.solution.FindProjectItem(configFile.FullName);
}
}
I hope someone finds this helpful...
The article you mentioned already contains a solution for that.
Look for the menuCommand_BeforeQueryStatus method in the sample code. It uses the IsSingleProjectItemSelection method to obtain an IVsHierarchy object representing the project as well as the id of the selected item. It seems that you can safely cast the hierarchy to IVsProject and use it´s GetMkDocument function to query the item´s fullpath...
IVsHierarchy hierarchy = null;
uint itemid = VSConstants.VSITEMID_NIL;
if (IsSingleProjectItemSelection(out hierarchy, out itemid))
{
IVsProject project;
if ((project = hierarchy as IVsProject) != null)
{
string itemFullPath = null;
project.GetMkDocument(itemid, out itemFullPath);
}
}
I don´t want to copy the entire code from the article into this answer, but it might be of interest how the IsSingleProjectItemSelection function obtains the selected item; so I just add some notes instead which may guide into the right direction... The method uses the GetCurrentSelection method of the global IVsMonitorSelection service to query to the current selected item.
DataRow[] drowpar = dt.Select("Parent_Id=" + 0);
foreach (DataRow dr in drowpar)
{
MenuItem objMenuItem = new MenuItem();
objMenuItem.Text = dr["Page_Name"].ToString();
objMenuItem.NavigateUrl = dr["Page_Url"].ToString();
MenuBar.Items.Add(objMenuItem);
}
foreach (DataRow dr in dt.Select("Parent_Id >" + 0))
{
MenuItem objMenuItem = new MenuItem();
objMenuItem.Text = dr["Page_Name"].ToString();
objMenuItem.NavigateUrl = dr["Page_Url"].ToString();
//MenuBar.FindItem(dr["Parent_Id"].ToString()).ChildItems.Add(objMenuItem);
MenuBar.FindItem(dr["Parent_Id"].ToString()).ChildItems.Add(objMenuItem);
//MenuBar.Items.Add(objMenuItem);
}
i am binding asp.net menu control using database and getting this below in childitem binding to menu
Object reference not set to an instance of an object.
MenuBar.FindItem(dr["Parent_Id"].ToString()).ChildItems.Add(objMenuItem);
That error message only happens for specific situations, and the possible reasons are:
objMenuItem is null - which obviously in your code it is not
dr["Parent_Id"] is null, and calling ToString() causes the error
MenuBar.FindItem(dr["Parent_Id"].ToString()) - this isn't finding the item with the given parent ID
The ChildItems collection on the menu item is null
If you want to be really sure where the object is not null, then you can do the following:
var id = dr["Parent_ID"].ToString();
var menuItem = MenuBar.FindItem(id);
if (menuItem != null)
menuItem.ChildItems.Add(objMenuItem);
Having the code together masks where the actual error occurs. Note, there is one other scenario where i didn't account for, which is the error is within the MenuBar itself, and it's masked. Without seeing the full stack trace, it's hard to tell. If you can post that, we can isolate it further.
I want to insert values to many to many relation table
I'm using entity framework & linq. and I want to build up the Insert query (.net Framework 4)
following are the tables
Menus -
menu_id,
menu_name,
menu_desc
Cater - cater_id,
cater_name,
enable_ind
Relation table
Menu_Cater - menu_id,
cater_id
I have tried with couple of cases seems not working,
if there is a SIMPLE way of implementing this insert & delete
Assuming you have the Menu and Cater objects (from the dropdown list or however), simply:
create a Menu_Cater record
set it to insert on submit
submit changes
Demonstrated below:
VB.NET
Dim menu As Menu = GetSelectedMenu() ' However you get the Menu record
Dim cater As Cater = GetSelectedCater() ' However you get the Cater record
Dim relationship = New Menu_Cater()
' EITHER:
relationship.menu_id = menu.menu_id
relationship.cater_id = cater.cater_id
' OR:
' relationship.menu = menu
' relationship.cater = cater
Using db = new MyDataContext
db.Menu_Cater.InsertOnSubmit( relationship )
db.SubmitChanges()
End Using
C#
Menu menu = GetSelectedMenu(); // However you get the Menu record
Cater cater = GetSelectedCater(); // However you get the Cater record
Menu_Cater relationship = new Menu_Cater();
// EITHER:
relationship.menu_id = menu.menu_id;
relationship.cater_id = cater.cater_id;
// OR:
// relationship.menu = menu
// relationship.cater = cater
using (db = new MyDataContext()) {
db.Menu_Cater.InsertOnSubmit(relationship);
db.SubmitChanges();
}
Small changes may need to be made for your variable/database-field names. And maybe db.Save() instead of db.SubmitChanges() depending on the type of data context.
I don't know, if You need it now, but Ill show how to do it.
If I have understood right, You mean smth like that.
public ActionResult Create(Cater cater, int menuId)
{
//Find menu with our menu_id
Menu menu = db.Menus.Where(m => m.menu_id == menuId).FirstOrDefault();
//Add cater for this Menu
menu.Cater.Add(cater);
db.SaveChanges();
return somethere...
}
public ActionResult Remove(int caterId, int menuId)
{
//Choose menu, from him we will delete cater which we need
Menu menu = db.Menus.Where(m => m.menu_id == menuId).FirstOrDefault();
//Find cater which we want delete from this Menu
Cater cater = menu.Cater.Where(c => c.cater_id == caterId).FirstOrDefault();
//Remove him from Table Menu_Cater
menu.Cater.Remove(cater);
db.SaveChanges();
return somethere...
}
Thats all. Its work for MVC4
In my other methods (data, text, etc.) the setItem method works fine to display changes made to a tree item. However, calling setItem after changing an item's icon doesn't seem to have any effect. What is the best way to update the tree item so the new icon appears?
Thanks
public void modified()
{
FormTreeItem workingItem;
;
super();
//find the current item
workingItem = FormTreeControl.getItem(FormTreeControl.getSelection());
//update the value
workingItem.Image(1);
//update the item in the list
FormTreeControl.setItem(workingItem);
}
Found a couple of issues here:
1. Never found a way to update the icon on a tree item effectively.
2. Found out some of the tree control objects aren't initialized if you try to add/delete from a datasource method, so deleting items throws Object Not Initialized errors.
Fixed it by:
1. Create a new item (addAfterIdx of the old item).
2. Delete the old item.
3. Select the new item.
3. Move the method from the datasource to the actual form control.
Here's the code that worked for me:
public boolean modified()
{
boolean ret;
FormTreeItem workingItem = FormTreeControl.getItem(currentEditingIdx);
TreeItemIdx newItemIdx;
;
ret = super();
//create a new item
newItemIdx = SysFormTreeControl::addTreeItem(FormTreeControl, workingItem.text(), FormTreeControl.getParent(workingItem.idx()), workingItem.data(), element.imageIdx(ABC_Icon.text()));
//delete the old item
FormTreeControl.delete(currentEditingIdx);
//select the new item
FormTreeControl.selectionChanged(FormTreeControl.getItem(FormTreeControl.getRoot()), FormTreeControl.getItem(newItemIdx), FormTreeSelect::Unknown);
return ret;
}