Thursday, 2 April 2009

Disallow Navigation on ForeignKey FieldTemplate – Dynamic Data (UPDATED)

This article originates from a post I ding on the ASP.NET Dynamic Data Forum here Re: A few problems with my dynamic data website, Rick Anderson suggesting that it would be a useful post to link to in his FAQ. So here it is for easy access rather than having to search the forum for it.

HappyWizard

Firstly the idea is that you want to show the name of the entity but not link to if from the ForeignKey FieldTemplate.

Category has Navigation disabled

Figure 1 - Category has Navigation disabled

The code we need for this comes in three parts

  1. The Attribute
  2. The modification the the FieldTemplate
  3. The Metadata.

The Attribute

C#
[AttributeUsage(AttributeTargets.Property)] public class DisallowNavigationAttribute : Attribute { public Boolean Hide { get; private set; } /// <summary> /// Initializes a new instance of the <see cref="DisallowNavigationAttribute"/> class. /// </summary> public DisallowNavigationAttribute() { Hide = false; } public DisallowNavigationAttribute(Boolean show) { Hide = show; } }
VB
<AttributeUsage(AttributeTargets.[Property] Or AttributeTargets.[Field])> _ Public Class DisallowNavigationAttribute Inherits Attribute Private _hide As [Boolean] Public Property Hide() As [Boolean] Get Return _hide End Get Private Set(ByVal value As [Boolean]) _hide = value End Set End Property Public Sub New(ByVal hide As [Boolean]) Me.Hide = hide End Sub Public Sub New() Me.Hide = False End Sub End Class

Listing 1 – AllowNavigation attribute

Note the use of the Default see Writing Attributes and Extension Methods for Dynamic Data for the details on why.

C#
/// <summary> ///
Get the attribute or a default instance of the attribute /// if the Column attribute do not contain the attribute /// </summary> /// <typeparam name="T">Attribute type</typeparam> /// <param name="table">Column to search for the attribute on.</param> /// <returns>The found attribute or a default instance of the attribute of type T</returns> public static T GetAttributeOrDefault<T>(this MetaColumn column) where T : Attribute, new() { return column.Attributes.OfType<T>().DefaultIfEmpty(new T()).FirstOrDefault(); }
VB
Imports
System.Runtime.CompilerServices Imports System.Web.DynamicData Public Module ExtensionMethods ''' <summary> ''' Get the attribute or a default instance of the attribute ''' if the Column attribute do not contain the attribute ''' </summary> ''' <typeparam name="T">Attribute type</typeparam> ''' <param name="column">Column to search for the attribute on.</param> ''' <returns>The found attribute or a default instance of the attribute of type T</returns> ''' <remarks>Used to simplify getting Attributes from metadata</remarks> <Extension()> _ Public Function GetAttributeOrDefault(Of T As {Attribute, New})(ByVal column As MetaColumn) As T Return column.Attributes.OfType(Of T)().DefaultIfEmpty(New T()).FirstOrDefault() End Function End Module

Listing 2 -  Extension method to get attribute

The modification the the FieldTemplate

Now we need to add a little change to the ForeignKey.aspx.cs file which can be found in the ~/DynamicData/FieldTemplates folder of your Dynamic Data site.

C#
protected string
GetNavigateUrl() { var dissallow = Column.GetAttributeOrDefault<DisallowNavigationAttribute>(); if (!AllowNavigation || dissallow.Hide) { // remove undeline :D HyperLink1.Style.Add(HtmlTextWriterStyle.TextDecoration, "none !important"); return null; } if (String.IsNullOrEmpty(NavigateUrl)) { return ForeignKeyPath; } else { return BuildForeignKeyPath(NavigateUrl); } }
VB
Protected Function
GetNavigateUrl() As String Dim dissallow = Column.GetAttributeOrDefault(Of DisallowNavigationAttribute)() If Not AllowNavigation OrElse dissallow.Hide Then Return Nothing End If If String.IsNullOrEmpty(NavigateUrl) Then Return ForeignKeyPath Else Return BuildForeignKeyPath(NavigateUrl) End If End Function

Listing 3 – ForeignKey FieldTemplate modifications

Updated: With the addition of the inline style the underline will not show, of course you could always just set the CssClass of the Hyperlink to a style with textdecoration: none !important; if you wanted.

All we’ve done here is get the attribute into the allow variable and the add it to the checks in the if statement so that:

  • If the internal AllowNavigation is set then null is returned.
  • If the custom attribute is set null is returned.

The Metadata

C#
[MetadataTypeAttribute(typeof(Products.ProductsMetadata))] public partial class Products { internal sealed class ProductsMetadata { public object ProductID { get; set; } public object ProductName { get; set; } public object QuantityPerUnit { get; set; } public object UnitPrice { get; set; } public object UnitsInStock { get; set; } public object UnitsOnOrder { get; set; } public object ReorderLevel { get; set; } public object Discontinued { get; set; } public object Order_Details { get; set; } [DisallowNavigation(true)] public object Categories { get; set; } [DisallowNavigation(true)] public object Suppliers { get; set; } } }
VB
Imports
Microsoft.VisualBasic Imports System.Web.DynamicData Imports System.ComponentModel Imports System.ComponentModel.DataAnnotations <MetadataType(GetType([Product].[ProductMD]))> _ Partial Public Class [Product] Partial Public Class [ProductMD] Public ProductID As Object Public ProductName As Object Public SupplierID As Object Public CategoryID As Object Public QuantityPerUnit As Object Public UnitPrice As Object Public UnitsInStock As Object Public UnitsOnOrder As Object Public ReorderLevel As Object Public Discontinued As Object Public Order_Details As Object <DisallowNavigationAttribute(True)> _ Public Category As Object Public Supplier As Object End Class End Class

Listing 4 – sample Metadata

Now if you attribute a foreign key column up with the AllowNavigationAttribute you can turn off the hyperlink.

Happy Coding and remember HappyWizard

 

3 comments:

Ian said...

Hey, you may be just the expert I'm looking for! I really know nothing about HTML, and I have a small problem on my Blogspot. At the end of every post there is a long list of links to all previous posts. I don't know how to remove it. I wonder if you would be so kind as to look at my blog and see if there is a way to fix it.

Thank you.

Stephen J. Naughton said...

Hi Ian, I would think it is something in the template you choose when setting up your blog. I'm probably not the person to sort it out, I struggle with Blogger aswell but I just put up with it. I do have a few Ideas as to what it could be but I recommend you e-mail me direct.

Steve :D

Ian said...

Thanks, Steve. Thats' really kind of you.