开发者

Hierarchical Menu in MVC.NET driven by XML

I am trying to create a hierarchical xml based menu in MVC.NET

<?xml version="1.0" encoding="utf-8" ?>
<NavigationMenu id="1" Name="myMenu" Lang="EN">
  <NavigationMenuGroup Header="Home" Name="header1" Link="/home" />
  <NavigationMenuGroup Header="Manage" Name="header2" Link="/options" />
  <NavigationMenuGroup Header="About" Name="header3"  Link="/About" >
    <NavigationMenuItem Header="Test1" Name="header5"  Link="/page1" />
    <NavigationMenuItem Header="Test2" Name="header6"  Link="/page2" />
  </NavigationMenuGroup>
</NavigationMenu>

I pan for the masterpage to Render a Partial menu (NavMenu.ascx), the data will be fed to the masterpage by a Custom BaseController.

The NavMenu.ascx will produce code similar to following (easy to plugin jQuery or simlar).

 <ul id="menu">
   <li>
      <h2><a href="/home">Home</a></h2>
   </li>

   <li>
      <h2><a href="/options">Manage</a></h2>
   </li>

   <li>
      <h2><a href="/about">About</a></h2>

          <li>
             <h2><a href="/page2">Test1</a></h2>
          </li>
          <li>
             <h2><a href="/page1开发者_如何转开发">Test2</a></h2>
          </li>
   </li>
</ul>

I also have setup a set of classes to Deserialize.

    namespace MyMVC.Helpers
    {
        public class XmlSerializerHelper<T>
        {
            public Type _type;

            public XmlSerializerHelper()
            {
                _type = typeof(T);
            }

            public void Save(string path, object obj)
            {
                using (TextWriter textWriter = new StreamWriter(path))
                {
                    XmlSerializer serializer = new XmlSerializer(_type);
                    serializer.Serialize(textWriter, obj);
                }
            }

            public T Read(string path)
            {
                T result;
                using (TextReader textReader = new StreamReader(path))
                {
                    XmlSerializer deserializer = new XmlSerializer(_type);
                    result = (T)deserializer.Deserialize(textReader);
                }
                return result;
            }
        }
}

I am not sure what is the best way to do this without breaking the MVC principals?


