I am using XamMenu for our primary application menu. Rather than hard code or add all the menus on the fly I want to use data binding. Our application menus are currently defined in XML. I can use linq to put them in an object graph if needed.
Reading the docs it talks about creating a hierarchal template but seems to say you need to create one for each menu level you need. Our menu structure is 100% defined in the XML.
First, is it possible to bind to XML or will I need to bind to an object graph.
Are there any examples of fully data driven XamMenus with random level depths.
BOb
Can anyone help me binding the XamMenu to an ObservableCollection in a ViewModel. I'm not quite sure how to set up the HierarchyTemplate object. I am just getting empty menus but I know the observable collection is getting populated.
Bob,
The XamDataTree will not be the best option. We may be able to get this to work now with the XamMenu with its current features. Please attach a sample XML file that you might use build a menu. I think we may be able to employ LINQ To XML to get this working.
Thanks,
Francis,
Ok, here is one of our menu files. What I have done currently is in my menu service I project it to an object graph of a MenuItem class:
public class MenuItem
{
[Key]
public int Id { get; set; }
public string MenuTitle { get; set; }
public string NavigationUri { get; set; }
public string NodeProvider { get; set; }
public string NodeSource { get; set; }
public int ParentMenuId { get; set; }
[Include]
[Composition]
[Association("Children","Id","ParentMenuId")]
public IList<MenuItem> Children { get; set; }
public MenuItem()
Children = new List<MenuItem>();
}
But, I can always return the raw XML is that will work better. Here is one of our smaller menu files:
Hmm... I don't see a way to attach stuff here. So, I'll just post the XML in, it is not too big.
<?xml version="1.0" encoding="utf-8" ?>
<TOC>
<NODE text="Configure" description="Configure Evolution Data Exchange Authentication Users" HeaderText="eDex" status="closed" requiredPermissions="eDex.Configure" possiblePermissions="eDex.Configure">
<NODE text="Users" description="Setup Users and Passwords" HeaderText="eDex" status="closed" navigate="EDEXWeb/frmAuthenticationUsersGrid.aspx" requiredPermissions="eDex.Configure" possiblePermissions=""/>
</NODE>
<NODE text="eSite" description="eSite" HeaderText="eDex" status="closed" requiredPermissions="eDex.eSite" possiblePermissions="eDex.eSite,eDex.eSite.LeasingReports,eDex.eSite.LeasingReports.View">
<NODE text="Mapping Tables" description="Mapping Tables" HeaderText="eDex" status="closed" requiredPermissions="" possiblePermissions="eDex.eSite.PropertyMapping,eDex.eSite.IncomeCodeMapping,eDex.eSite.UnitTypeMapping,eDex.eSite.ReturnPaymentFees">
<NODE text="Property Mapping" description="Property Mapping Table" HeaderText="eDex" status="closed" navigate="EDEXWeb/frmPropertyMappingGrid.aspx" requiredPermissions="eDex.eSite.PropertyMapping" possiblePermissions=""/>
<NODE text="Income Code Mapping" description="Income Code Mapping Table" HeaderText="eDex" status="closed" navigate="EDEXWeb/frmIncomeCodeMappingGrid.aspx" requiredPermissions="eDex.eSite.IncomeCodeMapping" possiblePermissions=""/>
<NODE text="Unit Type Mapping" description="Unit Type Mapping Table" HeaderText="eDex" status="closed" navigate="EDEXWeb/frmUnitTypeMappingGrid.aspx" requiredPermissions="eDex.eSite.UnitTypeMapping" possiblePermissions=""/>
<NODE text="Return Payment Fees" description="Return Payment Fees" HeaderText="eDex" status="closed" navigate="EDEXWeb/frmReturnPaymentFeesGrid.aspx" requiredPermissions="eDex.eSite.ReturnPaymentFees" possiblePermission=""/>
<NODE text="Reports" description="Reports of webservices activity" HeaderText="eDex" status="closed" requiredPermissions="eDex.Reports.WebServicesActivity" possiblePermissions="eDex.Reports.WebServicesActivity">
<NODE text="Webservices Activity" description="Webservices Activity Summary" HeaderText="eDex" status="closed" navigate="EDEXWeb/frmWebserviceReport.aspx" requiredPermissions="eDex.Reports.WebServicesActivity" possiblePermissions=""/>
<NODE text="Housekeeping" description="Housekeeping functions" HeaderText="eDex" status="closed" requiredPermissions="eDex.Reports.WebServicesActivity" possiblePermissions="eDex.Housekeeping.PurgeWebServicesActivity">
<NODE text="Purge Webservices Activity" description="Purge Webservices Activity" HeaderText="eDex" status="closed" navigate="EDEXWeb/frmPurgeWebservicesActivity.aspx" requiredPermissions="eDex.Housekeeping.PurgeWebServicesActivity" possiblePermissions=""/>
<NODE text="About" HeaderText="eDex" description="" status="closed" navigate="EDEXWeb/frmAbout.aspx" requiredPermissions="eDex.About" possiblePermissions="eDex.About"></NODE>
</TOC>
I am having some difficulty parsing the XML since it is a nested strructure of the same kind of item (NODE), so I am looking further into that. In the mean time, I need to ask the following questions:
1. Are you implementing INotifyProprtyChanged on the MenuItem class and on the collection of type MenuItem? If not, then there may be some chance that you are bound to that object before it is actually hydrated....just a thought.
2. Can you provide a sample (isolating just the menu) that shows the issue whereby you are getting the empty menu while the XML data is in memory?
I have implemented INotifyPropertyChanged in the view model. I have not in the MenuItem class since the menu items don't change.. just the collection (IList). I think I tried it both as an ObservableCollection and as the EntityCollection (that comes back from RIA.)
I have worked out the linq to XML to create the object graph. The code runs in my DomainService which returns the menu data as a List. Here is the code of our Menu service that creates the object graph from our menu xml:
namespace AmsiWeb.ConfigServices
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Xml.Linq;
using System.ServiceModel.DomainServices.Hosting;
using System.ServiceModel.DomainServices.Server;
using System.Collections;
using System.Text.RegularExpressions;
using System.Xml;
[EnableClientAccess()]
public class MenuService : DomainService
int _menuIdIterator;
public IEnumerable<MenuItem> LoadTocBranch(string tocPath, string menuProvider)
XDocument xdoc = XDocument.Load(new XmlNodeReader(MenuHelper.GetMenu(tocPath, menuProvider)));
var menu = (from node in xdoc.Root.Elements("NODE")
select new MenuItem
Id = ++_menuIdIterator,
MenuTitle = (string)node.Attribute("text"),
NavigationUri = ParseUri((string)node.Attribute("navigate")),
IconPath = (string)node.Attribute("iconPath"),
NodeSource = (string)node.Attribute("nodeSrc"),
NodeProvider = (string)node.Attribute("nodeProvider"),
Children = GetNodeChildren(node.Elements("NODE"), node)
}).ToList<MenuItem>();
return menu;
private IList<MenuItem> GetNodeChildren(IEnumerable<XElement> elements, XElement parentNode)
var parentId = _menuIdIterator;
return (from node in elements
ParentMenuId = parentId,
/// <summary>
/// Pre-pend Html/ to any Uri that ends with .htm or .html or .aspx. This will facilitate the UriMapper and navigation in the silverlight client.
/// </summary>
/// <param name="Uri">The Uri to parse.</param>
/// <returns></returns>
private string ParseUri(string Uri)
if ((! String.IsNullOrEmpty(Uri)) && Regex.IsMatch(Uri, @"(.*?)\.(html|htm|aspx|asp)"))
return "Html/" + System.Web.HttpUtility.UrlEncode(Uri);
return Uri;
public string IconPath { get; set; }
If I have time I will try to isolate this all into a single sample with what I was trying to do. I really need to get this working. Thanks.
The same XMAL worked to load the Menu items. but how this will work with the command.
I tried this way
<i:Interaction.Triggers> <i:EventTrigger EventName="ItemClicked"> <i:InvokeCommandAction Command="{Binding Path=SwitchPageCommand}" CommandParameter="{Binding Path=MenuName}" /> </i:EventTrigger> </i:Interaction.Triggers>
AND
<ig:XamMenuItem.InputBindings> <MouseBinding MouseAction="LeftClick" Command="{Binding Path=SwitchPageCommand}" CommandParameter="{Binding Path=MenuName}" /> </ig:XamMenuItem.InputBindings>
both the way but its not firing the event and not giving the parameter values. Can you help me on it
One of the developers informed me that we were neglecting to use the DefaultItemsContainer to host our DataTemplate for the XamMenuItem. An example is posted in our forums in a thread entitled "Horizontal XamMenu Data binding with Hierarchical Data" at this address: https://ko.infragistics.com/community/forums/f/retired-products-and-controls/49840/horizontal-xammenu-data-binding-with-hierarchicaldata/264957#264957
I believe the proper markup in my own sample should be the following...
<ig:XamMenu Name="xamMenu1" ItemsSource="{Binding MenuItems }"> <ig:XamMenu.HierarchicalItemTemplate > <ig:HierarchicalDataTemplate ItemsSource="{Binding Children }"> <ig:HierarchicalDataTemplate.DefaultItemsContainer > <DataTemplate > <ig:XamMenuItem /> </DataTemplate > </ig:HierarchicalDataTemplate.DefaultItemsContainer > <ig:HierarchicalDataTemplate.ItemTemplate > <DataTemplate > <TextBlock Text="{Binding MenuTitle }"/> </DataTemplate > </ig:HierarchicalDataTemplate.ItemTemplate > <DataTemplate > <TextBlock Text="{Binding MenuTitle }"/> </DataTemplate > </ig:HierarchicalDataTemplate > </ig:XamMenu.HierarchicalItemTemplate > </ig:XamMenu >
Just wanted to let you know that this topic is being discussed between myself and my colleagues. I will let you know our findings as soon as I can.
Thanks Bob....I'll look into this and get back to you shortly.
Ok a question.. all I get is text blocks in the menu. Shouldn't they be XamMenu items. I need to set the Header and NavigationUri along with a right click event handler. The "menu" displays but it doesn't do anything.