<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Daniel&#039;s Blog</title>
	<atom:link href="http://www.dlindemann.de/blog/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.dlindemann.de/blog</link>
	<description>.NET and SharePoint Development</description>
	<lastBuildDate>Mon, 20 Feb 2012 23:26:08 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.1</generator>
		<item>
		<title>Ribbon Commands wiederverwenden</title>
		<link>http://www.dlindemann.de/blog/2011/05/20/ribbon-commands-wiederverwenden/</link>
		<comments>http://www.dlindemann.de/blog/2011/05/20/ribbon-commands-wiederverwenden/#comments</comments>
		<pubDate>Fri, 20 May 2011 12:56:32 +0000</pubDate>
		<dc:creator>Daniel Lindemann</dc:creator>
				<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[SharePoint]]></category>
		<category><![CDATA[Ribbon]]></category>
		<category><![CDATA[Tips]]></category>

		<guid isPermaLink="false">http://www.dlindemann.de/blog/?p=377</guid>
		<description><![CDATA[Möchte man SharePoint Ribbon Commands wiederverwenden, um z.B. einen Button in einem PageLayout mit einer Funktion des Ribbons auszustatten, kann man das sehr einfach über eine Zeile Javascript-Code bereitstellen: &#160; Die Commands kann man sehr gut aus der CMDUI.XML lesen. Hier ein Beispiel für den Ordner erstellen Dialog:]]></description>
			<content:encoded><![CDATA[<p>Möchte man SharePoint Ribbon Commands wiederverwenden, um z.B. einen Button in einem PageLayout mit einer Funktion des Ribbons auszustatten, kann man das sehr einfach über eine Zeile Javascript-Code bereitstellen:</p>
<pre class="brush: jscript; title: ; notranslate">
SP.Ribbon.PageManager.get_instance().get_commandDispatcher().executeCommand(&lt;CommandName&gt;, &lt;OptionalParameters&gt;);
</pre>
<p>&nbsp;</p>
<p>Die Commands kann man sehr gut aus der CMDUI.XML lesen.</p>
<p>Hier ein Beispiel für den Ordner erstellen Dialog:</p>
<pre class="brush: jscript; title: ; notranslate">
SP.Ribbon.PageManager.get_instance().get_commandDispatcher().executeCommand(&quot;NewFolder&quot;,null);
</pre>
<p></p>
]]></content:encoded>
			<wfw:commentRss>http://www.dlindemann.de/blog/2011/05/20/ribbon-commands-wiederverwenden/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>dotPeek &#8211; eine gute Alternative zum Reflector</title>
		<link>http://www.dlindemann.de/blog/2011/05/16/dotpeek-eine-gute-alternative-zum-reflector/</link>
		<comments>http://www.dlindemann.de/blog/2011/05/16/dotpeek-eine-gute-alternative-zum-reflector/#comments</comments>
		<pubDate>Mon, 16 May 2011 20:13:21 +0000</pubDate>
		<dc:creator>Daniel Lindemann</dc:creator>
				<category><![CDATA[.NET]]></category>
		<category><![CDATA[Tools]]></category>
		<category><![CDATA[Decompiler]]></category>

		<guid isPermaLink="false">http://www.dlindemann.de/blog/2011/05/16/dotpeek-eine-gute-alternative-zum-reflector/</guid>
		<description><![CDATA[Der Reflector ist seit Jahren das Standardtool zum Analysieren von .NET Assemblies. Doch seit Version 7 ist das Tool kostenpflichtig und viele Entwickler suchen seitdem eine Alternative. Version 6 des Reflectors gibts zwar noch kostenfrei, jedoch wird sie nicht mehr weiterentwickelt bzw. gewartet. Doch es gibt Abhilfe. Das Team von JetBrains hat vor kurzen die [...]]]></description>
			<content:encoded><![CDATA[<p>Der Reflector ist seit Jahren das Standardtool zum Analysieren von .NET Assemblies. Doch seit Version 7 ist das Tool kostenpflichtig und viele Entwickler suchen seitdem eine Alternative. Version 6 des Reflectors gibts zwar noch kostenfrei, jedoch wird sie nicht mehr weiterentwickelt bzw. gewartet.</p>
<p>Doch es gibt Abhilfe. Das Team von JetBrains hat vor kurzen die erste Version von dotPeek veröffentlicht. dotPeek ist ein Assembly Browser der sich vor allem durch seine gute Bedienung, ähnlich wie Visual Studio bzw. das Addon ReSharper, von Ã¤hnlichen Tools abhebt.</p>
<p>Mehr Infos gibts auf <a title="http://www.jetbrains.com/decompiler/" href="http://www.jetbrains.com/decompiler/">http://www.jetbrains.com/decompiler/</a> .<br />
Ich denke jeder Entwickler der eine alternative zum .NET Reflector sucht wird mit dotPeek seine Freude haben.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.dlindemann.de/blog/2011/05/16/dotpeek-eine-gute-alternative-zum-reflector/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Alles Gute zum Geburtstag, dotnet-snippets.de</title>
		<link>http://www.dlindemann.de/blog/2011/04/20/alles-gute-zum-geburtstag-dotnet-snippets-de/</link>
		<comments>http://www.dlindemann.de/blog/2011/04/20/alles-gute-zum-geburtstag-dotnet-snippets-de/#comments</comments>
		<pubDate>Wed, 20 Apr 2011 07:10:00 +0000</pubDate>
		<dc:creator>Daniel Lindemann</dc:creator>
				<category><![CDATA[.NET]]></category>
		<category><![CDATA[Community]]></category>

		<guid isPermaLink="false">http://www.dlindemann.de/blog/2011/04/20/alles-gute-zum-geburtstag-dotnet-snippets-de/</guid>
		<description><![CDATA[Es ist schon Wahnsinn wie schnell die Zeit vergeht. Da ist die deutschsprachige Anlaufstelle für .NET Snippets doch schon 5 Jahre alt. Dazu möchte ich herzlichst gratulieren! Alles Gute zum 5. Geburtstag dotnet-snippets.de !!! Und auf viele weitere Jahre! Die Macher rund um die Community Page haben sich für diesen Anlass auch etwas einfallen lassen. [...]]]></description>
			<content:encoded><![CDATA[<p>Es ist schon Wahnsinn wie schnell die Zeit vergeht. Da ist die deutschsprachige Anlaufstelle für .NET Snippets doch schon 5 Jahre alt.</p>
<p>Dazu möchte ich herzlichst gratulieren!<br />
<strong>Alles Gute zum 5. Geburtstag <a href="http://dotnet-snippets.de/dns/5-Jahre.aspx?guid=de57d9fa-0dca-49bb-8563-b5b3c12e83a4">dotnet-snippets.de</a> !!!<br />
Und auf viele weitere Jahre!</strong></p>
<p>Die Macher rund um die Community Page haben sich für diesen Anlass auch etwas einfallen lassen. Somit gibt es tolle Preise zu gewinnen. Darunter Visual Studio 2010, Office Professional Plus 2010, ein .NET Pro Abo und viele Bücher.</p>
<p>Das Gewinnspiel läuft von 20.04.2011 bis zum 04.05.2011.<br />
Weiter Info zum Gewinnspiel gibts auf <a href="http://dotnet-snippets.de/dns/5-Jahre.aspx?guid=de57d9fa-0dca-49bb-8563-b5b3c12e83a4">dotnet-snippets.de</a> .</p>
]]></content:encoded>
			<wfw:commentRss>http://www.dlindemann.de/blog/2011/04/20/alles-gute-zum-geburtstag-dotnet-snippets-de/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Einfaches Handling von SharePoint Ribbon Postback Commands</title>
		<link>http://www.dlindemann.de/blog/2011/04/02/einfaches-handling-von-sharepoint-ribbon-postback-commands/</link>
		<comments>http://www.dlindemann.de/blog/2011/04/02/einfaches-handling-von-sharepoint-ribbon-postback-commands/#comments</comments>
		<pubDate>Sat, 02 Apr 2011 08:30:36 +0000</pubDate>
		<dc:creator>Daniel Lindemann</dc:creator>
				<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[SharePoint]]></category>
		<category><![CDATA[Examples]]></category>
		<category><![CDATA[Ribbon]]></category>

		<guid isPermaLink="false">http://www.dlindemann.de/blog/?p=353</guid>
		<description><![CDATA[In der Welt der SharePoint Ribbon Erweiterungen muss man zwingend auf JavaScript zurückgreifen um Aktionen auszuführen. Dafür gibt es ja das neue JavaScript Client Object Model. Doch dieses Framework stößt auch irgendwann an seine Grenzen. So kann es z.B. bei lange andauernden, complexen Abfragen vorkommen, dass der Browser einfriert. Trotz Asynchronität. Außerdem sollte man bei [...]]]></description>
			<content:encoded><![CDATA[<p>In der Welt der SharePoint Ribbon Erweiterungen muss man zwingend auf JavaScript zurückgreifen um Aktionen auszuführen.<br />
Dafür gibt es ja das neue JavaScript Client Object Model. Doch dieses Framework stößt auch irgendwann an seine Grenzen.<br />
So kann es z.B. bei lange andauernden, complexen Abfragen vorkommen, dass der Browser einfriert. Trotz Asynchronität.<br />
Außerdem sollte man bei solchen Queries bedenkten, dass man viele Zeilen JavaScript Code schreiben muss, der viele Delegates enthalten wird. Dies führt zu einer schlechteren Lesbarkeit des Codes und bläht diesen nur unnötig auf.<br />
Viel einfacher können solche Methoden serverseitig entwickelt werden. Und zwar durch den Einsatz eines Delegate-Controls in Verbindung mit einem IPostBackEventHandler.</p>
<h4>Erweiterte PageComponente</h4>
<p>Aber zuerst einmal alles zurück auf Anfang. Zunächst benötigt man eine PageComponente.<br />
Ein PageComponent-Objekt ermöglicht das Interagieren mit dem Ribbon (<a href="http://msdn.microsoft.com/en-us/library/ff407303.aspx" target="_blank">http://msdn.microsoft.com/en-us/library/ff407303.aspx</a>).</p>
<pre class="brush: jscript; highlight: [13,14,36]; title: ; notranslate">
Type.registerNamespace('DL.PostbackRibbon');
// RibbonApp Page Component
DL.PostbackRibbon.PageComponent = function () {
	DL.PostbackRibbon.PageComponent.initializeBase(this);
}
DL.PostbackRibbon.PageComponent.initialize = function () {
	ExecuteOrDelayUntilScriptLoaded(
		Function.createDelegate(
			null,
			DL.PostbackRibbon.PageComponent.initializePageComponent),
		'SP.Ribbon.js');
}
DL.PostbackRibbon.PageComponent.initialize = function (controlId) {
	DL.PostbackRibbon.PageComponent.ControlClientId = controlId;
	ExecuteOrDelayUntilScriptLoaded(
		Function.createDelegate(
			null,
			DL.PostbackRibbon.PageComponent.initializePageComponent),
		'SP.Ribbon.js');
}
DL.PostbackRibbon.PageComponent.initializePageComponent = function () {
	var ribbonPageManager = SP.Ribbon.PageManager.get_instance();
	if (null !== ribbonPageManager) {
		ribbonPageManager.addPageComponent(DL.PostbackRibbon.PageComponent.instance);
		ribbonPageManager
			.get_focusManager()
			.requestFocusForComponent(DL.PostbackRibbon.PageComponent.instance);
	}
}
DL.PostbackRibbon.PageComponent.refreshRibbonStatus = function () {
	SP.Ribbon.PageManager
		.get_instance()
		.get_commandDispatcher()
		.executeCommand(Commands.CommandIds.ApplicationStateChanged, null);
}
DL.PostbackRibbon.PageComponent.ControlClientId = null;

DL.PostbackRibbon.PageComponent.prototype = {
	init: function () {
		// if you have something to initalize
	},
	getFocusedCommands: function () {
		return [];
	},
	getGlobalCommands: function () {
		// Server side commands will show up here
		return getGlobalCommands();
	},
	isFocusable: function () {
		return true;
	},
	canHandleCommand: function (commandId) {
		return commandEnabled(commandId);
	},
	handleCommand: function (commandId, properties, sequence) {
		return handleCommand(commandId, properties, sequence);
	}
}

// Register classes
DL.PostbackRibbon.PageComponent.registerClass('DL.PostbackRibbon.PageComponent', CUI.Page.PageComponent);
DL.PostbackRibbon.PageComponent.instance = new DL.PostbackRibbon.PageComponent();

// Notify and execute jobs
NotifyScriptLoadedAndExecuteWaitingJobs(&quot;/_layouts/ListinfoRibbonPostbackCommand/DL.PostbackRibbon.PageComponent.js&quot;);
</pre>
<p>Hier gibt es auch die erste Anpassung die ich gemacht habe.<br />
In <b>Zeile 36</b> habe ich die Variable <b>ControlClientId</b> erstellt, die später die ID des IPostBackEventHandler hält. Somit wird sichergestellt, dass der richtige Handler benutzt wird.<br />
<b>Zeile 13 und 14</b> zeigen die angepasste Initialize-Methode, die die Control-ID setzt.<br />
Ansonsten ist es eine einfache PageComponente wie in der MSDN beschrieben.</p>
<h4>Das CommandHandler Control</h4>
<p>Jetzt die spannende Serverseite. Ich habe ein Cotrol erstellt, das das Interface IPostBackEventHandler implementiert.</p>
<pre class="brush: csharp; highlight: [25]; title: ; notranslate">
public class PostbackRibbonHandler : Control, IPostBackEventHandler
{
	public PostbackRibbonHandler()
	{
		ID = &quot;PostbackRibbonHandler&quot;;
	}

	protected override void CreateChildControls()
	{
		base.CreateChildControls();

		// register server side command
		List&lt;IRibbonCommand&gt; cmds = new List&lt;IRibbonCommand&gt;()
		{
			new SPRibbonPostBackCommand(&quot;RunPostback&quot;, this, &quot;RunPostback&quot;, null)
		};

		SPRibbonScriptManager sm = new SPRibbonScriptManager();

		// register the page component
		sm.RegisterInitializeFunction(this.Page,
			&quot;InitPageComponent&quot;,
			&quot;/_layouts/ListinfoRibbonPostbackCommand/DL.PostbackRibbon.PageComponent.js&quot;,
			false,
			&quot;DL.PostbackRibbon.PageComponent.initialize('&quot; + this.ClientID + &quot;')&quot;);

		// enable server registered commands on the page
		sm.RegisterGetCommandsFunction(this.Page, &quot;getGlobalCommands&quot;, cmds);
		sm.RegisterCommandEnabledFunction(this.Page, &quot;commandEnabled&quot;, cmds);
		sm.RegisterHandleCommandFunction(this.Page, &quot;handleCommand&quot;, cmds);
	}

	public void RaisePostBackEvent(string eventArgument)
	{
		// implement PostBack logic
		// by default eventArgument contains the name of the command
	}
}
</pre>
<p>Im Konstruktor gebe ich dem Control einen Namen, damit man später einen PostBack auf dem Control abfeuern kann. Hier werden auch die Commands sowie die PageComponenten registriert die später von dem Control behandelt werden sollen.<br />
<b>Zeile 25</b> enthält den wichtigsten Schritt: Das setzen der Control-ID in die PageComponente.</p>
<h4>PostBack ausführen</h4>
<p>Nun wieder zurück zur PageComponente. In der Methode <b>handleCommand</b> wird der PostBack ausgelöst, der den IPostBackEventHandler triggert.<br />
Dabei wird als Argument ein kleines JSON-Objekt übergeben, das mir die benötigten SharePoint Listen- und Iteminformationen bereitstellt.</p>
<pre class="brush: jscript; title: ; notranslate">
handleCommand: function (commandId, properties, sequence) {
	if (commandId === 'RunPostback') {
		if (!CUI.ScriptUtility.isNullOrUndefined(DL.PostbackRibbon.PageComponent.ControlClientId)) {
			var controlId = DL.PostbackRibbon.PageComponent.ControlClientId;
			__doPostBack(controlId.replace('_', '$'), '{&quot;id&quot;:&quot;RunPostback&quot;,&quot;selectedId&quot;:' + SP.ListOperation.Selection.getSelectedItems()[0].id + ', &quot;listId&quot;:&quot;' + GetCurrentCtx().listName + '&quot;}');
			return true;
		}
		else {
			if (window.console)
				window.console.error('Unable to do a postback. PostBackHandler not found.')
		}
	}
	else {
		return handleCommand(commandId, properties, sequence);
	}
}
</pre>
<p></p>
<h4>Verarbeiten der Daten</h4>
<p>Die PostBack Argumente kann man sehr schnell über den JavaScriptSerializer zu einem Objekt umwandeln.<br />
Danach führt man wie gewohnt SharePoint Operationen aus.</p>
<p>In diesem Beispiel setze ich einen neuen Titel für das ausgewählte Dokument.</p>
<pre class="brush: csharp; title: ; notranslate">
public void RaisePostBackEvent(string eventArgument)
{
	JavaScriptSerializer jss = new JavaScriptSerializer();
	var args = jss.Deserialize&lt;SPRibbonCommandArgs&gt;(eventArgument);

	switch (args.Id)
	{
		case &quot;RunPostback&quot;:
			SPWeb web = SPContext.Current.Web;
			SPList list = web.Lists[args.ListId];
			if (list != null)
			{
				SPListItem item = list.GetItemById(args.SelectedId);
				if (item != null)
				{
					SPField titleField = item.Fields.GetFieldByInternalName(&quot;Title&quot;);
					item[titleField.Id] = &quot;Mein neuer Titel&quot;;
					item.SystemUpdate();
				}
			}
			break;
	}
}
</pre>
<pre class="brush: csharp; title: ; notranslate">
[Serializable]
public class SPRibbonCommandArgs
{
	/// &lt;summary&gt;
	/// Command ID
	/// &lt;/summary&gt;
	public string Id { get; set; }

	/// &lt;summary&gt;
	/// ID of the Selected Item
	/// &lt;/summary&gt;
	public int SelectedId { get; set; }

	/// &lt;summary&gt;
	/// ID of the List
	/// &lt;/summary&gt;
	public Guid ListId { get; set; }
}
</pre>
<p></p>
<h4>Ribbon Erweiterung und Delegate-Control</h4>
<p>Dann fehlt ja &#8220;nur&#8221; noch die Ribbon definition. Diese besteht in meinem Fall aus einem einzelnen Button, der in jeder Dokumentenbibliothek eingeblendet wird.<br />
Klickt man auf den Button wird das Klick-Event an die PageComponente geliefert und diese triggert per PostBack den IPostBackEventHandler.</p>
<p>In diese Datei kann man auch direkt das Delegate-Control registieren, wie in <b>Zeile 34</b>.</p>
<pre class="brush: xml; highlight: [34]; title: ; notranslate">
&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;
&lt;Elements xmlns=&quot;http://schemas.microsoft.com/sharepoint/&quot;&gt;
	&lt;CustomAction Id=&quot;DL.PostbackCommand&quot; Location=&quot;CommandUI.Ribbon&quot; RegistrationId=&quot;101&quot; RegistrationType=&quot;List&quot;&gt;
		&lt;CommandUIExtension&gt;
			&lt;CommandUIDefinitions&gt;
				&lt;CommandUIDefinition Location=&quot;Ribbon.Documents.Copies&quot; /&gt;
				&lt;CommandUIDefinition Location=&quot;Ribbon.Documents.Workflow&quot; /&gt;
				&lt;CommandUIDefinition Location=&quot;Ribbon.Documents.Groups._children&quot;&gt;
					&lt;Group Id=&quot;Ribbon.Documents.CustomGroup&quot;
						   Sequence=&quot;55&quot;
						   Description=&quot;Custom Group&quot;
						   Title=&quot;Custom&quot;
						   Template=&quot;Ribbon.Templates.Flexible2&quot;&gt;
						&lt;Controls Id=&quot;Ribbon.Documents.CustomGroup.Controls&quot;&gt;
							&lt;Button Id=&quot;Ribbon.Documents.CustomGroup.RunPostback&quot;
									Command=&quot;RunPostback&quot;
									Image16by16=&quot;/_layouts/images/ListinfoRibbonPostbackCommand/runit_32x32.png&quot;
									Image32by32=&quot;/_layouts/images/ListinfoRibbonPostbackCommand/runit_32x32.png&quot;
									LabelText=&quot;Postback!&quot;
									TemplateAlias=&quot;o2&quot;
									Sequence=&quot;15&quot; /&gt;
						&lt;/Controls&gt;
					&lt;/Group&gt;
				&lt;/CommandUIDefinition&gt;
				&lt;CommandUIDefinition Location=&quot;Ribbon.Documents.Scaling._children&quot;&gt;
					&lt;MaxSize Id=&quot;Ribbon.Documents.Scaling.CustomGroup.MaxSize&quot;
							 Sequence=&quot;15&quot;
							 GroupId=&quot;Ribbon.Documents.CustomGroup&quot;
							 Size=&quot;LargeLarge&quot; /&gt;
				&lt;/CommandUIDefinition&gt;
			&lt;/CommandUIDefinitions&gt;
		&lt;/CommandUIExtension&gt;
	&lt;/CustomAction&gt;
	&lt;Control Id=&quot;AdditionalPageHead&quot; ControlAssembly=&quot;ListinfoRibbonPostbackCommand, Version=1.0.0.0, Culture=neutral, PublicKeyToken=098b81014c222ac1&quot; ControlClass=&quot;ListinfoRibbonPostbackCommand.Controls.PostbackRibbonHandler&quot;&gt;&lt;/Control&gt;
&lt;/Elements&gt;
</pre>
<p>That&#8217;s it.<br />
Da diese ganze Mischung aus JavaScript, C# und XML auf den ersten Blick wohl etwas unübersichtlich ist gibt es hier noch das fertige Projekt zum Download.<br />
Note: There is a file embedded within this post, please visit this post to download the file. </p>
]]></content:encoded>
			<wfw:commentRss>http://www.dlindemann.de/blog/2011/04/02/einfaches-handling-von-sharepoint-ribbon-postback-commands/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>ListView Item reselektieren</title>
		<link>http://www.dlindemann.de/blog/2011/03/21/listview-item-reselektieren/</link>
		<comments>http://www.dlindemann.de/blog/2011/03/21/listview-item-reselektieren/#comments</comments>
		<pubDate>Mon, 21 Mar 2011 17:35:24 +0000</pubDate>
		<dc:creator>Daniel Lindemann</dc:creator>
				<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[SharePoint]]></category>
		<category><![CDATA[Examples]]></category>

		<guid isPermaLink="false">http://www.dlindemann.de/blog/?p=368</guid>
		<description><![CDATA[Das ModalDialog-Framework in SharePoint ist eine nette Sache. Leider hat es das Problem, dass ausgewählte Listenelemente nach dem Aktualisieren der Seite wieder deselektiert sind. Möchte man über den Ribbon bzw. mehrere Dialoge einen &#8220;Workflow&#8221; abbilden ist das Verhalten sehr störend (z.B. wenn ein Benutzer mehrere Dialog öffnen muss um einen bestimmten Status auf ein Element [...]]]></description>
			<content:encoded><![CDATA[<p>Das ModalDialog-Framework in SharePoint ist eine nette Sache. Leider hat es das Problem, dass ausgewählte Listenelemente nach dem Aktualisieren der Seite wieder deselektiert sind.</p>
<p>Möchte man über den Ribbon bzw. mehrere Dialoge einen &#8220;Workflow&#8221; abbilden ist das Verhalten sehr störend (z.B. wenn ein Benutzer mehrere Dialog öffnen muss um einen bestimmten Status auf ein Element zu setzen).</p>
<p>Die gute Nachricht: Durch das Neuladen der Seite mittels <a href="http://msdn.microsoft.com/en-us/library/ff411790.aspx">SP.UI.ModalDialog.RefreshPage</a> wird ein POST ausgelöst.<br />
Somit kann man sich die Daten in einem HiddenField speichern. Einfachste Lösung wäre hier ein Delegate-Control, das die ID des selektierten Elemtents wieder ausliest.</p>
<p>Doch wie selektiert man das Element wieder?</p>
<p>Microsoft hat bei der Entwicklung des Userinterfaces schon an alles gedacht. Ich musste allerdings lange suchen, bis ich die richtige Funktion gefunden habe:</p>
<pre class="brush: jscript; title: ; notranslate">ToggleItemRowSelection2(ctxCur, tr, fSelect, fUpdateRibbon)</pre>
<p>Die Funktion stammt aus der SharePoint core.js.</p>
<p>Die Parameter:</p>
<ul>
<li><strong>ctxCur: </strong>Der aktuelle SharePoint Context der Seite</li>
<li><strong>tr: </strong>Das DOM-Objekt der auszuwählenden TableRow</li>
<li><strong>fSelect: </strong>Ein bool-Wert, der angibt ob das Element selektiert oder deselektiert wird</li>
<li><strong>fUpdateRibbon: </strong>bool, Gibt an ob die Command-UI (Ribbon) aktualisiert werden soll</li>
</ul>
<p>Hier ist ein Ausschnitt aus meiner Lösung. Voraussetzung ist ein HiddenField, das per Klick-Event die ID der selektierten Zeile speichert.</p>
<pre class="brush: jscript; title: ; notranslate">
$(function () {
	// add click event to row
	$('tr.ms-itmhover').click(function () {
		var iidAttributeValue = $(this).attr('iid');
		var iid = iidAttributeValue.split(',');
		if (iid.length == 3) {
			$('#thehiddenfieldid').val(iid[1]);	// set selection to hidden field
		}
	});

	// read value from hidden field and reselect the row
	var currentCtx = GetCurrentCtx();	// method from CUI.js
	var itemId = $('#thehiddenfieldid').val();		// get id from hiddenfield
	var jTr = $('tr[iid*=&quot;,' + itemId + ',&quot;]:first');	// tr to select

	if (!CUI.ScriptUtility.isNullOrUndefined(currentCtx) &amp;amp;&amp;amp; jTr.length &amp;gt; 0) {
		ToggleItemRowSelection2(currentCtx, jTr[0], true, true);
	}
});
</pre>
<p>&nbsp;</p>
]]></content:encoded>
			<wfw:commentRss>http://www.dlindemann.de/blog/2011/03/21/listview-item-reselektieren/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>MySites Konfiguration &#8220;debuggen&#8221;</title>
		<link>http://www.dlindemann.de/blog/2010/07/09/mysites-konfiguration-debuggen/</link>
		<comments>http://www.dlindemann.de/blog/2010/07/09/mysites-konfiguration-debuggen/#comments</comments>
		<pubDate>Fri, 09 Jul 2010 12:01:17 +0000</pubDate>
		<dc:creator>Daniel Lindemann</dc:creator>
				<category><![CDATA[SharePoint]]></category>

		<guid isPermaLink="false">http://www.dlindemann.de/blog/?p=341</guid>
		<description><![CDATA[Die MySites in SharePoint 2010 sind sehr auf den Austausch von persönlichen Informationen ausgerichtet. Neu hinzu kommt eine Pinnwand à la Facebook und die Möglichkeit Statusinformationen bereitzustellen, wie auf XING. Das Aufsetzen von MySites kann jedoch etwas knifflig sein. Ein bekanntes Problem ist z.B. dass der Serviceaccount, der den User Profile Synchronization Services ausführt zwingend [...]]]></description>
			<content:encoded><![CDATA[<p>
Die MySites in SharePoint 2010 sind sehr auf den Austausch von persönlichen Informationen ausgerichtet. Neu hinzu kommt eine Pinnwand à la Facebook und die Möglichkeit Statusinformationen bereitzustellen, wie auf XING.<br />
Das Aufsetzen von MySites kann jedoch etwas knifflig sein. Ein bekanntes Problem ist z.B. dass der Serviceaccount, der den User Profile Synchronization Services ausführt zwingend zur lokalen Administratorengruppe hinzugefügt werden muss (weitere Informationen dazu gibts auf <a href="http://sharepointcommunity.de/blogs/fabianm/archive/2010/05/05/fehler-beim-start-des-sharepoint-2010-user-profile-synchronization-services.aspx" target="_blank">Fabians Blog</a>).<br />
Deshalb möchte ich hier kurz zusammenfassen auf was man achten muss um MySites zu erstellen und zeigen wie man Fehlerquellen beim synchronisieren auf die Schliche kommt.
</p>
<h4>Die Konfiguration</h4>
<ul>
<li>
<b>Farm/Service Account muss zur Gruppe Administratoren gehören</b><br />
Der Benutzer der den User Profile Synchronisation Service ausführt musst zur <u>lokalen</u> Administratorgruppe gehören.
</li>
<li>
<b>Zugriffsrechte auf die Sharepoint Datenbank</b><br />
Der Benutzer der den User Profile Synchronisation Service ausführt muss Daten in die Datenbank schreiben können.
</li>
<li>
<b>Prüfen, dass die Windows Services Forefront Indentity Snychronisation und Forefront Identity Manager laufen</b><br />
Nachdem man den User Profile Synchronisation Service gestartet hat (der Start kann bis zu 10min dauern), sollte man sich vergewisser, dass die Windows Services Forefront Indentity Snychronisation Service und Forefront Identity Manager Service gestartet wurden. Diese werden von dem User Profile Synchronisation Service ausgeführt.
</li>
<li>
<b>IIS Reset</b><br />
Nach dem Starten des Services sollte man einen IIS Reset durchführen, da man sonst eine System.IO.FileLoadException an den Kopf geworfen bekommt :/<br />
<div class="links-link"><a href="#" onclick="showhide_toggle('links', 341, 'Komplette Exception anzeigen', 'Komplette Exception anzeigen'); return false;"><span id="links-toggle-341">Komplette Exception anzeigen</span></a></div><div id="links-content-341" class="links-content" style="display: none;"></p>
<pre class="brush: plain; title: ; notranslate">
System.IO.FileLoadException: The located assembly's manifest definition does not match the assembly reference. (Exception from HRESULT: 0x80131040)
     at Microsoft.Office.Server.UserProfiles.UserProfileConfigManager.InitializeIlmClient(String ILMMachineName, Int32 FIMWebClientTimeOut)
     at Microsoft.Office.Server.UserProfiles.UserProfileConfigManager..ctor(UserProfileApplicationProxy userProfileApplicationProxy, Guid partitionID)
     at Microsoft.SharePoint.Portal.UserProfiles.AdminUI.ProfileAdminPage.IsProfileSynchronizationRunning()
     at Microsoft.SharePoint.Portal.WebControls.UserProfileServiceImportStatisticsWebPart.RenderSectionContents(HtmlTextWriter writer)
     at Microsoft.SharePoint.Portal.WebControls.UserProfileServiceImportStatisticsWebPart.RenderWebPart(HtmlTextWriter writer)
     at Microsoft.SharePoint.WebPartPages.WebPart.Render(HtmlTextWriter writer)
     at System.Web.UI.Control.RenderChildrenInternal(HtmlTextWriter writer, ICollection children)
     at System.Web.UI.Control.RenderChildrenInternal(HtmlTextWriter writer, ICollection children)
     at System.Web.UI.HtmlControls.HtmlForm.RenderChildren(HtmlTextWriter writer)
     at System.Web.UI.HtmlControls.HtmlForm.Render(HtmlTextWriter output)
     at System.Web.UI.HtmlControls.HtmlForm.RenderControl(HtmlTextWriter writer)
     at System.Web.UI.Control.RenderChildrenInternal(HtmlTextWriter writer, ICollection children)
     at System.Web.UI.HtmlControls.HtmlContainerControl.Render(HtmlTextWriter writer)
     at System.Web.UI.Control.RenderChildrenInternal(HtmlTextWriter writer, ICollection children)
     at System.Web.UI.Control.RenderChildrenInternal(HtmlTextWriter writer, ICollection children)
     at Microsoft.SharePoint.WebControls.UnsecuredLayoutsPageBase.RenderChildren(HtmlTextWriter writer)
     at System.Web.UI.Page.Render(HtmlTextWriter writer)
     at Microsoft.SharePoint.WebControls.UnsecuredLayoutsPageBase.Render(HtmlTextWriter writer)
     at System.Web.UI.Page.ProcessRequestMain(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint)
</pre>
<p></div>
</li>
<li>
<b>Benötigte Rechte und Daten des Active Directories zu synchronisieren</b><br />
Der Benutzer der Daten aus dem Active Directory zieht, braucht das Recht <u>Replicate Directory Changes</u>. Meistens ist das der SharePoint Farm Account, es kann aber auch ein anderer Account angegeben werden.
</li>
</ul>
<p>Weitere Informationen zu diesen Themen findet man auch im Microsoft Technet: <a href="http://technet.microsoft.com/en-us/library/ee721049(office.14).aspx" target="_blank">http://technet.microsoft.com/en-us/library/ee721049(office.14).aspx</a>
</p>
<h4>Probleme mit dem Tool Forefront Synchronisation Service Manager lösen</h4>
<p>
Der Forefront Synchronisation Service Manager ist ein nettes Tool mit dem man die Konfiguration des User Profile Synchronisation Services überprüfen kann.<br />
Man findet das Programm unter <i>C:\Program Files\Microsoft Office Servers\14.0\Synchronization Service\UI\Shell\miisclient.exe</i>.<br />
Mit diesem Tool hat man die Möglichkeit sich eine Liste der Operationen auf ein Active Directory oder auf eine andere Datenquellen anzuschauen, kann sich Operationen (wie z.B. einen FullImport) starten und sich eine genaue Fehlermeldung anzeigen lassen.<br />
<div id="attachment_339" class="wp-caption aligncenter" style="width: 410px"><a href="http://www.dlindemann.de/blog/wp-content/uploads/2010/07/forefrontidentitymanagerclient.png" rel="lightbox[341]"><img src="http://www.dlindemann.de/blog/wp-content/uploads/2010/07/forefrontidentitymanagerclient.png" alt="" title="Forefront Identity Manager Client" width="400" class="size-full wp-image-339" /></a><p class="wp-caption-text">Forefront Identity Manager Client</p></div></p>
<p>Um das Programm starten zu können muss der Benutzer in folgenden Gruppen sein:</p>
<ul>
<li>FIMSyncBrowse</li>
<li>FIMSyncJoiners</li>
<li>FIMSyncOperators</li>
<li>FIMSyncPasswordSet</li>
</ul>
<p>Danach startet man das Programm im Context des Service Accounts.</p>
<p>Nun sieht man eine Liste der ausgeführten Aktionen.<br />
<div id="attachment_343" class="wp-caption aligncenter" style="width: 410px"><a href="http://www.dlindemann.de/blog/wp-content/uploads/2010/07/miisOverview.png" rel="lightbox[341]"><img src="http://www.dlindemann.de/blog/wp-content/uploads/2010/07/miisOverview.png" alt="" title="Synchronisation Service Manager Übersicht" width="400" class="size-full wp-image-343" /></a><p class="wp-caption-text">Synchronisation Service Manager Übersicht</p></div></p>
<p>Um z.B. einen FullImport laufen zu lassen, kann man über Actions -> Run (bzw. STRG+F5) eine Aktion starten.</p>
<div id="attachment_340" class="wp-caption aligncenter" style="width: 410px"><a href="http://www.dlindemann.de/blog/wp-content/uploads/2010/07/runfullimport.png" rel="lightbox[341]"><img src="http://www.dlindemann.de/blog/wp-content/uploads/2010/07/runfullimport.png" alt="" title="Synchronisation Service Manager Action" width="400" class="size-full wp-image-340" /></a><p class="wp-caption-text">Synchronisation Service Manager Action</p></div>
<p>Möchte man wissen, warum eine Synchronisation nicht geklappt hat, kann man sich einfach das Log anschauen.<br />
<div id="attachment_338" class="wp-caption aligncenter" style="width: 410px"><a href="http://www.dlindemann.de/blog/wp-content/uploads/2010/07/connectionlog.png" rel="lightbox[341]"><img src="http://www.dlindemann.de/blog/wp-content/uploads/2010/07/connectionlog.png" alt="" title="Synchronisation Service Manager Connection Log" width="400" class="size-full wp-image-338" /></a><p class="wp-caption-text">Synchronisation Service Manager Connection Log</p></div></p>
<p>Der Synchronisation Service Manager hat noch einiges mehr zu bieten. Für ein kleines Debugging sollten die beschriebenen Funktionen jedoch ausreichen.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.dlindemann.de/blog/2010/07/09/mysites-konfiguration-debuggen/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Entwickeln mit Hilfe des Developer Dashboards</title>
		<link>http://www.dlindemann.de/blog/2010/05/14/entwickeln-mit-hilfe-des-developer-dashboards/</link>
		<comments>http://www.dlindemann.de/blog/2010/05/14/entwickeln-mit-hilfe-des-developer-dashboards/#comments</comments>
		<pubDate>Fri, 14 May 2010 11:47:48 +0000</pubDate>
		<dc:creator>Daniel Lindemann</dc:creator>
				<category><![CDATA[SharePoint]]></category>

		<guid isPermaLink="false">http://www.dlindemann.de/blog/?p=329</guid>
		<description><![CDATA[Eines der wichtigsten Features für Entwickler im neuen SharePoint 2010 ist das Developer Dashboard. Wie man das Developer Dashboard aktiviert habe ich schon hier beschrieben. Doch wie benutzt man das Feature um seinen Code zu analysieren? Zeit stoppen In der linken Spalte des Developer Dashboards findet man die Ablaufverfolgung des Requests. Hier findet man eine [...]]]></description>
			<content:encoded><![CDATA[<p>
Eines der wichtigsten Features für Entwickler im neuen SharePoint 2010 ist das<br />
Developer Dashboard.<br />
Wie man das Developer Dashboard aktiviert habe ich schon <a href="http://www.dlindemann.de/blog/?p=132">hier</a> beschrieben.<br />
Doch wie benutzt man das Feature um seinen Code zu analysieren?
</p>
<p><h4>Zeit stoppen</h4>
<p>In der linken Spalte des Developer Dashboards findet man die Ablaufverfolgung des Requests.<br />
Hier findet man eine Liste von ausgeführten Aktionen mit Angaben zur Dauer der Verarbeitung.<br />
Um eigene Aktionen aufzunehmen benutzt man das Objekt <b>SPMonitoredScope</b>, das sich im Namespace <b>Microsoft.SharePoint.Utilities</b> befindet.<br />
Jeglicher Code, der ausgeführt wird solange eine Instanz von SPMonitoredScope vorhanden ist wird protokolliert.<br />
Deshalb sollte man SPMonitoredScope über usings steuern.</p>
<pre class="brush: csharp; title: ; notranslate">
protected void myButton_Click(object sender, EventArgs e)
{
    using (SPMonitoredScope scopeButtonPushed = new SPMonitoredScope(&quot;Button action&quot;))
    {
        // dummy sleep action
        Thread.Sleep(5000);
        l.Text = &quot;Meine Daten: &quot;;

        string myData = GenerateLabelData();
        l.Text += myData;
    }
}
</pre>
<p>Dieser Beispielcode nimmt auf, dass die Aktion &#8220;Button action&#8221; 5 Sekunden gedauert hat und zeigt die Daten in der Ablaufverfolgung an.</p>
<p>Es besteht auch die Möglichkeit Aktionen zu verschachteln.<br />
Somit kann man eine detaillierte Informationen zu seinem Code bekommen.</p>
<pre class="brush: csharp; title: ; notranslate">
protected void myButton_Click(object sender, EventArgs e)
{
    using (SPMonitoredScope scopeButtonPushed = new SPMonitoredScope(&quot;Button action&quot;))
    {
        // dummy sleep action
        Thread.Sleep(5000);
        l.Text = &quot;Meine Daten: &quot;;

        string myData = GenerateLabelData();
        l.Text += myData;
    }
}

private string GenerateLabelData()
{
    // z.B. lesen von daten aus einer datenbank
    using (SPMonitoredScope scopeGetData = new SPMonitoredScope(&quot;Get user information&quot;))
    {
        // ... und noch ein dummy sleep
        Thread.Sleep(3000);
        return &quot;Daniel Lindemann&quot;;
    }
}
</pre>
<p>In diesem Beispiel wird die Aktion &#8220;Get user information&#8221; innerhalb der Aktion &#8220;Button action&#8221; ausgeführt.<br />
Dies erzeugt folgende Ausgabe im Developer Dashboard:<br />
<div id="attachment_330" class="wp-caption aligncenter" style="width: 410px"><a href="http://www.dlindemann.de/blog/wp-content/uploads/2010/05/usingdd.png" rel="lightbox[329]"><img src="http://www.dlindemann.de/blog/wp-content/uploads/2010/05/usingdd.png" alt="Informationen im Developer Dashboard" title="Informationen im Developer Dashboard" width="400" class="size-full wp-image-330" /></a><p class="wp-caption-text">Informationen im Developer Dashboard</p></div>
</p>
<p><h4>Wichtige Ereignisse protokollieren</h4>
<p>Auf der rechten Seite des Developer Dashboards findet man die Spalte <b>Assertionen und kritische Ereignisse</b> bzw. <b>Asserts and Critical Events</b> in der englischen Version.<br />
Wie der Name schon verrät können hier kritische Ereignisse Überprüft werden.<br />
Man sollte diese Funktion benutzten um darauf hinzuweisen, dass etwas nicht wie gewünscht ausgeführt wurde. Dazu benutzt man die statische Methode <b>AddDataToScope</b> der Klasse <b>SPCriticalTraceCounter</b> die sich ebenfalls im Namespace <b>Microsoft.SharePoint.Utilities</b> befindet.<br />
Als Beispiel ändere ich die Methode GenerateLabelData() sodass ein Eintrag zu den Ereignissen hinzugefügt wird:</p>
<pre class="brush: csharp; title: ; notranslate">
private string GenerateLabelData()
{
    // z.B. lesen von daten aus einer datenbank
    using (SPMonitoredScope scopeGetData = new SPMonitoredScope(&quot;Get user information&quot;))
    {
        // ... und noch ein dummy sleep
        Thread.Sleep(3000);
        SPCriticalTraceCounter.AddDataToScope(2501, &quot;Database problem&quot;, 1, &quot;Database query took long time&quot;);
        return &quot;Daniel Lindemann&quot;;
    }
}
</pre>
<p>Als 3. Parameter erhält die Methode ein Flag, das beschreibt um welche Art von Meldung es sich handelt.<br />
Folgende Meldungen sind möglich:</p>
<ul>
<li>1 = Critical</li>
<li>4 = Exception</li>
<li>6 = Assert</li>
<li>8 = Warning</li>
<li>10 = Unexpected</li>
<li>15 = Monitorable</li>
</ul>
<p>Diese Methode um den Ablauf des Codes zu verfolgen hat jedoch einen Nachteil. Es wird immer der komplette StackTrace mitgespeichert und somit kann die Antwort des Servers um einige kB anwachsen.<br />
Darum sollte die Methode nicht für jedes Problem das auftreten kann aufgerufen werden.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.dlindemann.de/blog/2010/05/14/entwickeln-mit-hilfe-des-developer-dashboards/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>ShareCamp 2010 / Session</title>
		<link>http://www.dlindemann.de/blog/2010/04/14/sharecamp-2010-session/</link>
		<comments>http://www.dlindemann.de/blog/2010/04/14/sharecamp-2010-session/#comments</comments>
		<pubDate>Wed, 14 Apr 2010 19:39:29 +0000</pubDate>
		<dc:creator>Daniel Lindemann</dc:creator>
				<category><![CDATA[Community]]></category>
		<category><![CDATA[SharePoint]]></category>

		<guid isPermaLink="false">http://www.dlindemann.de/blog/?p=319</guid>
		<description><![CDATA[Am Wochenende war das erste Barcamp der SharePoint Community. Das mit fast 200 Besuchern ausgebuchte Event war ein voller Erfolg bei dem man sich mit anderen SharePoint Enthusiasten austauschen konnte. Mit über 40 Sessions hatte die Unkonferenz eine Menge zu bieten. Die Vorträge gingen von Konfigurationsthemen, über Workflows bis zu Entwicklungsthemen. Alles sehr ausgewogen. Eine [...]]]></description>
			<content:encoded><![CDATA[<p>
Am Wochenende war das erste Barcamp der SharePoint Community.<br />
Das mit fast 200 Besuchern ausgebuchte Event war ein voller Erfolg bei dem man sich mit anderen SharePoint Enthusiasten austauschen konnte.<br />
Mit über 40 Sessions hatte die Unkonferenz eine Menge zu bieten. Die Vorträge gingen von Konfigurationsthemen, über Workflows bis zu Entwicklungsthemen. Alles sehr ausgewogen.<br />
Eine Kleinigkeit habe ich dennoch zu bemängeln: Ich hätte mir mehr Entwicklersessions gewünscht <img src='http://www.dlindemann.de/blog/wp-includes/images/smilies/icon_biggrin.gif' alt=':D' class='wp-smiley' />  <img src='http://www.dlindemann.de/blog/wp-includes/images/smilies/icon_razz.gif' alt=':P' class='wp-smiley' />  .</p>
<p>Sollte es nächstes Jahr auch ein ShareCamp geben bin ich wieder mit Freude dabei.</p>
<p><a href="http://www.dlindemann.de/blog/wp-content/uploads/2010/02/born2share.gif" rel="lightbox[319]"><img src="http://www.dlindemann.de/blog/wp-content/uploads/2010/02/born2share.gif" alt="born2share" title="born2share" width="254" height="50" class="aligncenter size-full wp-image-268" /></a></p>
<p>Eindrücke vom ersten ShareCamp gibts auf <a href="http://www.sharecamp.de">http://www.sharecamp.de</a>
</p>
<p>
Ich möchte mich auch nochmal bei allen Besuchern meiner Session zum Thema <b>Ribbon Customizing im SharePoint 2010</b> bedanken.<br />
Wie versprochen sind hier die Slides und Beispiele.</p>
Note: There is a file embedded within this post, please visit this post to download the file.
<p>
<em>EDIT: Hatte Probleme mit meinem Webserver. Jetzt funktioniert der Download aber <img src='http://www.dlindemann.de/blog/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </em></p>
]]></content:encoded>
			<wfw:commentRss>http://www.dlindemann.de/blog/2010/04/14/sharecamp-2010-session/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Bing Maps im Sharepoint</title>
		<link>http://www.dlindemann.de/blog/2010/03/15/bing-maps-im-sharepoint/</link>
		<comments>http://www.dlindemann.de/blog/2010/03/15/bing-maps-im-sharepoint/#comments</comments>
		<pubDate>Mon, 15 Mar 2010 16:12:28 +0000</pubDate>
		<dc:creator>Daniel Lindemann</dc:creator>
				<category><![CDATA[.NET]]></category>
		<category><![CDATA[SharePoint]]></category>
		<category><![CDATA[ASP.NET]]></category>

		<guid isPermaLink="false">http://www.dlindemann.de/blog/?p=276</guid>
		<description><![CDATA[Im aktuellen .NET Magazin ist ein schöner Bericht von Tobias Richling über das Entwickeln von Webanwendungen die geographische Daten per Bing Maps visualisieren. Dabei benutzt er ein Bing Maps ASP.NET Control, das auf Codeplex veröffentlicht wurde. Nachdem ich den Artikel durchgelesen habe, dachte ich mir: &#8220;Hey, Sharepoint mit Bing Maps ausstatten &#8230; wieso nicht?&#8221; Das [...]]]></description>
			<content:encoded><![CDATA[<p>
Im aktuellen .NET Magazin ist ein schöner Bericht von Tobias Richling über das Entwickeln von Webanwendungen die geographische Daten per Bing Maps visualisieren.<br />
Dabei benutzt er ein <a href="http://bingmapsasp.codeplex.com/">Bing Maps ASP.NET Control</a>, das auf Codeplex veröffentlicht wurde.<br />
<br />
Nachdem ich den Artikel durchgelesen habe, dachte ich mir: &#8220;Hey, Sharepoint mit Bing Maps ausstatten &#8230; wieso nicht?&#8221;<br />
Das Ergebnis lies nicht lange auf sich warten. Deshalb möchte ich hier zeigen wie man Bing Maps per Webpart in den Sharepoint 2010 einbinden kann.</p>
<div id="attachment_282" class="wp-caption aligncenter" style="width: 410px"><a href="http://www.dlindemann.de/blog/wp-content/uploads/2010/03/bingMapsOverview1.png" rel="lightbox[276]"><img src="http://www.dlindemann.de/blog/wp-content/uploads/2010/03/bingMapsOverview1.png" alt="" title="Bing Maps im Sharepoint 2010" width="400" class="size-full wp-image-282" /></a><p class="wp-caption-text">Bing Maps im Sharepoint 2010</p></div>
<p><h4>Bing Maps ASP.NET Control anpassen</h4>
<p>Das Bing Maps ASP.NET Control ist ein Wrapper, der um den Bing Maps Service gelegt wurde. Das Steuerelement gehörte zum Live SDK wurde aber wieder entfernt.<br />
Der Vorteil dieses Steuerelements ist, dass man durch das Setzen von wenigen Eigenschaften eine Bing Map angezeigt bekommt ohne eine Zeile Javascript. Dennoch ist es möglich die angezeigte Karte mittels <a href="http://www.microsoft.com/maps/developers/">Bing Maps AJAX SDK</a> zu ändern, was einem Entwickler bei Sharepoint 2010 Projekten sehr entgegen kommt <img src='http://www.dlindemann.de/blog/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' />  .</p>
<p>Auf Codeplex steht nur der Quellcode des Steuerelements zu Verfügung. Da die Assembly, um sie in Sharepoint benutzen zu können, mit einem Schlüssel signiert sein muss , ist das sogar ein Vorteil.<br />
<br />
Wenn man sich den <a href="http://bingmapsasp.codeplex.com/SourceControl/list/changesets">Quellcode</a> geladen hat, kann man die Solution in Visual Studio öffnen und die Assembly signieren. Das Projekt das einen Schlüssel braucht hat den Namen <b>Microsoft.Live.ServerControls.VE</b>.<br /> Ist dieser Schritt erledigt kann man das Projekt neu erstellen. Das benötigte Steuerelement findet man dann im Projektordner unter Sourcebin.
</p>
<p><h4>Erstellen eines Bing Map Webparts</h4>
<p>Um das Bing Maps Webpart zu erstellen, benutzt man am besten die Vorlage für ein normales Webpart (die Vorlage des Visual Webpart finde ich ein wenig oversized).<br />
Nachdem man die Referenz zur Bing Maps Control hinzugefügt hat, muss man im Solution Packet Editor noch die Assembly als SafeControl eintragen, damit sie mit auf den Server deployt wird.<br />
Das Solution Paket sollte danach so aussehen:</p>
<pre class="brush: xml; title: ; notranslate">
&lt;Solution xmlns=&quot;http://schemas.microsoft.com/sharepoint/&quot; SolutionId=&quot;3dd182a9-21c3-4260-9177-de19e39420fe&quot; SharePointProductVersion=&quot;14.0&quot;&gt;
  &lt;Assemblies&gt;
    &lt;Assembly Location=&quot;Microsoft.Live.ServerControls.VE.dll&quot; DeploymentTarget=&quot;GlobalAssemblyCache&quot;&gt;
      &lt;SafeControls&gt;
        &lt;SafeControl Assembly=&quot;Microsoft.Live.ServerControls.VE, Version=0.1.0.0, Culture=neutral, PublicKeyToken=null&quot; Namespace=&quot;Microsoft.Live.ServerControls.VE&quot; TypeName=&quot;*&quot; /&gt;
        &lt;SafeControl Assembly=&quot;Microsoft.Live.ServerControls.VE, Version=0.1.0.0, Culture=neutral, PublicKeyToken=null&quot; Namespace=&quot;Microsoft.Live.ServerControls.VE.Extenders&quot; TypeName=&quot;*&quot; /&gt;
      &lt;/SafeControls&gt;
    &lt;/Assembly&gt;
    &lt;Assembly Location=&quot;BingMapsWebpart_SP2010.dll&quot; DeploymentTarget=&quot;GlobalAssemblyCache&quot;&gt;
      &lt;SafeControls&gt;
        &lt;SafeControl Assembly=&quot;BingMapsWebpart_SP2010, Version=1.0.0.0, Culture=neutral, PublicKeyToken=2cf157c772a0dd57&quot; Namespace=&quot;BingMapsWebpart_SP2010.BingMaps&quot; TypeName=&quot;*&quot; /&gt;
      &lt;/SafeControls&gt;
    &lt;/Assembly&gt;
  &lt;/Assemblies&gt;
  &lt;FeatureManifests&gt;
    &lt;FeatureManifest Location=&quot;BingMapsWebpart_SP2010_BingMapsFeatureFeature.xml&quot; /&gt;
  &lt;/FeatureManifests&gt;
&lt;/Solution&gt;
</pre>
<p>Je nachdem wie man das Webpart benutzen möchte muss man noch die Deployment Eigenschaften anpassen.<br />
Für mein Beispiel benutze ich folgende Einstellungen:</p>
<ul>
<li>Deployment der Assemblies im GAC</li>
<li>Webpart Feature Bereich Site</li>
</ul>
<p>Zurück zum eigentlichen Thema.<br />
Im Quellcode des Webparts muss man erst einmal feststellen ob ein ScriptManager auf der Seite vorhanden ist, da es sich beim Bing Maps ASP.NET Control um ein Ajax Control handelt. Ist kein ScriptManager auf der Seite vorhanden muss man einen hinzufügen! Am besten Überschreibt man dafür die Methode OnInit( ).</p>
<pre class="brush: csharp; title: ; notranslate">
protected override void OnInit(EventArgs e)
{
    base.OnInit(e);

    // enables script manager
    ScriptManager sm = ScriptManager.GetCurrent(this.Page);
    if (sm == null)
    {
        // register scriptmanager
        ScriptManager newScriptManager = new ScriptManager() { ID = &quot;bingMapsScriptManager&quot;, ScriptMode = ScriptMode.Auto };
        this.Page.Form.Controls.Add(newScriptManager);
    }
}
</pre>
<p>Fehlt nur noch eine Bing Map. Um diese anzeigen zu lassen erstellt man in der Methode CreateChildControls( ) das Objekt <b>Map</b>. Das Map-Objekt ist das Hauptobjekt das benötigt wird und befindet sich im Namespace Microsoft.Live.ServerControls.VE. Es spiegelt wie der Name schon vermuten lässt eine Bing Map wieder.<br />
Man könnte sich die Map jetzt schon anzeigen lassen. Aber ich möchte den Benutzer gerne auf eine Standardansicht leiten. So kann man mittels der Eigenschaft <b>Dashboard</b> das Bing Maps Menü ein- bzw. ausblenden und die Eigenschaft <b>Center</b> gibt an welchen Punkt das Map-Objekt zu Beginn zentrieren soll.<br />
Dazu gibt es noch viele weitere Eigenschaften auf die ich hier nicht weiter eingehen möchte, da es sehr viele sind.</p>
<p>Der Code um Berlin in der Karte anzeigen zu lassen sieht folgendermaßen aus:</p>
<pre class="brush: csharp; title: ; notranslate">
protected override void CreateChildControls()
{
    base.CreateChildControls();

    Map bingMap = new Map() { ID = &quot;bingMap&quot;, Height = new Unit(600), Width = new Unit(100.00, UnitType.Percentage) };
    bingMap.ZoomLevel = 10;
    bingMap.Dashboard = true;
    bingMap.Center = new LatLong(52.5070, 13.3615);    // Berlin
    bingMap.Locale = SupportedLocales.de_de;    // UI in deutsch
    bingMap.ScaleBarDistanceUnit = DistanceUnit.Kilometers;    // MaÃŸeinheit in KM

    this.Controls.Add(bingMap);
}
</pre>
<p>Jetzt kann man das Webpart testen. Einfach das Debuggen starten und das Bing Map Webpart auf einer Seite hinzufügen.
</p>
<p><h4>Daten in Bing Map anzeigen</h4>
<p>Natürlich kann man sich mit Bing Maps nicht nur eine Karte anzeigen lassen. Wie auch bei vielen anderen Web Map Diensten kann man Punkte auf der Karte hervorheben. Dazu gehören z.B. Punkte auf Objekte, Routen, hervorgehobene Bereiche.<br />
Ermöglicht wird das Ganze im Bing Maps ASP.NET Control durch Shapes. Wenn ich mir also eine Reißzwecke am Brandenburger Tor hinzufügen möchte muss ich ein Shape in Gestalt einer Reißzwecke hinzufügen.</p>
<pre class="brush: csharp; title: ; notranslate">
Shape brandenburgerTor = new Shape(ShapeType.Pushpin, new LatLongWithAltitude(52.51625, 13.37767));
brandenburgerTor.Title = &quot;Brandenburger Tor&quot;;
brandenburgerTor.Description = &quot;Das Wahrzeichen Berlins&quot;;
brandenburgerTor.MoreInfoURL = &quot;http://de.wikipedia.org/wiki/Brandenburger_Tor&quot;;
bingMap.AddShape(brandenburgerTor);
</pre>
<p>Die wichtigesten Informationen muss man im Konstruktor übergeben. <b>ShapeType.Pushpin</b> gibt an, dass der Shape als Reißzwecke gerendert wird. Danach folgen die Koordinaten für das Brandenburger Tor als LatLongWithAltitude-Objekt.<br />
Die Eigenschaften <b>Title</b>, <b>Description</b> und <b>MoreInfoURL</b> geben an was angezeigt werden soll, wenn man mit der Maus über den Reißzwecken fährt.<br />
<div id="attachment_311" class="wp-caption aligncenter" style="width: 410px"><a href="http://www.dlindemann.de/blog/wp-content/uploads/2010/03/bingMapsOverview2.png" rel="lightbox[276]"><img src="http://www.dlindemann.de/blog/wp-content/uploads/2010/03/bingMapsOverview2.png" alt="" title="Ortsmarke in Bing Maps" width="400" class="size-full wp-image-311" /></a><p class="wp-caption-text">Ortsmarke in Bing Maps</p></div>
</p>
<p><h4>Fazit</h4>
<p>Durch Bing Maps und das Bing Maps ASP.NET Control ist es auf einfache Art und Weise möglich geographische Daten im Sharepoint zu visualieren. Man könnte sich beispielsweise eine Liste mit Konferenzen halten und speichert sich in einem zusätzlichen Feld wo sie statt finden. Für mich ist es zudem eine Abwechslung zu den einfach gehaltenen Listen.<br />Ob Bing Maps in ASP.NET / Sharepoint Anwendungen eine Zukunft hat wird sich noch zeigen. Mir hat das Entwickeln dieser Beispielapplikation auf jeden fall Spaß gemacht.</p>
Note: There is a file embedded within this post, please visit this post to download the file.
]]></content:encoded>
			<wfw:commentRss>http://www.dlindemann.de/blog/2010/03/15/bing-maps-im-sharepoint/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Erstes Sharepoint BarCamp</title>
		<link>http://www.dlindemann.de/blog/2010/02/09/erstes-sharepoint-barcamp/</link>
		<comments>http://www.dlindemann.de/blog/2010/02/09/erstes-sharepoint-barcamp/#comments</comments>
		<pubDate>Tue, 09 Feb 2010 10:23:08 +0000</pubDate>
		<dc:creator>Daniel Lindemann</dc:creator>
				<category><![CDATA[Community]]></category>
		<category><![CDATA[SharePoint]]></category>

		<guid isPermaLink="false">http://www.dlindemann.de/blog/?p=267</guid>
		<description><![CDATA[Am 10. und 11.4.2010 veranstaltet die Firma DataOne zusammen mit Microsoft das erste Sharepoint BarCamp in der Microsoft Zentrale in Unterschleißheim. Ein BarCamp ist eine Art Konferenz bei der es jedoch statt Besuchern nur aktive Teilnehmer gibt. Die einzelnen Sessions werden dabei meist zu beginn des BarCamps aufgenommen und geplant. Jeder Teilnehmer ist dazu aufgefordert [...]]]></description>
			<content:encoded><![CDATA[<p>
Am 10. und 11.4.2010 veranstaltet die Firma DataOne zusammen mit Microsoft das erste Sharepoint BarCamp in der Microsoft Zentrale in Unterschleißheim.<br />
Ein BarCamp ist eine Art Konferenz bei der es jedoch statt Besuchern nur aktive Teilnehmer gibt. Die einzelnen Sessions werden dabei meist zu beginn des BarCamps aufgenommen und geplant. Jeder Teilnehmer ist dazu aufgefordert eigene Ideen/Sessions vorzuschlagen. Diese müssen nicht zwingend geplant sein. Ich habe selbst schon guten Sessions beigewohnt, die innerhalb von 5min entstanden sind!
</p>
<p><a href="http://www.dlindemann.de/blog/wp-content/uploads/2010/02/born2share.gif" rel="lightbox[267]"><img src="http://www.dlindemann.de/blog/wp-content/uploads/2010/02/born2share.gif" alt="born2share" title="born2share" width="254" height="50" class="aligncenter size-full wp-image-268" /></a></p>
<p>
Weitere Informationen gibt es auf der Seite <a href="http://www.sharecamp.de">[ShareCamp] born2share</a>.<br />
Wenn das mit meiner Übernachtungsmöglichkeit klappt (wovon ich ausgehen), werde ich auf jeden fall dort sein!<br />
Bleibt nur noch abzuwarten ob ich auf dem ShareCamp meine erste Session halten werden und über welches Thema *grübel* <img src='http://www.dlindemann.de/blog/wp-includes/images/smilies/icon_biggrin.gif' alt=':D' class='wp-smiley' /></p>
]]></content:encoded>
			<wfw:commentRss>http://www.dlindemann.de/blog/2010/02/09/erstes-sharepoint-barcamp/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

