Html.ActionLink 分机
Html.ActionLink extension
我正在尝试扩展 Html.ActionLink,因为我想为共享组件(在本例中为模式)添加自定义元数据。
我的目标是进一步扩展 .Net MVC 中的 LinkExtensions class,这将向 html class 属性添加一个值并添加一个自定义数据属性,结果如下:
<a href="/Controller/Action/id" class="show-in-modal style1 style2" data-title="Modal title">Link</a>
助手看起来类似于 MVC 方法:
public static MvcHtmlString ModalLink(this HtmlHelper htmlHelper, string title, string linkText, string actionName, string controllerName, object routeValues, object htmlAttributes)
{
// Add 'show-in-modal' class here
// Add 'data-title' attribute here
return htmlHelper.ActionLink(linkText, actionName, controllerName, routeValues, htmlAttributes);
}
@Html.ModalLink("Modal title", "Link", "action", "controller", new { id = "id" }, new { @class = "style1 style2" });
我遇到的这个问题是我无法轻易地修改 htmlAttributes 对象来添加我的 class 名称和数据属性,这是有道理的,因为这是一个只读的匿名对象。
有没有一种方法可以轻松应用所需的 values/meta 数据,而不必通过反射将所有内容拆开再重新组合起来?
我注意到 MVC 有重载,它以 IDictionary<string, object>
的形式接受 html 属性,是否有扩展方法将匿名类型转换为可修改的字典?
我在搜索中得到的只是如何使用 Html.ActionLink() 方法。
您要查找的函数是:
HtmlHelper.AnonymousObjectToHtmlAttributes()
这是 ModalLink 扩展的一个版本:
public static MvcHtmlString ModalLink(this HtmlHelper htmlHelper, string title, string linkText, string actionName, string controllerName, object routeValues, object htmlAttributes)
{
// Add 'show-in-modal' class here
// Add 'data-title' attribute here
var htmlAttr = HtmlHelper.AnonymousObjectToHtmlAttributes(htmlAttributes);
const string classKey = "class";
const string titleKey = "data-title";
const string classToAdd = "show-in-modal";
if (htmlAttr.ContainsKey(classKey) == true)
{
htmlAttr[classKey] += " " + classToAdd;
}
else
{
htmlAttr.Add(classKey, classToAdd);
}
if (htmlAttr.ContainsKey(titleKey) == true)
{
htmlAttr[titleKey] = title;
}
else
{
htmlAttr.Add(titleKey, title);
}
return htmlHelper.ActionLink(linkText, actionName, controllerName, new RouteValueDictionary(routeValues), htmlAttr);
}
不久前我为这种情况制作了一个助手class。这是它的基本简化版本。我为其中一种方法留下了 XML 注释,因为否则它会有点混乱。
HtmlAttributes.cs
/// <copyright file="HtmlAttributes.cs"><author username="Octopoid">Chris Bellini</author></copyright>
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Text;
using System.Web.Mvc;
public class HtmlAttributes : Dictionary<string, object>
{
public HtmlAttributes()
: base()
{
}
public HtmlAttributes(object anonymousAttributes)
: base(HtmlHelper.AnonymousObjectToHtmlAttributes(anonymousAttributes))
{
}
public HtmlAttributes(IDictionary<string, object> attributes)
: base(attributes)
{
}
public void Add(object anonymousAttributes)
{
this.Add(HtmlHelper.AnonymousObjectToHtmlAttributes(anonymousAttributes));
}
public void Add(IDictionary<string, object> attributes)
{
foreach (var attribute in attributes)
{
this.Add(attribute.Key, attribute.Value);
}
}
public void AddCssClass(string cssClass)
{
if (cssClass == null) { throw new ArgumentNullException("cssClass"); }
string key = "class";
if (this.ContainsKey(key))
{
string currentValue;
if (this.TryGetString(key, out currentValue))
{
this[key] = currentValue + " " + cssClass;
return;
}
}
this[key] = cssClass;
}
public void Remove(object anonymousAttributes)
{
this.Remove(HtmlHelper.AnonymousObjectToHtmlAttributes(anonymousAttributes));
}
/// <summary>
/// Removes the value with the specified key from the <see cref="System.Collections.Generic.Dictionary<TKey,TValue>"/>.
/// This method hides the base implementation, then calls it explicity.
/// This is required to prevent the this.Remove(object) method catching base.Remove(string) calls.
/// </summary>
/// <param name="key">The key of the element to remove.</param>
/// <returns>
/// true if the element is successfully found and removed; otherwise, false.
/// This method returns false if key is not found in the System.Collections.Generic.Dictionary<TKey,TValue>.
/// </returns>
/// <exception cref="System.ArgumentNullException">key is null.</exception>
public new bool Remove(string key)
{
return base.Remove(key);
}
public void Remove(IDictionary<string, object> attributes)
{
foreach (var attribute in attributes)
{
this.Remove(attribute.Key);
}
}
public MvcHtmlString ToMvcHtmlString()
{
return new MvcHtmlString(this.ToString());
}
public override string ToString()
{
StringBuilder output = new StringBuilder();
foreach (var item in this)
{
output.Append(string.Format("{0}=\"{1}\" ", item.Key.Replace('_', '-'), item.Value.ToString()));
}
return output.ToString().Trim();
}
public bool TryGetString(string key, out string value)
{
object obj;
if (this.TryGetValue(key, out obj))
{
value = obj.ToString();
return true;
}
value = default(string);
return false;
}
}
在你的例子中,在你的辅助方法中,你会这样做:
HtmlAttributes finalAttributes = new HtmlAttributes(htmlAttributes);
finalAttributes.Add("data_title", "title");
finalAttributes.AddCssClass("show-in-modal");
请注意,如果需要,您也可以将它们一起添加(或删除):
finalAttributes.Add(new { data_title = "title", id = "id", data_extra = "extra" });
然后您可以像往常一样传入 finalAttributes,因为它扩展了 Dictionary<string, object>
。
这在您制作自己的自定义 HTML 控件渲染器时也很有用,因为您可以使用 attributes.ToMvcHtmlString()
方法将属性渲染到 HTML。
我正在尝试扩展 Html.ActionLink,因为我想为共享组件(在本例中为模式)添加自定义元数据。
我的目标是进一步扩展 .Net MVC 中的 LinkExtensions class,这将向 html class 属性添加一个值并添加一个自定义数据属性,结果如下:
<a href="/Controller/Action/id" class="show-in-modal style1 style2" data-title="Modal title">Link</a>
助手看起来类似于 MVC 方法:
public static MvcHtmlString ModalLink(this HtmlHelper htmlHelper, string title, string linkText, string actionName, string controllerName, object routeValues, object htmlAttributes)
{
// Add 'show-in-modal' class here
// Add 'data-title' attribute here
return htmlHelper.ActionLink(linkText, actionName, controllerName, routeValues, htmlAttributes);
}
@Html.ModalLink("Modal title", "Link", "action", "controller", new { id = "id" }, new { @class = "style1 style2" });
我遇到的这个问题是我无法轻易地修改 htmlAttributes 对象来添加我的 class 名称和数据属性,这是有道理的,因为这是一个只读的匿名对象。
有没有一种方法可以轻松应用所需的 values/meta 数据,而不必通过反射将所有内容拆开再重新组合起来?
我注意到 MVC 有重载,它以 IDictionary<string, object>
的形式接受 html 属性,是否有扩展方法将匿名类型转换为可修改的字典?
我在搜索中得到的只是如何使用 Html.ActionLink() 方法。
您要查找的函数是:
HtmlHelper.AnonymousObjectToHtmlAttributes()
这是 ModalLink 扩展的一个版本:
public static MvcHtmlString ModalLink(this HtmlHelper htmlHelper, string title, string linkText, string actionName, string controllerName, object routeValues, object htmlAttributes)
{
// Add 'show-in-modal' class here
// Add 'data-title' attribute here
var htmlAttr = HtmlHelper.AnonymousObjectToHtmlAttributes(htmlAttributes);
const string classKey = "class";
const string titleKey = "data-title";
const string classToAdd = "show-in-modal";
if (htmlAttr.ContainsKey(classKey) == true)
{
htmlAttr[classKey] += " " + classToAdd;
}
else
{
htmlAttr.Add(classKey, classToAdd);
}
if (htmlAttr.ContainsKey(titleKey) == true)
{
htmlAttr[titleKey] = title;
}
else
{
htmlAttr.Add(titleKey, title);
}
return htmlHelper.ActionLink(linkText, actionName, controllerName, new RouteValueDictionary(routeValues), htmlAttr);
}
不久前我为这种情况制作了一个助手class。这是它的基本简化版本。我为其中一种方法留下了 XML 注释,因为否则它会有点混乱。
HtmlAttributes.cs
/// <copyright file="HtmlAttributes.cs"><author username="Octopoid">Chris Bellini</author></copyright>
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Text;
using System.Web.Mvc;
public class HtmlAttributes : Dictionary<string, object>
{
public HtmlAttributes()
: base()
{
}
public HtmlAttributes(object anonymousAttributes)
: base(HtmlHelper.AnonymousObjectToHtmlAttributes(anonymousAttributes))
{
}
public HtmlAttributes(IDictionary<string, object> attributes)
: base(attributes)
{
}
public void Add(object anonymousAttributes)
{
this.Add(HtmlHelper.AnonymousObjectToHtmlAttributes(anonymousAttributes));
}
public void Add(IDictionary<string, object> attributes)
{
foreach (var attribute in attributes)
{
this.Add(attribute.Key, attribute.Value);
}
}
public void AddCssClass(string cssClass)
{
if (cssClass == null) { throw new ArgumentNullException("cssClass"); }
string key = "class";
if (this.ContainsKey(key))
{
string currentValue;
if (this.TryGetString(key, out currentValue))
{
this[key] = currentValue + " " + cssClass;
return;
}
}
this[key] = cssClass;
}
public void Remove(object anonymousAttributes)
{
this.Remove(HtmlHelper.AnonymousObjectToHtmlAttributes(anonymousAttributes));
}
/// <summary>
/// Removes the value with the specified key from the <see cref="System.Collections.Generic.Dictionary<TKey,TValue>"/>.
/// This method hides the base implementation, then calls it explicity.
/// This is required to prevent the this.Remove(object) method catching base.Remove(string) calls.
/// </summary>
/// <param name="key">The key of the element to remove.</param>
/// <returns>
/// true if the element is successfully found and removed; otherwise, false.
/// This method returns false if key is not found in the System.Collections.Generic.Dictionary<TKey,TValue>.
/// </returns>
/// <exception cref="System.ArgumentNullException">key is null.</exception>
public new bool Remove(string key)
{
return base.Remove(key);
}
public void Remove(IDictionary<string, object> attributes)
{
foreach (var attribute in attributes)
{
this.Remove(attribute.Key);
}
}
public MvcHtmlString ToMvcHtmlString()
{
return new MvcHtmlString(this.ToString());
}
public override string ToString()
{
StringBuilder output = new StringBuilder();
foreach (var item in this)
{
output.Append(string.Format("{0}=\"{1}\" ", item.Key.Replace('_', '-'), item.Value.ToString()));
}
return output.ToString().Trim();
}
public bool TryGetString(string key, out string value)
{
object obj;
if (this.TryGetValue(key, out obj))
{
value = obj.ToString();
return true;
}
value = default(string);
return false;
}
}
在你的例子中,在你的辅助方法中,你会这样做:
HtmlAttributes finalAttributes = new HtmlAttributes(htmlAttributes);
finalAttributes.Add("data_title", "title");
finalAttributes.AddCssClass("show-in-modal");
请注意,如果需要,您也可以将它们一起添加(或删除):
finalAttributes.Add(new { data_title = "title", id = "id", data_extra = "extra" });
然后您可以像往常一样传入 finalAttributes,因为它扩展了 Dictionary<string, object>
。
这在您制作自己的自定义 HTML 控件渲染器时也很有用,因为您可以使用 attributes.ToMvcHtmlString()
方法将属性渲染到 HTML。