Archive for August 28, 2012

Word wrapping SharePoint list column headers

A customer for our Highlighter product recently asked us how you could modify SharePoints List View Web Part (LVWP) to word wrap column headers. He had found that as he had replaced lengthy text with status icons he could fit a lot more columns on the page – if only he could shrink the column headers down.

To be clear – this isn’t unique to lists using our Highlighter product, this example shows a basic SharePoint list with a long title that is causing a horizontal toolbar as it won’t word warp even though the column will only ever contain Yes or No.

Of course you could rename the column and shorted the name and put more information in the description – but that only appears on the Edit form so it’s a balancing act between being brief and giving enough info so everyone knows what the columns contains.

Anyway – how to make these columns word wrap?

Inspired by this post on Stack Exchange I looked at using Cascading Style Sheets to do this.

The property we need is white-space : normal

Then we need to figure out which parts of the html to apply it to. This is done by HTML classes, so taking into account SharePoint 2007 and 2010 and different column styles (number/text/filterable/non-filterable) we end up with.

So the white-space property is applied to html elements with a class of .ms-vh, ms-vh2-nograd and so on.

We could also make the column headers center aligned and red (just for an example) by putting in

So how do we add these styles to the page?

You can use SharePoint Designer, but perhaps the easiest way is to add it via a Content Editor Web Part (CEWP)

  • Go to your list.
  • Select Site Actions > Edit Page
  • Click “Add a web part”

SharePoint 2007 SharePoint 2010
  • Select Miscellaneous > Content Editor Web Part
  • Click “open tool pane” then “Source Editor”
  • Add in the CSS from above
  • Select Media and Content > Content Editor
  • Select “Click here to add new content”
  • On the ribbon select Html > Edit HTML Source
  • Add in the CSS.

And – word wrapping :-

If this doesn’t work for you then as with all things ‘code’ exact syntax is important so check everything carefully – a “ is not the same as a ” for example. Also be sure that you’ve put the CSS in the HTML Source area, not just directly into the rich text editor.

You can add lots more effects (Red, bold etc) but sometimes its hard figuring out exactly what html elements and classes to target (e.g. you can’t apply a colour to the .ms-vh table header, you’ve got to apply it to an anchor element inside this – so “.ms-vh a”) – Firebug, the IE developer tools or the Chrome equivalent are invaluable for this – they will save your sanity!

Using LINQ to manipulate data in DataSet/DataTable

LINQ (Language Integrated Query) provides a very easy and fast way to manipulate data that is cached in a DataSet. In .Net applications, DataSet represents a disconnected cache of data. Your application typically needs to search, filter thru this data in order to display this data according to the need. DataView provides a very limited options
when it comes to creating a filtered view of the data. LINQ extends these capabilities to a greater extend.

A LINQ query opertaion consists of 3 actions (Ref:MSDN): obtain the data source, create the query and execute the query.

Any datasource that implements the IEnumerable(T) generic interface can be queried thru LINQ. So DataTable objects are good candidates to do any LINQ query opertions, we will see using the following examples, how some common tasks can be done using LINQ queries.

For our example, we will consider that our DataSet has one(1) table with the following schema,

1 dtCustomer (CustomerID,CustomerName,Address,City,PostalCode,State,Country,PhoneNumer)

A simple select:

1 IEnumerable query =
2     from customer in dtCustomer.AsEnumerable()
3     select customer;

Till this point, we have the LINQ query ready, but not executed it yet, query is executed when we actually use it.

1 foreach (DataRow dr in query)
2 {
3     Console.WriteLine(dr.Field("CustomerName"));
4 }

At this point, our query is executed and it prints the names of the customer.

We can also, get the resulset as a DataView by simply doing,

1 DataView view = query.AsDataView();

Most times, when we are dealing with DataSet/DataTable, data we will be creating a DataView as result of our LINQ query. ToList(), ToArray() methods are also very useful when you want to get your resultset
as a generic list or Array (Think AJAX/JSON!).

Lambda Expressions can be used as parameters to LINQ queries.

1 IEnumerable customers =
2     query.Where(c => c.Field("CustomerName").Containes("John"));
4 //All names that contain "John"
5 foreach (DataRow cust in customers)
6 {
7     Console.WriteLine(cust.Field("CustomerName"));
8 }

Simple Where Clause:

1 EnumerableRowCollection query
2               = from customer in dtCustomer.AsEnumerable()
3                 where customer.Field("State") == "NJ"
4                 select customer;
5             DataView njview = query.AsDataView();

Pretty simple, njview represents all customers that live in NJ.
You can extend the example to add more criteria to your where clause…

1 EnumerableRowCollection query
2               = from customer in dtCustomer.AsEnumerable()
3                 where customer.Field("State") == "NJ" && customer.Field("PostalCode") == "08807"
4                 select customer;
5             DataView njview = query.AsDataView();

It is useful to note that when you write your where clause, you leverage the power of your C# (or VB.Net) language features to search and filter your resultset using LINQ.

So, A SQL where clause is

1 where customer.Field("State") == "NJ"
2      where customer.Field("State") != "NJ"

A SQL Like clause is

1 where customer.Field("CustomerName").Containes("John")

Skip and Take allows to get the skip the first n rows or get the top n rows as a result of the query.\

1 EnumerableRowCollection query
2               = (from customer in dtCustomer.AsEnumerable()
3                 where customer.Field("State") == "NJ"
4                 select customer).Skip(3);
6 EnumerableRowCollection query
7               = (from customer in dtCusomter.AsEnumerable()
8                 where customer.Field("State") == "NJ"
9                 select customer).Take(3);

Simple ORDER BY clause:

1 EnumerableRowCollection query
2               = from customer in dtCustomer.AsEnumerable()
3                 orderby customer.Field("CustomerName")
4                 select customer;

Above query, gets the result order by customer name (ascending is default). And if you want it by descending order,

1 EnumerableRowCollection query
2               = from customer in dtCusomter.AsEnumerable()
3                 orderby customer.Field("CustomerName")  descending
4                 select customer;

Reverse ORDER:

1 EnumerableRowCollection query
2               = (from customer in dtCustomer.AsEnumerable()
3                 orderby customer.Field("CustomerName")
4                 select customer.Reverse();

Simple JOIN Operator:

1 var customers = ds.Tables["Customer"].AsEnumerable();
2 var orders = ds.Tables["Order"].AsEnumerable();
3 var query =
4             from customer in customers
5             join order in orders
6         on order.Field("CustomerID")
7             equals customer.Field("Customer")
8     into custOrders
9     select custOrders;

All the examples given above is just the tip of iceberg on what you can do with LINQ and Lambda expressions. There is tons of samples and articles available on Internet on this, if you are looking for a way to simplyfy and speed up your business processing logic in your middle tier, LINQ is something you need to adopt!