Was trying to solve this problem myself and came up with the following. I used mine for a primary navigation which needed certain active classes (based on Drupal's menu rendering):

XML:

<?xml version="1.0" encoding="utf-8" ?>
<items>
  <item title="Some Title" name="Test" text="Testing 1" link="1">
    <items>
      <item name="Test" text="Testing 1-1" link="2">
        <items>
          <item name="Test" text="About" link="/home/about" />
          <item name="Test" text="Testing 1-1-2" link="4" />
          <item name="Test" text="Testing 1-1-3" link="5" />
        </items>
      </item>
      <item name="Test" text="Testing 1-2" link="6" />
      <item name="Test" text="Testing 1-3" link="7" />
    </items>
  </item>
  <item name="Testame" text="Testing 2" link="8" />
  <item name="Test" text="Testing 3" link="9" />
  <item name="Test" text="Testing 4" link="10" />
  <item name="Test" text="Testing 5" link="11" />
  <item title="Some Title" name="Test" text="Testing 6" link="1">
    <items>
      <item name="Test" text="Testing 6-1" link="12">
        <items>
          <item name="Test" text="Testing 6-1-1" link="13" />
          <item name="Test" text="Testing 6-1-2" link="14" />
          <item name="Test" text="Testing 6-1-3" link="15" />
        </items>
      </item>
      <item name="Test" text="Testing 6-2" link="16" />
      <item name="Test" text="Testing 6-3" link="17" />
    </items>
  </item>
  <item name="Test" text="Testing 7" link="18" />
  <item name="Test" text="Testing 8" link="19">
    <items>
      <item name="Test" text="Testing 8-1" link="20" />
      <item name="Test" text="Testing 8-2" link="21" />
      <item name="Test" text="Testing 8-3" link="22" />
    </items>
  </item>
</items>

Helper:

    public static class Helpers
    {

        public static MvcHtmlString Menu(this HtmlHelper helper, string name, string e = null, object attributes = null)
        {
            string filepath = helper.ViewContext.HttpContext.Server.MapPath(name + ".xml");

            XPathDocument oDoc = new XPathDocument(filepath);

            return new MvcHtmlString(GetMenuHtml(oDoc.CreateNavigator(), e, attributes));
        }

        private static string GetMenuHtml(XPathNavigator nav, string e = "ul", object attributes = null)
        {

            List<String> item = new List<String>();

            XPathNodeIterator nodes = nav.Select("items/item");

            TagBuilder holder = new TagBuilder(e);

            if (attributes != null)
            {
                IDictionary<string, object> htmlAttributes = HtmlHelper.AnonymousObjectToHtmlAttributes(attributes);
                holder.MergeAttributes(htmlAttributes);
            }

            while (nodes.MoveNext())
            {

                TagBuilder a = new TagBuilder("a");
                TagBuilder span = new TagBuilder("span");
                TagBuilder li = new TagBuilder("li");

                string url = nodes.Current.GetAttribute("link", string.Empty);
                string text = nodes.Current.GetAttribute("text", string.Empty);
                string title = nodes.Current.GetAttribute("title", string.Empty);

                span.InnerHtml = text;

                a.MergeAttribute("href", url);

                if (!String.IsNullOrEmpty(title)) a.MergeAttribute("title", title);

                a.InnerHtml = span.ToString();

                List<String> classes = new List<String>();

                if (url == HttpContext.Current.Request.Url.AbsolutePath)
                {
                    classes.Add("active");   
                }

                if (nodes.Count == nodes.CurrentPosition)
                {
                    classes.Add("last");
                }
                else if (nodes.CurrentPosition == 1)
                {
                    classes.Add("first");
                }

                if (nodes.Current.HasChildren)
                {
                    li.InnerHtml = a.ToString() + GetMenuHtml(nodes.Current, e);

                    if (li.InnerHtml.Contains("class=\"active"))
                    {
                        classes.Add("active-trail");
                    }

                    classes.Add("leaf");
                }
                else
                {
                    li.InnerHtml = a.ToString();
                }

                if(classes.Count > 0){
                    li.MergeAttribute("class", string.Join(" ", classes.ToArray()));
                }

                item.Add(li.ToString() + "\n");

            }

            holder.InnerHtml = string.Join("", item.ToArray());

            return holder.ToString();

        }


    }

View:

@Html.Menu("navigation", "ul")

Output

<ul>
    <li class="first active-trail leaf">
        <a href="1" title="Some Title"><span>Testing 1</span></a>
        <ul>
            <li class="first active-trail leaf"><a href="2"><span>Testing 1-1</span></a>
                <ul>
                    <li class="active first"><a href="/home/about"><span>Testing 1-1-1</span></a></li>
                    <li><a href="4"><span>Testing 1-1-2</span></a></li>
                    <li class="last"><a href="5"><span>Testing 1-1-3</span></a></li>
                </ul>
            </li>
            <li><a href="6"><span>Testing 1-2</span></a></li>
            <li class="last"><a href="7"><span>Testing 1-3</span></a></li>
        </ul>
    </li>
    <li><a href="8"><span>Testing 2</span></a></li>
    <li><a href="9"><span>Testing 3</span></a></li>
    <li><a href="10"><span>Testing 4</span></a></li>
    <li><a href="11"><span>Testing 5</span></a></li>
    <li class="leaf">
        <a href="1" title="Some Title"><span>Testing 6</span></a>
        <ul>
            <li class="first leaf"><a href="12"><span>Testing 6-1</span></a>
                <ul>
                    <li class="first"><a href="13"><span>Testing 6-1-1</span></a></li>
                    <li><a href="14"><span>Testing 6-1-2</span></a></li>
                    <li class="last"><a href="15"><span>Testing 6-1-3</span></a></li>
                </ul>
            </li>
            <li><a href="16"><span>Testing 6-2</span></a></li>
            <li class="last"><a href="17"><span>Testing 6-3</span></a></li>
        </ul>
    </li>
    <li><a href="18"><span>Testing 7</span></a></li>
    <li class="last leaf"><a href="19"><span>Testing 8</span></a>
        <ul>
            <li class="first"><a href="20"><span>Testing 8-1</span></a></li>
            <li><a href="21"><span>Testing 8-2</span></a></li>
            <li class="last"><a href="22"><span>Testing 8-3</span></a></li>
        </ul>
    </li>
</ul>


Have a look at MvcSiteMap provider that works also with XML

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