Donnerstag, 25. Februar 2010

Changing the button-images on EntityEditorWithPicker for a custom Picker-Field

If you ever got the task to create a custom field with custom pickerdialog-controls, don't dispair. Although there is no really helpful tutorial or how-to that illuminates the connections between field-, control-, entityeditorwithpicker-, dialogclasses and so on available on the internet (at least I never found one) and the information available on msdn is sparely too. My approach so far was to reflector all the stuff, Microsoft did in their picker-classes and I found out, that they did a lot of unbeautiful things in their classes that makes it harder to inherit from them.

As long as you just want to change the searchquery or the result-list (to achieve a behaviour similar as you know from the peopleeditor) this is no big hit. But as soon, as you start to create more individual pickerdialogs, you will run in some difficulties.

My plan for the next time is to write a few articles and how-tos about how to create custom picker-fields with more cool look and feel than known from the people-editor.

Let's start with a "simple" task. You know the two button below the entityeditor-field for checking names and browse:



Now it's the task to replace those two buttons by your own to have a closer look to the whole surrounding website-design like this one:


The locations for those two images can be set in the EntityEditorWithPicker-class and are stored in the members named CheckButtonImageName and BrowseButtonImageName. If you have a look in the msdn for that member, you'll see... absolutely nothing helpful. Even if you enter them as searchterm in google, you'll find at most one page. So I had to guess and did try-by-error-changes.

The result, you can see on the second screenshot, I achieved by setting those values to the members in the onInit-method of my inherited EntityEditorWithPicker-class:

CheckButtonImageName = "../../_layouts/_myproject/images/icon/check_a.gif";
BrowseButtonImageName = "../../_layouts/_myproject/images/icon/book.gif";


The path to the images is assembled by going to the 12\template-folder upward from the subfolder in the controltemplates-folder, where the controltemplate (that includes the entityeditor-tag) exists and after this going down to the icons in the layouts\images-folder. The following image helps you to understand this:


Mittwoch, 10. Februar 2010

How to get absolute path to a sp-object on the simple way

Often I have to work with absolute urls instead of the server-relative that I can get from SharePoint-Objects like for e.g. SPContext.Current.ListItem.Url that returns me something like "Pages/subfolder1/publishingpage1.aspx".

Until now I cumbersome concatenated the different url-parts to get the absolute path but I found a much more simple method that relieves that task: just use the MakeFullUrl-Method of your SPSite-Object. Simple reference the server-relative URL as parameter and get the full path.

// for e.g.: returns http://server/sitecollection/Pages/folder/publishingpage.aspx if executed in the code-behind of a PublishingPage
string absoluteUrl = SPContext.Current.Site.MakeFullUrl(SPContext.Current.ListItem.Url);

Dienstag, 2. Februar 2010

Redirect to a PublishingPage in edit-mode from code-behind

After a long period of not-posting because of high stress at the current project at work, finally I found some time to write a little hint. I really hope to shorten the period of time between future posts. I promise, that I'll try! :-)

In the current project it's a requirement to create PublishingPages on a code-behind of an application page and redirect to that Page afterwards.

There're two little stumbling blocks you have to watch out. The first is, that you have to check out the newly created PublishingPage before redirecting, otherwise you'll get a nice error-message of type "You have not checked out this page. Click 'Edit Page' to edit the page.".

The next obstacle is - you wouldn't believe it -  the correct use of case-sensitive parameters in the querystring. So much to say for case-insensitiveness of querystring-parameters.

Use this code-snippet to redirect to a PublishingPage:

PublishingPage newPage = <Method that creates thePublishingPage>();
...
newPage.CheckOut();

string controlMode = "Edit";
string displayMode = "Design";

Page.Response.Redirect(string.Format("{0}?ControlMode={1}&DisplayMode={2}", newPage.Uri.AbsoluteUri, controlMode, displayMode), true);


Be sure to write "Edit" and "Design" with capitalized letters or else it wouldn't work.

Montag, 5. Oktober 2009

Prevent expanding grouping in listviews

Recently I got the requirement from a customer to deactivate the auto-expanding of groups in a single AllItems.aspx-Default-Listview that was grouped and should show at least 700 items per page.
First attempts where in vain to deactivate viewStates from the control or change webpart-attributes. A more promising approach seemed to be deleting browser-cookies. Reloading Firefox after deleting cookies worked like a charm but I've got no success to reproduce this behaviour by code.

