This is just a short article on some useful tips I’ve found for writing Attributes for Dynamic Data.
I say Tips there really isn’t that much to this.
Let me show you an attribute I just created for a post on the Dynamic Data Forum:
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false)] public class DisableEditingAttribute : Attribute { public Boolean Disable { get; set; } public static DisableEditingAttribute Default = new DisableEditingAttribute(); public DisableEditingAttribute() : this(false) { } public DisableEditingAttribute(Boolean disable) { Disable = disable; } }
Listing 1 – Disable Editing Attribute
And here’s it being used in the List page:
protected void Page_Load(object sender, EventArgs e) { table = GridDataSource.GetTable(); Title = table.DisplayName; //GridView1.Sort("ColumnName, ColumnName", SortDirection.Descending); InsertHyperLink.NavigateUrl = table.GetActionPath(PageAction.Insert); // Disable various options if the table is readonly var editingDisabled = table.Attributes.OfType<DisableEditingAttribute>().DefaultIfEmpty(new DisableEditingAttribute()).FirstOrDefault(); if (table.IsReadOnly || editingDisabled.Disable) { GridView1.Columns[0].Visible = false; InsertHyperLink.Visible = false; } }
Listing 2 – DisableEditingAttribute in use BOLD ITALIC
The first ting to note is a Linq thing; the DefautIfEmpty extension method. This is used to specify a default value if the returned value is null (From the OfType FirstOrDefault combination) this means I don’t have to test for null like:
// Disable various options if the table is readonly var editingDisabled = table.Attributes.OfType<DisableEditingAttribute>().FirstOrDefault(); if (table.IsReadOnly || (editingDisabled != null && editingDisabled.Disable)) { GridView1.Columns[0].Visible = false; InsertHyperLink.Visible = false; }
Listing 3 – Having to test for null
Another way of doing this would be to use a Default static method to provide the default value.
// Disable various options if the table is readonly var editingDisabled = table.Attributes.OfType<DisableEditingAttribute>(). DefaultIfEmpty(DisableEditingAttribute.Default).FirstOrDefault(); if (table.IsReadOnly || editingDisabled.Disable) { GridView1.Columns[0].Visible = false; InsertHyperLink.Visible = false; }
Listing 4 – using the Default static method
Either method works but my preference is to have a default constructor Attribute() and I’ll explain why. But first let me show you an Extension method I found in the Dynamic Data Futures project extension methods:
public static T GetAttribute<T>(this MetaTable table) where T : Attribute { return table.Attributes.OfType<T>().FirstOrDefault(); }
Listing 5 – the GetAttribute Generic extension method.
And it’s use:
// Disable various options if the table is readonly var editingDisabled = table.GetAttribute<DisableEditingAttribute>(); if (table.IsReadOnly || (editingDisabled != null && editingDisabled.Disable)) { GridView1.Columns[0].Visible = false; InsertHyperLink.Visible = false; }
Listing 6 – the GetAttribute extension method in use
This is better more readable code but the test for null makes it a bit messy. So here are my interpretations of the GetAttribute extension method:
public static T GetAttributeOrDefault<T>(this MetaTable table) where T : Attribute, new() { return table.Attributes.OfType<T>().DefaultIfEmpty(new T()).FirstOrDefault(); } public static T GetAttributeOrDefault<T>(this MetaColumn column) where T : Attribute, new() { return column.Attributes.OfType<T>().DefaultIfEmpty(new T()).FirstOrDefault(); }
Listing 7 – My GetAttributeOrDefault extension methods
All I’ve done here is use the DefaultIfEmpty Linq extension method and added an extra constraint to the generic class the make the extension method only work with attributes that have an explicit default Constructor.
And just for completeness here are all the generic extension methods together:
public static T GetAttributeOrDefault<T>(this MetaTable table) where T : Attribute, new() { return table.Attributes.OfType<T>().DefaultIfEmpty(new T()).FirstOrDefault(); } public static T GetAttribute<T>(this MetaTable table) where T : Attribute { return table.Attributes.OfType<T>().FirstOrDefault(); } public static T GetAttributeOrDefault<T>(this MetaColumn column) where T : Attribute, new() { return column.Attributes.OfType<T>().DefaultIfEmpty(new T()).FirstOrDefault(); } public static T GetAttribute<T>(this MetaColumn column) where T : Attribute { return column.Attributes.OfType<T>().FirstOrDefault(); }
Listing 8 – All Generic Attributes together
The one in BOLD ITALIC is the original from Dynamic Data Futures project.
9 comments:
where should i put function "GetAttribute"? thank you
where should i put function "GetAttribute"?
You put them in a seperate public static class like all extension methods.
Steve :D
See C# Version 3.0 - Extension Methods
I dont care what your picture looks like. I think your beautiful.
Now tell me how to turn a column filter off.
Hi Anonymous, and thank you for the compliment :)
you could have a look at this article here Limit the Filter Fields which shows how to hide filters based on a custom attribute.
Steve :D
I found this read only attribute to be extremely helpful for the List.aspx page. But you didn't mention the Details.aspx page that has the Edit and Delete at the bottom of the fields. I had to add the following code on the Page_Load of that page as well in order to hide that as well for read only tables.
// Disable various options if the table is readonly
var editingDisabled = table.Attributes.OfType().DefaultIfEmpty(new DisableEditingAttribute()).FirstOrDefault();
if (table.IsReadOnly || (editingDisabled != null && editingDisabled.Disable))
{
//GridView1.Columns[0].Visible = false;
//InsertHyperLink.Visible = false;
var totalFields = DetailsView1.Fields.Count;
DetailsView1.Fields[totalFields - 1].Visible = false;
}
Thanks Joe,
Error 35 'System.ComponentModel.AttributeCollection' does not contain a definition for 'OfType' and no extension method 'OfType' accepting a first argument of type 'System.ComponentModel.AttributeCollection' could be found (are you missing a using directive or an assembly reference?)
How to resolve this error?
Sounds like you are missing a using for System.Linq
Steve
Post a Comment