Skip to main content

Le blog de Stéphane Eyskens

Go Search
Le blog de Stéphane Eyskens
  

 

 

 My codeplex tools

FR/EN

Retrouvez mon espace sur Developpez.com, l'espace Sharepoint sur developpez.com. Pour toute question relative à Sharepoint, vous pouvez tenter votre chance dans ce forum 

Reduce All
 Custom Field + displaypattern + AJAX en CAML
Salut,
 
J'ai récemment discuté avec une personne qui souhaitait afficher des données dynamiques provenant d'une DB externe à partir du displaypattern d'un custom field.
 
Comme vous le savez, le displaypattern est utilisé pour décrire comment une colonne doit s'afficher en mode liste.
 
Pour plus d'infos sur les patterns, vous pouvez consulter ce lien
 
 
Ces patterns ne sont pas tous simples à utiliser et le but de ce billet n'est pas de les expliquer mais simplement de faire un POC démontrant la possibilité d'utiliser de l'AJAX dans les patterns CAML.
 
Je l'ai juste fait pour le fun et n'ai pas encore eu à le réaliser dans un projet.
 
D'ailleurs si cela vous arrive, pensez à utiliser le BDC si possible...
 
 
Bon, voici néanmoins le scénario du POC
 
Disons que vous avez une liste SharePoint dans laquelle vous avez un custom field qui stocke l' ID d'un enregistrement de DB. Vous voulez offrir aux utilisateurs la possibilité de recevoir le libellé correspondant à cet ID de manière dynamique comme illustré ci-dessous
 
 
Comme vous pouvez le constater, J'ai les IDs qui viennent de la DB et je peux récupérer les libellés correspondants en cliquant sur l'image à côté des IDs.
 
Pour pouvoir obtenir ce résultat, vous devez faire ceci:
 
- Developper un custom field
 
- Developper le CAML du fichier FLDTYPES_xxx.xml associé à votre custom field et dans lequel vous devez inclure le code javascript
 
- Developper une page server ou utiliser un web service qui retourne une réponse XML aux requêtes AJAX.
 
Ceci fait, en cliquant sur une image, vous obtiendrez ceci:
 
 
Voici le code
 
Le custom field
 
C'est un simple POC qui utilise un SPFieldText hyper basique, juste cette classe suffit
 
using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.SharePoint;

namespace AjaxRawField
{
    public class AjaxRawView : SPFieldText
    {
        public AjaxRawView(SPFieldCollection fields, string fieldName)
            : base(fields, fieldName)
        {
           
        }
        public AjaxRawView(Microsoft.SharePoint.SPFieldCollection fields, string typeName, string displayName)
            : base(fields, typeName, displayName)
        {

           
        }
    }
}
La page serveur
 
Rappelez-vous qu'il s'agit juste d'un POC, donc pour simplifier les choses, je n'ai pas été chercher les données d'une DB..Je ne fais que renvoyer du XML mais avec un peu d'imagination, celui-ci pourrait être généré après une query DB.
 
<%@ Page Language="C#" %>
<%@ Import Namespace="System.Collections.Generic" %>
<%@ Import Namespace="System.Threading" %>
<script runat="server">
   
        protected override void Render(HtmlTextWriter writer)
        {
            try
            {
                Thread.Sleep(1000);      
                Response.ContentType = "text/xml";
                int Id = Convert.ToInt16(Request.QueryString["Id"]);
                List<string> Ids = new List<string>();
                for (int i = 0; i < 10; i++)
                {
                   Ids.Add(string.Format("Label {0}",i.ToString()));
                }
                Response.Write(string.Format("<?xml version=\"1.0\" encoding=\"utf-8\"?><Root><Label Text=\"{0}\"/></Root>",Ids[Id]));
               
            }
            catch
            {
                Response.Write("<?xml version=\"1.0\" encoding=\"utf-8\"?><Root><Label Text=\"Not found\"/></Root>");
            }
           
        }
</script>

Si vous copiez/collez ce code dans une page aspx et la déployez dans le répertoire LAYOUTS, ça devrait suffire.
 
 
Le fichier CAML
 
C'est ici que ça se complique!
 
L'idée est d'écrire les fonctions AJAX dans le headerpattern du custom field et de les appeler  dans le displaypattern
 