So I had to try another way and began to debug the SharePoint-JavaScript by using Firebug. That was a good decision because I discovered this method:

ProcessDefaultOnLoad(_spBodyOnLoadFunctionNames);

In here a simple array is iterated over that's items are getting executed by eval-function.
One of the array-items is "ExpGroupOnPageLoad". This function cares for expanding each group if it's found in the state-cookie.

A little bit googling about the JS-Variable _spBodyOnLoadFunctionNames gave me a little bit more overview and so I tried to remove the
ExpGroupOnPageLoad-entry in hope that the groups stayed collapsed after reload. And voila! It worked like a charm!

Just add this piece of code in your AllItems.aspx (or another view-file) and the list-groupings stay closed after page-reload, no matter, what groups the user expanded before:


<script type="text/javascript">
for (var i = 0; i < _spBodyOnLoadFunctionNames.length; i++) {
if (_spBodyOnLoadFunctionNames[i] == "ExpGroupOnPageLoad") {
// remove only this one element from array
_spBodyOnLoadFunctionNames.splice(i,1);
break;
}
}
</script>

Lange nichts gehört... / Long time ago...

Seit meinem letzten Post ist einige Zeit vergangen, in der ich auch ein paar Tage im Urlaub war. Schöne Grüße nach Mallorca, wo während meines Aufenthalts die schlimmsten Unwetter der letzten 40 Jahre herrschten ;-)

Seit letzter Woche bin ich zurück und ausgeruht um neue neue SharePoint-Abenteuer zu bestehen. Ich hoffe, dass ich zukünftige Postings in kürzeren Abständen schreiben kann. Diese werden dann, beginnend ab dem nächsten, komplett in Englisch sein. Ebenfalls habe ich vor, das etwas angestaubte Design des Blogs ein wenig zu überarbeiten.

Damit der Übergang zum Sprachwechsel nicht ganz so hart ausfällt, hier die englische Version:

English version:

Since my last post some time elapsed, which I used for making holidays and other lovely things.
Greetings to Mallorca, Spain that suffered from the heaviest thunderstorm since the last 40 years. ;-)

Now I'm back since last week and feel refreshed to look forward new SharePoint-Adventures. I hope to shorten the delays between my upcoming blogposts which I'll try to write henceforth completely in english. I also want to redesign the blog-layout a little bit.

So that the change-over for my readers isn't that hard, this posting is a mixture from german and english.

Dienstag, 18. August 2009

Länge des Mailbody in SPUtility.SendEmail begrenzt

Die Methode SendEmail der statischen Klasse SPUtility kann dazu verwendet werden, aus dem SharePoint-Kontext heraus E-Mails zu verschicken. Zu beachten ist dabei allerdings, dass der Mailbody nach 2048 Zeichen abgeschnitten wird. Für größere E-Mails, bzw. Inhalte mit aufwendigen HTML-Inhalten kann dies zum Problem werden.

Abhilfe schafft hier allerdings das Verwenden von New Lines innerhalb des Body-Strings.

Der Mailbody für SendEmail kann also mehr als 2048 Zeichen insgesamt verschicken, es dürfen allerdings nur maximal 2048 Zeichen pro Zeile stehen.


StringBuilder mailBody = new StringBuilder();
...
mailBody.AppendFormat("<tr style='{0}'><td style='padding-right:10px;'>{1}</td><td style='padding-right:10px;'>{2}</td><td style='padding-right:10px;'>{3}</td><td style='padding-right:10px;'>{4}</td></tr>", style, key, title, milestone, dueDate).AppendLine();
...

SPUtility.SendEmail(spWeb, false, false, toAddresses, "Subject", mailBody.ToString());

Donnerstag, 30. Juli 2009

Listeninstanzen - Cannot complete this action

Werden bei einer Solution ListInstances verwendet und sollen dann an speziell diese Listen CustomActions angehängt werden, empfiehlt es sich, anstelle der Standard-TemplateTypes (100, 101, etc..) eigene IDs ab 10000 zu verwenden.

Diese Änderung muss aber überall nachgezogen werden, sonst kommt es beim Erstellen der SiteCollection schnell zu der nichts sagenden Fehlermeldung "Cannot complete this action".



Die TemplateType-ID muss angepasst werden in
  • CustomAction
  • ListInstance
  • ListTemplate
  • Schema.xml