<?xml version="1.0" encoding="utf-8"?>
<FieldTypes>
 <FieldType>
  <Field Name="TypeName">AjaxRawField</Field>
  <Field Name="ParentType">Text</Field>  
  <Field Name="TypeDisplayName">AjaxRawField</Field>
  <Field Name="TypeShortDescription">AjaxRawField</Field>
  <Field Name="UserCreatable">TRUE</Field>
  <Field Name="ShowInListCreate">TRUE</Field>
  <Field Name="ShowInSurveyCreate">TRUE</Field>
  <Field Name="ShowInDocumentLibraryCreate">TRUE</Field>
  <Field Name="ShowInColumnTemplateCreate">TRUE</Field>
  <Field Name="FieldTypeClass">AjaxRawField.AjaxRawView, AjaxRawField,Version=1.0.0.0, Culture=neutral, PublicKeyToken=a17af6dda41cb365</Field>  
  <Field Name="MaxLength">2000</Field>
  <RenderPattern Name="HeaderPattern">
   <Switch>
    <Expr>
     <Property Select='Filterable'/>
    </Expr>
    <Case Value="FALSE"> </Case>
    <Default>
     <Switch>
      <Expr>
       <GetVar Name='Filter'/>
      </Expr>
      <Case Value='1'>
       <HTML><![CDATA[<SELECT ID="diidFilter]]></HTML>
       <Property Select='Name'/>
       <HTML><![CDATA[" TITLE=]]></HTML>
       <HTML>"$Resources:spscore,BusinessDataField_Filterby;</HTML>
       <Property Select='DisplayName' HTMLEncode='TRUE'/>
       <HTML><![CDATA[" OnChange='FilterField("]]></HTML>
       <GetVar Name="View"/>
       <HTML><![CDATA[",]]></HTML>
       <ScriptQuote>
        <Property Select='Name' URLEncode="TRUE"/>
       </ScriptQuote>
       <HTML>
        <![CDATA[,this.options[this.selectedIndex].value, this.selectedIndex, 0);' dir="]]>
       </HTML>
       <Property Select="Direction" HTMLEncode="TRUE"/>
       <HTML><![CDATA[">]]></HTML>
       <FieldFilterOptions BooleanTrue="$Resources:spscore,BusinessDataField_Yes;"
         BooleanFalse="$Resources:spscore,BusinessDataField_No;"
         NullString="$Resources:spscore,BusinessDataField_Empty;"
         AllItems="$Resources:spscore,BusinessDataField_All;"></FieldFilterOptions>
       <HTML><![CDATA[</SELECT><BR>]]></HTML>
      </Case>
     </Switch>
    </Default>
   </Switch>
   <Switch>
    <Expr>
     <Property Select='Sortable'/>
    </Expr>
    <Case Value="FALSE">
     <Property Select='DisplayName' HTMLEncode="TRUE"/>
    </Case>
    <Default>
     <Switch>
      <Expr>
       <GetVar Name='SortDisable'/>
      </Expr>
      <Case Value='TRUE'>
       <Property Select='DisplayName' HTMLEncode="TRUE"/>
      </Case>
      <Default>
       <HTML><![CDATA[<A ID="diidSort]]></HTML>
       <Property Select='Name'/>
       <HTML>
        <![CDATA[" TITLE=]]>
       </HTML>
       <HTML>"$Resources:spscore,BusinessDataField_Sortby;</HTML>
       <Property Select='DisplayName' HTMLEncode='TRUE'/>
       <HTML><![CDATA[" SORTINGFIELDS="]]></HTML>
       <FieldSortParams/>
       <HTML><![CDATA[" HREF="javascript:" OnClick='javascript:SubmitFormPost("]]></HTML>
       <ScriptQuote NotAddingQuote="TRUE">
        <PageUrl/>
        <HTML><![CDATA[?]]></HTML>
        <FieldSortParams/>
       </ScriptQuote>
       <HTML>
        <![CDATA[");javascript:return false;'>]]>
       </HTML>
       <Property Select='DisplayName' HTMLEncode="TRUE"/>
       <HTML><![CDATA[</A><IMG SRC="]]></HTML>
       <FieldSortImageURL/>
       <HTML><![CDATA[" ALT=]]></HTML>
       <Switch>
        <Expr>
         <GetVar Name='SortDir'/>
        </Expr>
        <Case Value='Asc'>
         <HTML>$Resources:spscore,BusinessDataField_Asc;</HTML>
        </Case>
        <Case Value='Desc'>
         <HTML>$Resources:spscore,BusinessDataField_Desc;</HTML>
        </Case>
        <Default>
         <HTML>""</HTML>
        </Default>
       </Switch>
       <HTML><![CDATA[ BORDER=0>]]></HTML>
      </Default>
     </Switch>
    </Default>
   </Switch>
   <HTML><![CDATA[<IMG SRC="]]></HTML>
   <FieldFilterImageURL/>
   <HTML><![CDATA[" BORDER=0 ALT=]]></HTML>
   <HTML>""</HTML>
   <HTML><![CDATA[>]]></HTML>
   <HTML>
    <![CDATA[
    <script language="javascript">
    ReturnedIds = new Array();
    HttpObject = null;
    
    function DoQuery(Id)
    {
    
     if(HttpObject == null) 
     {
      if (window.XMLHttpRequest)
      {
       HttpObject = new XMLHttpRequest();
      }
      else if (window.ActiveXObject)
      {
       HttpObject = new ActiveXObject("MSXML2.XMLHTTP.3.0");
      }      
     }
     HttpObject.DOMTarget = document.getElementById("__"+Id);     
     if(HttpObject.DOMTarget && HttpObject.DOMTarget.innerHTML.indexOf("-")==-1)
     {
      HttpObject.DOMTarget.innerHTML = HttpObject.DOMTarget.innerHTML + "- waiting for server...";
      HttpObject.open("GET", "/_layouts/GetTitles.aspx?id="+Id, true);
      HttpObject.setRequestHeader("Content-Type","text/xml; charset=utf-8");
      HttpObject.setRequestHeader("Host", "localhost");
      readyStateChangeHandler = AjaxAnswer;
      HttpObject.onreadystatechange = readyStateChangeHandler;
      HttpObject.send();
     }
    }
    
    function AjaxAnswer()
    {
     
      if (HttpObject.readyState==4 && HttpObject.status==200)
      {     
        var xml = HttpObject.responseXML;     
     if (xml.documentElement)
     {
       var rows = xml.documentElement.getElementsByTagName("z:Label");
       if (rows.length==0)
       {
         rows = xml.documentElement.getElementsByTagName("Label");
       }
      
       if (rows.length > 0)
       {
         for (var i = 0; i < rows.length; i++)
      {
       
        if (rows[i].getAttributeNode("Text")!=null)
        {
       
       HttpObject.DOMTarget.innerHTML = parseInt(HttpObject.DOMTarget.innerHTML) + "-" +rows[i].getAttributeNode("Text").nodeValue;
         
           }       
      }
          }
      }
     }    
      }
      </script>
      ]]>
    </HTML>
   </RenderPattern>

  <RenderPattern Name="DisplayPattern">
   <HTML><![CDATA[<table><tr><td id="__]]></HTML>
   <Column HTMLEncode="TRUE"/>
   <HTML><![CDATA[">]]></HTML>
   <Column HTMLEncode="TRUE"/>
   <HTML><![CDATA[</td><td><img onclick="DoQuery(']]></HTML>
   <Column HTMLEncode="TRUE"/>
   <HTML><![CDATA[')" src="_layouts/images/BDUPDATE.GIF"/></td></tr></table>]]></HTML>
   
   
  </RenderPattern>
  
 </FieldType>
</FieldTypes>
 
------------------------------------------------------------------
 
Voilà c'est fait! Simple non?
 
Déployez ce fichier XML dans le répertoire XML du 12 et vous aurez une nouvelle colonne vous permettant d'effectuer du rendering dynamique en mode liste.
Posted by Stéphane Eyskens at 7/3/2008 11:35:26 PM | Comments(0)
 CustomField + Dynamic data (AJAX) in displaypattern
Hello,
 
I've recently discussed with someone who wanted to render  dynamic data coming from an external database from within the CAML displaypattern of a custom field.
 
As you know, the displaypattern is used to describe the display behavior of a list column when rendered in raw view.
 
To have more info on patterns, you can refer to MSDN at the following link
 
 
All those patterns are not so easy to use and my purpose here is not to explain them but just to make a kind of POC on using AJAX within the CAML patterns. I just did if for fun and I didn't have to use that in a project so far...:)
 
Also, remember that if possible, the preferred option for such requirements is to use the BDC
 
 
Well, this said, here is the scenario of the POC
 
Say, you've got a SharePoint list in which you store a custom field that holds the ID value of a Database record. You want to give users the possibility to retrieve the label associated to the ID dynamically from within a list view.
 
 
As you can see here, I've got the IDs coming from the database and I want to retrieve the corresponding label by clicking on the picture next to the ID.
 
To achieve this behavior, you need at list three things
 
- Develop a custom field (derived from whatever type)
 
- Develop the necessary CAML file FLDTYPES_xxx.xml associated to your custom fields in which you'll include the javascript code
 
- Develop a server page or use a web service or whatever that will return the XML answer to the AJAX query.
 
Once done, when clicking on a picture you'll get the following
 
 
 
So, here is the code
 
The custom field
 
I just make this POC using a SPFieldText, so just having this class is enough
 
using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.SharePoint;

namespace AjaxRawField
{
    public class AjaxRawView : SPFieldText
    {
        public AjaxRawView(SPFieldCollection fields, string fieldName)
            : base(fields, fieldName)
        {
           
        }
        public AjaxRawView(Microsoft.SharePoint.SPFieldCollection fields, string typeName, string displayName)
            : base(fields, typeName, displayName)
        {

           
        }
    }
}
The server page
 
Here remember that it's just a POC, so the data doesn't come from a DB to keep things simple...I just return some XML but with a bit of imagination, this could be produced after a DB query :)
 
<%@ Page Language="C#" %>
<%@ Import Namespace="System.Collections.Generic" %>
<%@ Import Namespace="System.Threading" %>
<script runat="server">
   
        protected override void Render(HtmlTextWriter writer)
        {
            try
            {
                Thread.Sleep(1000);      
                Response.ContentType = "text/xml";
                int Id = Convert.ToInt16(Request.QueryString["Id"]);
                List<string> Ids = new List<string>();
                for (int i = 0; i < 10; i++)
                {
                   Ids.Add(string.Format("Label {0}",i.ToString()));
                }
                Response.Write(string.Format("<?xml version=\"1.0\" encoding=\"utf-8\"?><Root><Label Text=\"{0}\"/></Root>",Ids[Id]));
               
            }
            catch
            {
                Response.Write("<?xml version=\"1.0\" encoding=\"utf-8\"?><Root><Label Text=\"Not found\"/></Root>");
            }
           
        }
</script>

If you copy/paste the above code within a aspx page and you deploy it to the LAYOUTS folder, it's enough.
 
 
CAML File
 
And now, here is the big deal :), writing the CAML in the custom field definition file
 
The idea is to write the ajax functions in the headerpattern of the custom field and to call some of these in the displaypattern when rendering list items
 
 
<?xml version="1.0" encoding="utf-8"?>
<FieldTypes>
 <FieldType>
  <Field Name="TypeName">AjaxRawField</Field>
  <Field Name="ParentType">Text</Field>  
  <Field Name="TypeDisplayName">AjaxRawField</Field>
  <Field Name="TypeShortDescription">AjaxRawField</Field>
  <Field Name="UserCreatable">TRUE</Field>
  <Field Name="ShowInListCreate">TRUE</Field>
  <Field Name="ShowInSurveyCreate">TRUE</Field>
  <Field Name="ShowInDocumentLibraryCreate">TRUE</Field>
  <Field Name="ShowInColumnTemplateCreate">TRUE</Field>
  <Field Name="FieldTypeClass">AjaxRawField.AjaxRawView, AjaxRawField,Version=1.0.0.0, Culture=neutral, PublicKeyToken=a17af6dda41cb365</Field>  
  <Field Name="MaxLength">2000</Field>
  <RenderPattern Name="HeaderPattern">
   <Switch>
    <Expr>
     <Property Select='Filterable'/>
    </Expr>
    <Case Value="FALSE"> </Case>
    <Default>
     <Switch>
      <Expr>
       <GetVar Name='Filter'/>
      </Expr>
      <Case Value='1'>
       <HTML><![CDATA[<SELECT ID="diidFilter]]></HTML>
       <Property Select='Name'/>
       <HTML><![CDATA[" TITLE=]]></HTML>
       <HTML>"$Resources:spscore,BusinessDataField_Filterby;</HTML>
       <Property Select='DisplayName' HTMLEncode='TRUE'/>
       <HTML><![CDATA[" OnChange='FilterField("]]></HTML>
       <GetVar Name="View"/>
       <HTML><![CDATA[",]]></HTML>
       <ScriptQuote>
        <Property Select='Name' URLEncode="TRUE"/>
       </ScriptQuote>
       <HTML>
        <![CDATA[,this.options[this.selectedIndex].value, this.selectedIndex, 0);' dir="]]>
       </HTML>
       <Property Select="Direction" HTMLEncode="TRUE"/>
       <HTML><![CDATA[">]]></HTML>
       <FieldFilterOptions BooleanTrue="$Resources:spscore,BusinessDataField_Yes;"
         BooleanFalse="$Resources:spscore,BusinessDataField_No;"
         NullString="$Resources:spscore,BusinessDataField_Empty;"
         AllItems="$Resources:spscore,BusinessDataField_All;"></FieldFilterOptions>
       <HTML><![CDATA[</SELECT><BR>]]></HTML>
      </Case>
     </Switch>
    </Default>
   </Switch>
   <Switch>
    <Expr>
     <Property Select='Sortable'/>
    </Expr>
    <Case Value="FALSE">
     <Property Select='DisplayName' HTMLEncode="TRUE"/>
    </Case>
    <Default>
     <Switch>
      <Expr>
       <GetVar Name='SortDisable'/>
      </Expr>
      <Case Value='TRUE'>
       <Property Select='DisplayName' HTMLEncode="TRUE"/>
      </Case>
      <Default>
       <HTML><![CDATA[<A ID="diidSort]]></HTML>
       <Property Select='Name'/>
       <HTML>
        <![CDATA[" TITLE=]]>
       </HTML>
       <HTML>"$Resources:spscore,BusinessDataField_Sortby;</HTML>
       <Property Select='DisplayName' HTMLEncode='TRUE'/>
       <HTML><![CDATA[" SORTINGFIELDS="]]></HTML>
       <FieldSortParams/>
       <HTML><![CDATA[" HREF="javascript:" OnClick='javascript:SubmitFormPost("]]></HTML>
       <ScriptQuote NotAddingQuote="TRUE">
        <PageUrl/>
        <HTML><![CDATA[?]]></HTML>
        <FieldSortParams/>
       </ScriptQuote>
       <HTML>
        <![CDATA[");javascript:return false;'>]]>
       </HTML>
       <Property Select='DisplayName' HTMLEncode="TRUE"/>
       <HTML><![CDATA[</A><IMG SRC="]]></HTML>
       <FieldSortImageURL/>
       <HTML><![CDATA[" ALT=]]></HTML>
       <Switch>
        <Expr>
         <GetVar Name='SortDir'/>
        </Expr>
        <Case Value='Asc'>
         <HTML>$Resources:spscore,BusinessDataField_Asc;</HTML>
        </Case>
        <Case Value='Desc'>
         <HTML>$Resources:spscore,BusinessDataField_Desc;</HTML>
        </Case>
        <Default>
         <HTML>""</HTML>
        </Default>
       </Switch>
       <HTML><![CDATA[ BORDER=0>]]></HTML>
      </Default>
     </Switch>
    </Default>
   </Switch>
   <HTML><![CDATA[<IMG SRC="]]></HTML>
   <FieldFilterImageURL/>
   <HTML><![CDATA[" BORDER=0 ALT=]]></HTML>
   <HTML>""</HTML>
   <HTML><![CDATA[>]]></HTML>
   <HTML>
    <![CDATA[
    <script language="javascript">
    ReturnedIds = new Array();
    HttpObject = null;
    
    function DoQuery(Id)
    {
    
     if(HttpObject == null) 
     {
      if (window.XMLHttpRequest)
      {
       HttpObject = new XMLHttpRequest();
      }
      else if (window.ActiveXObject)
      {
       HttpObject = new ActiveXObject("MSXML2.XMLHTTP.3.0");
      }      
     }
     HttpObject.DOMTarget = document.getElementById("__"+Id);     
     if(HttpObject.DOMTarget && HttpObject.DOMTarget.innerHTML.indexOf("-")==-1)
     {
      HttpObject.DOMTarget.innerHTML = HttpObject.DOMTarget.innerHTML + "- waiting for server...";
      HttpObject.open("GET", "/_layouts/GetTitles.aspx?id="+Id, true);
      HttpObject.setRequestHeader("Content-Type","text/xml; charset=utf-8");
      HttpObject.setRequestHeader("Host", "localhost");
      readyStateChangeHandler = AjaxAnswer;
      HttpObject.onreadystatechange = readyStateChangeHandler;
      HttpObject.send();
     }
    }
    
    function AjaxAnswer()
    {
     
      if (HttpObject.readyState==4 && HttpObject.status==200)
      {     
        var xml = HttpObject.responseXML;     
     if (xml.documentElement)
     {
       var rows = xml.documentElement.getElementsByTagName("z:Label");
       if (rows.length==0)
       {
         rows = xml.documentElement.getElementsByTagName("Label");
       }
      
       if (rows.length > 0)
       {
         for (var i = 0; i < rows.length; i++)
      {
       
        if (rows[i].getAttributeNode("Text")!=null)
        {
       
       HttpObject.DOMTarget.innerHTML = parseInt(HttpObject.DOMTarget.innerHTML) + "-" +rows[i].getAttributeNode("Text").nodeValue;
         
           }       
      }
          }
      }
     }    
      }
      </script>
      ]]>
    </HTML>
   </RenderPattern>

  <RenderPattern Name="DisplayPattern">
   <HTML><![CDATA[<table><tr><td id="__]]></HTML>
   <Column HTMLEncode="TRUE"/>
   <HTML><![CDATA[">]]></HTML>
   <Column HTMLEncode="TRUE"/>
   <HTML><![CDATA[</td><td><img onclick="DoQuery(']]></HTML>
   <Column HTMLEncode="TRUE"/>
   <HTML><![CDATA[')" src="_layouts/images/BDUPDATE.GIF"/></td></tr></table>]]></HTML>
   
   
  </RenderPattern>
  
 </FieldType>
</FieldTypes>
 
------------------------------------------------------------------
 
You're done! Easy no?
 
Just deploying that XML file in the XML folder of the 12 hive will show you a new column type with AJAX call enabled in row view.
Posted by Stéphane Eyskens at 7/3/2008 11:11:46 PM | Comments(0)
 Longue Opération
Salut
 
Lorsque vous exécutez des opérations longues ou susceptibles de l'être dans SharePoint, pour faire patienter vos visiteurs, vous pouvez utiliser la classe SPLongOperation qui a été spécialement conçue pour cela.
 
Vous pouvez l'utiliser comme suit:
 
 
SPLongOperation LongOp = new SPLongOperation();
LongOp.LeadingHTML = "My long operaation..."
LongOp.Begin();
//Vos opérations longues :)
LongOp.End(ReturnUrl);
 
L'avantage est donc que pendant que votre code s'exécute, le visiteur voit le message spécifié dans LeadingHTML
 
 
long run
Posted by Stéphane Eyskens at 6/26/2008 10:21:42 PM | Comments(1)
 Long running operation
Hello,
 
When you have to perform a long running operation in SharePoint, you can use a dedicated class that's been espacially designed for that.
 
This class is SPLongOperation. You can use it this way:
 
 
SPLongOperation LongOp = new SPLongOperation();
LongOp.LeadingHTML = "My long operaation..."
LongOp.Begin();
//do what you want to do here :)
LongOp.End(ReturnUrl);
 
 
So, the advantage of that is that it will show you a message while your code is executed as illustrated here
 
long run
Posted by Stéphane Eyskens at 6/26/2008 10:19:11 PM | Comments(0)
 Copy and Paste documents from Jan Tielen
Good idea from Jan Tielen. He has developed a copy/paste feature to copy and paste documents accross the entire farm.
 
 
This adds an extra functionality since it is not possible with standard SharePoint UI's to copy and paste documents from one site collection to another except with the explorer view but the explorer view isn't always available.
 
Well done Jan!
Posted by Stéphane Eyskens at 6/19/2008 9:01:12 AM | Comments(0)
 SharePoint audiences to groups
Hi,
 
I've uploaded a tool on codeplex. This tool is designed to create SharePoint groups based on audiences.
 
Audiences can be easily created using rules and multiple criteria based on the user profiles. You don't have as much flexibility when creating SharePoint groups.
 
The idea here is to create and maintain SharePoint groups from audiences. To help you achieving this, there is a webpart as illustrated below
 
webpart
 
This webpart allows you to
 
  • Create a group from an audience without any further synchrronization (one shot)
  • Create a group & a timer job to maintain the group synchronized with the audience. You can scedule the timer job to run daily or weekly
  • An SPGridView with a menu gives you the possibility to run the execute the job manually
This webpart can only be deployed within TOP LEVEL sites. It's clearly a tool that should be used by site collection admins only!
 
It will appear in the webpart gallery. If you wish to hide it from subsites, you can give it special permissions (break inheritance on the webpart gallery).
 
 
You can download the tool and find the source code here
 
 
Note that I created that tool for my own needs and that it has never been tested in a real environment.
 
Posted by Stéphane Eyskens at 6/17/2008 6:50:28 PM | Comments(0)
 Groupes SharePoint à partir des audiences
Salut,
 
J'ai mis en ligne un outil sur codeplex. Le but de cet outil est de créer des groupes SharePoint basés sur des audiences.
 
Les audiences peuvent être crées facilement dans MOSS via la centrale d'administration en utilisant des règles multi-critères sur les profils utilisateurs.
 
On ne dispose pas d'autant de flexibilité pour la constitution de groupes SharePoint.
 
L'idée de cet outil est donc de proposer de créer et maintenir des groups SharePoint à partir d'audiences. Pour ce faire, vous disposez d'un webpart
 
webpart
 
Ce webpart vous permet
  • de créer un groupe à partir d'audience sans maintenance de synchronisation.
  • de créer un groupe & un timer job chargé de maintenir le groupe synchronisé avec l'audience. Vous pouvez planifier l'exécution du job pour qu'il s'exécute tous les jours ou une fois par semaine. (L'idéal étant de le faire s'exécuter après la compilation des audiences)
  • un SPGridView avec un menu vous donne la possibilité d'exécuter un job manuellement

Ce webpart ne peut être utilisé que dans des TOP Level sites et est clairement destiné à être utilisé par des admins de collection

Il apparaîtra dans la gallerie de webparts. Si vous souhaitez qu'il n'apparaisse pas dans les sous sites, vous pouvez lui attribuer des permissions uniques dans la gallerie de webparts.
 
Vous pouvez télécharger l'outil et le code source ici
 
 
Notez que j'ai créé cet outil pour mes propres besoins et qu'il n'a jamais été testé en environnement réel
Posted by Stéphane Eyskens at 6/17/2008 6:49:50 PM | Comments(0)
 Creating an Infopath Form from scratch programmatically
Hello
 
One of my colleagues (Geoffrey) recently had to generate an InfoPath Form from code and looking on the web, he found out this short article here describing a method that helps achieving the requirement
 
 
I had never faced this needs before so I also started looking on my side for a method. It's quite similar to what is done in the article but I think my method is probably easier and better for the following reasons
 
  • easy maintenance
  • object reusability
  • automatic xml serialization, so don't need to care about characters such as "&" :)
  • easier to manipulate repetitive data sources such as repeating table frequently used in InfoPath forms
My thought has been lead by the fact that Infopath Form = XML and XML = XSD .
 
Starting from this receipe, I planned on using XSD to create a csharp class and add it to my project.
 
 
So, here is step by step how to create an Infopath Form document into a form library based on a specific form template
 
1. Create your form in Infopath
 
The goal is to achive that kind of form
 
design your form
 
This has the following datasource
 
Datasource
 
This datasource contains a repetitive group. That kind of thing is hard to maintain when using the method described by the article.
 
2. Publish the form to SharePoint
 
Publish it to a new form library.
 
3. Export the source files of your form and run XSD
 
So, my preferred way is to use XSD. This tool has been built to create dotnet classe(s) from XML data. To create such a class, just do the following
 
  • Open your form in Design Mode
  • Choose, File => Save as source files => give a folder name
  • Close InfoPath (because it keeps a lock on the files)
  • Open the visual studio command prompt, go to the folder location where you saved the source files
  • run this command xsd /c myschema.xsd

This should have created the file myschema.cs

 
4. Create a console program and add the generated .cs to your project
 
Open Visual Studio and create a console application, add the file "myschema.cs" to your project.
 
5. Code it! 
 
5.1 add the required DLL Microsoft.SharePoint
 
5.2 declare the following namespaces
 
using System.Xml;
using System.Xml.Serialization;
using Microsoft.SharePoint;
using System.IO;
 
5.3 create an instance of your form data, serialize it and add the serialized data as a SharePoint document
 
using (SPSite Site = new SPSite("your site"))
{
    using (SPWeb Web = Site.OpenWeb())
    {
        try
        {
            SPDocumentLibrary FormLibrary = Web.Lists["Sample Forms"] as SPDocumentLibrary;
            string DocumentTemplateUrl = Web.Url + "/" + FormLibrary.DocumentTemplateUrl;
            string FileName = "SampleForm.xml";
            myFields FormData = new myFields();
            FormData.SampleHeaderData = "Header value";
            List<SampleLines> Lines = new List<SampleLines>();
            SampleLines Aline = null;
            for (int i = 0; i < 5; i++)
            {
                Aline = new SampleLines();
                Aline.SampleLine = string.Format("sample line {0}",
                    i.ToString());
                Lines.Add(Aline);
            }
            FormData.SampleLines = Lines.ToArray();
            MemoryStream MemStr = new MemoryStream();
            XmlTextWriter Writer = new XmlTextWriter(MemStr, Encoding.UTF8);
            //required otherwise the document will be considered as a simple xml doc
            Writer.WriteProcessingInstruction("xml", "version=\"1.0\" encoding=\"UTF-8\"");                      
            Writer.WriteProcessingInstruction("mso-infoPathSolution",
                string.Format("solutionVersion=\"1.0.0.5\" productVersion=\"12.0.0\" PIVersion=\"1.0.0.0\" href=\"{0}\" name=\"urn:schemas-microsoft-com:office:infopattestfrm:-myXSD-2008-06-11T14-36-25\"",
                DocumentTemplateUrl));
            Writer.WriteProcessingInstruction("mso-application", "progid=\"InfoPath.Document\" versionProgid=\"InfoPath.Document.2\"");
            XmlSerializer Serializer = new XmlSerializer(typeof(myFields));
            Serializer.Serialize(Writer, FormData);
            SPFileCollection Files = FormLibrary.RootFolder.Files;
            SPFile NewFile = Files.Add(
                string.Format("{0}/{1}", FormLibrary.RootFolder.Url, FileName),
                MemStr, true);
            SPListItem NewItem = NewFile.Item;
            NewItem["Title"] = "A title";
            NewItem.Update();
        }
        catch (Exception Ex)
        {
            Console.WriteLine(Ex.Message);
        }
    }
}
 
You're done! Here is the results of your efforts
 
form library
 
The Form
 
6. Advantages
 
  • What if you change your form's datasource? In that case, if you want to include one or more fields, you'll have to rerun xsd (or add it manually to your class) and use it in your code

    FormData.YourNewField = The value;
  • You can also easily pass the instance (FormData) to any other class if you need to use it elsewhere
  • As you've seen, XSD generates partial classe(s), it makes it very easy to handle repeating table data.
 
Subsidiary question : will your form be compatible with Forms Services?
 
You don't care of it, this is handled by the form template (.xsn) and does not relate to the data!
 
7. Download it!
 
If you want to download the sample project, just click on this link
 
If you know any other better method, don't hesitate to post a comment
Posted by Stéphane Eyskens at 6/12/2008 9:51:28 PM | Comments(0)
 Système d'évaluation/vote de documents SharePoint
Salut,
 
J'ai mis en ligne un système d'évaluation de documents SharePoint
 
 
N'hésitez pas à l'utiliser/le redistribuer/le personnaliser à votre guise.
 
J'ai également écrit un tutoriel sur le fonctionnement de ce système http://stephaneey.developpez.com/tutoriel/sharepoint/docrating
 
 
MISE A JOUR
 
J'ai modifié le système, il inclut désormais les fonctionnalités suivantes:
 
- Les utilisateurs authentifiés peuvent évaluer ET commenter les documents
- Le rapport des évaluations pour un document est maintenant accessible à tous
- Le rapport des évaluations pour une bibliothèque entière reste uniquement accessible à un gestionnaire de bibliothèque
- Le système est à présent compatible avec l'approbation
- Les étoiles sont plus jolies :)
 
Posted by Stéphane Eyskens at 6/6/2008 10:47:09 PM | Comments(0)

>>

 ‭(Hidden)‬ Content Editor Web Part ‭[1]‬