jeudi 24 janvier 2013

Sort DataTable DataView ascending with null or empty last.


You first need to specify the sorting column in 'param' and replace the original DataTable by 'collection'.

In this example I filter a DataTable with the SelectedValue given by my DropDownList control (ddlFiltre).

In the DataRow array 'nameNotNull' I simply simply the data that are not null for my parameter and sort them.
And in the DataRow array 'nameNull' I select the null data for my parameter.

You just need to merge the two DataRow array and bind it with the GridView

DataTable collection;
//Fill the dataTable
//...
///

protected void ddlFiltre_Change(object sender, EventArgs e){ 
  if (!string.IsNullOrEmpty(ddlFiltre.SelectedValue)) {   
       string param = "Name";
       DataRow[] nameNotNull = collection.Select(string.Format("{0} IS NOT NULL AND {0} <> ''", param),string.Format("{0} ASC", param));
       DataRow[] nameNull = collection.Select(string.Format("{0} IS NULL OR {0} = ''", param));
        DataTable collectionSorted = collection.Clone();
   if (nameNotNull.Length > 0)
   {
      foreach (DataRow dr in nameNotNull)
      {
         DataRow newRow = collectionSorted.NewRow();
         newRow.ItemArray = dr.ItemArray;
         collectionSorted.Rows.Add(newRow);
      }
      if (nameNull.Length > 0)
      {
         foreach (DataRow dr in nameNull)
         {
            DataRow newRow = collectionSorted.NewRow();
            newRow.ItemArray = dr.ItemArray;
            collectionSorted.Rows.Add(newRow);
         }
       }
    }
    else if (nameNull.Length > 0)
    {
       foreach (DataRow dr in nameNull)
       {
          DataRow newRow = collectionSorted.NewRow();
          newRow.ItemArray = dr.ItemArray;
          collectionSorted.Rows.Add(newRow);
       }
    }
    gvItems.DataSource = collectionSorted;
    gvItems.DataBind();
}
}

jeudi 10 janvier 2013

Modifier les pages SharePoint par défaut. (AccessDenied.aspx, Confirmation.aspx, Error.aspx, Login.aspx, RequestAccess.aspx, Signout.aspx, WebDeleted.aspx)

Il est possible d'avoir de modifier l'url des pages suivantes et de les surcharger pour intégrer le design de l'entreprise :
  •  AccessDenied (Specifies AccessDenied.aspx)
  •  Confirmation (Specifies Confirmation.aspx)
  •  Error (Specifies Error.aspx)
  •  Login (Specifies Login.aspx)
  •  RequestAccess (Specifies ReqAcc.aspx)
  •  Signout (Specifies SignOut.aspx)
  •  WebDeleted (Specifies WebDeleted.aspx)
Avec les classes correspondantes se trouvant dans le namespace : 


Microsoft.SharePoint.ApplicationPages



Il est aussi nécéssaire de modifier la masterpage de votre page d'application par :

MasterPageFile="~/_layouts/simple.master"

Et d'hériter la classe correspondante 

UnsecuredLayoutsPageBase pour AccessDenied.aspx par exemple.




La modification de ces pages peut ensuite se faire de deux manières, soit par code C# :

SPWebApplication.UpdateMappedPage(SPWebApplication.SPCustomPage.AccessDenied, 

"_layouts/MyAccessDenied.aspx);


Soit via powershell : 


Set-SPCustomLayoutsPage -Identity "AccessDenied" -RelativePath 

"/_layouts/MyAccessDenied.aspx" -WebApplication http://serveur 

Get-SPCustomLayoutsPage –Identity "AccessDenied" -WebApplication http://serveur 

iisreset


Voici une page complète d'une customisation simple de la page AccessDenied.aspx avec changement du lien 'Retour au site' par défaut : 



<%@ Assembly Name="Name, Version=1.0.0.0, Culture=neutral,PublicKeyToken=092c1c010b5e2820" %>
<%@ Import Namespace="Microsoft.SharePoint.ApplicationPages" %>
<%@ Register Tagprefix="SharePoint" Namespace="Microsoft.SharePoint.WebControls" Assembly="Microsoft.SharePoint, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>
<%@ Register Tagprefix="Utilities" Namespace="Microsoft.SharePoint.Utilities" Assembly="Microsoft.SharePoint, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>
<%@ Register Tagprefix="asp" Namespace="System.Web.UI" Assembly="System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" %>
<%@ Import Namespace="Microsoft.SharePoint" %>
<%@ Assembly Name="Microsoft.Web.CommandUI, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>
<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="AccessDenied.aspx.cs" Inherits="AccessDenied" MasterPageFile="~/_layouts/simple.master" %>

<%@ Import Namespace="System.Data" %>
<%@ Import Namespace="System.Data.SqlClient" %>
<%@ Import Namespace="System.IO" %>
<%@ Import Namespace="Microsoft.SharePoint" %>
<%@ Import Namespace="Microsoft.SharePoint.Publishing" %>
<%@ Import Namespace="System.Web" %>
<%@ Import Namespace="Microsoft.SharePoint.WebControls" %>

<script runat="server">
    protected void Page_Load(object sender, EventArgs e)
    {
        if (SPContext.Current != null && SPContext.Current.Web != null && SPContext.Current.Web.CurrentUser != null)
        {
            LabelUserName.Text = SPContext.Current.Web.CurrentUser.LoginName;
        }
     
        if (SPContext.Current != null && SPContext.Current.Web != null && SPContext.Current.Web.Site != null
            && SPContext.Current.Web.Site.WebApplication != null)
        {
         
            Page.ClientScript.RegisterStartupScript(this.GetType(), "click",
        "modifierRetour('" + SPContext.Current.Web.Site.WebApplication.Sites[0].Url + "');", true);
        }


   //     HLinkLoginAsAnother.Attributes.Add("onclick", "LoginAsAnother('\u002fsites\u002factuariat\u002f_layouts\u002fcloseConnection.aspx?loginasanotheruser=true', 1)");
    //    HLinkLoginAsAnother.NavigateUrl = "http://www.google.com/";
    }
    </script>

<asp:Content ID="PageHead" ContentPlaceHolderID="PlaceHolderAdditionalPageHead" runat="server">
    <style type="text/css"></style>
    <script type="text/javascript">
        function modifierRetour() {
            var backbutton = document.getElementById('ctl00_PlaceHolderGoBackLink_idSimpleGoBackToHome');

            if (backbutton != null) {
                backbutton.href = "javascript:history.back()"; // cacherBackToSite.arguments[0];
            }
        }
</script>
</asp:Content>

<asp:Content ID="Main" ContentPlaceHolderID="PlaceHolderMain" runat="server">
 
   <table border="0" cellpadding="0">
         <asp:Panel id="PanelUserName" runat="server">
         <tr>
       <td class="ms-sectionheader">
       <%--<img src="/_layouts/images/ListSet.gif" alt="" />--%>
       <SharePoint:EncodedLiteral ID="EncodedLiteral3" runat="server" text="<%$Resources:wss,accessDenied_currentuser%>" EncodeMethod='HtmlEncode'/>
       </td>
         </tr>
         <tr>
       <td valign="top" class="ms-descriptiontext"><SharePoint:EncodedLiteral ID="EncodedLiteral4" runat="server" text="<%$Resources:wss,accessDenied_loggedInAs%>" EncodeMethod='HtmlEncode'/>
       &#160;<b><asp:Label id="LabelUserName" runat="server"/></b>
       </td>
         </tr>
         </asp:Panel>
    </table>
</asp:Content>

<asp:Content ID="PageTitle" ContentPlaceHolderID="PlaceHolderPageTitle" runat="server">
 <SharePoint:EncodedLiteral ID="EncodedLiteral1" runat="server" text="Accès refusé au site demandé" EncodeMethod='HtmlEncode'/>
</asp:Content>

<asp:Content ID="PageTitleInTitleArea" ContentPlaceHolderID="PlaceHolderPageTitleInTitleArea" runat="server" >
    <SharePoint:EncodedLiteral ID="EncodedLiteral2" runat="server" text="Vous n'avez pas le droit de visualiser ce site." EncodeMethod='HtmlEncode'/>
</asp:Content>


 


















vendredi 14 décembre 2012

How to activate custom action based on SharePoint Right

This javascript function is a helper to enable or disable custom action for SharePoint 2010 based on ContentTypeID, Permissions and number of selected element.

You can call this function in the CommandUIHandler EnabledScript attribute

Create a custom action for Ribbon :

  <CustomAction Id="Ribbon.AlertPerso"
              RegistrationType="ContentType"
                 RegistrationId="0x0101002D02DF72FAFB4EAB9446F92337C759AE01"
              Location="CommandUI.Ribbon" Title="Alert Perso">
    <CommandUIExtension>
      <CommandUIDefinitions>
        <CommandUIDefinition Location="Ribbon.Documents.Manage.Controls._children">
          <Button Id="Ribbon.CreerAlerter.Button"
                  LabelText="Créer une alerte personnalisée"
                  TemplateAlias="o2"
                  Image16by16="/_layouts/images/avertir16.png"
                  Image32by32="/_layouts/images/avertir32.png"
                  Sequence="08"
                  Command="AlerteCommandeDoc" />
        </CommandUIDefinition>
      </CommandUIDefinitions>
      <CommandUIHandlers>
        <CommandUIHandler Command="AlerteCommandeDoc"
                          CommandAction="javascript:window.location='votre page cible."
<!-- Replace the first attribute by you content type id, the second one with the SPPermission needed, and the thrid with the number of element that have to be selected (list of sharepoint permission kind : http://msdn.microsoft.com/en-us/library/ee556747(v=office.14).aspx) -->            EnabledScript="javascript:ActiveTypeContenuDroit('0x0101002D02DF72FAFB4EAB9446F92337C759AE01',SP.PermissionKind.,1);"/>
      </CommandUIHandlers>
    </CommandUIExtension>
  </CustomAction>
</Elements>




Ajout de la fonction dans core.js :

//Id of SP.ListItem
var ItemSelectedID;
//Content Type ID
var ItemSelectedContentType;
//SP.ListItem
var ItemSelectedItem;
//Right on the item.
var ItemSelectedRight;

//Check if the custom action is enabled

//ContenuID : Content Type Id that the item must match.
//Permission : Permissions needed, if null the custom action will be enabled.
function ActiveTypeContenuDroit(ContenuID, Permission, TypeAction) {
    var result = false;
    var selectedItems = SP.ListOperation.Selection.getSelectedItems();
    var countItems = CountDictionary(selectedItems);

    //when the action is available for all items.
    if (TypeAction == 0 && countItems == TypeAction) {
        result = true;
    } else {
        //when the action is available when only one item is selected.
        if (countItems == TypeAction && TypeAction == 1) {
            //when the objet is not defined
            if (this.ItemSelectedID == null) {
                var listGuid = SP.ListOperation.Selection.getSelectedList();
                ItemSelectedID = selectedItems[0]['id'];
                ListItemContentTypePermission(this.ItemSelectedID, listGuid);
            }
            //when the charged item is not previous item that was charged
            else if (this.ItemSelectedID != selectedItems[0]['id']) {
                this.ItemSelectedID = selectedItems[0]['id'];
                var listGuid = SP.ListOperation.Selection.getSelectedList();
                ListItemContentTypePermission(this.ItemSelectedID, listGuid);
            }
            //compare with the content type id parameter
            else if (this.ItemSelectedContentType != null) {
                if (ItemSelectedContentType.toString().indexOf(ContenuID.toString()) != -1) {
                    //Check rigth on the object.
                    if (Permission != null && ItemSelectedRight != null) {
                        if (ItemSelectedRight == null) {
                            alert("ItemSelectedRight null");
                        }
                        else {
                            //Check rigth on the object.
                            var permettre = ItemSelectedRight.has(Permission);
                            if (permettre) {
                                { result = true; }
                            }
                        }
                    }
                    else {
                        result = true;
                    }
                }
            }
        }
        else {
            //when more than one selected value is possible
            if (TypeAction > 1) {
                    // .. action when two item selected.
                alert("not defined ActiveTypeContenuDroit " + TypeAction);
                result = false;
            }
        }
    }
    return result;
}

//Initialize SP.ListItem and get the property  Title  ContentTypeId EffectiveBasePermissions
function ListItemContentTypePermission(ItemId, listGuid) {
    var clientContext = new SP.ClientContext();
    var web = clientContext.get_web();
    var lists = web.get_lists();
    var list = lists.getById(listGuid);
    ItemSelectedItem = list.getItemById(ItemId);
    clientContext.load(ItemSelectedItem, 'Title', 'ContentTypeId', 'EffectiveBasePermissions');
    clientContext.executeQueryAsync(onListItemContentTypePermission, failedListItemContentTypePermission);
}

//Get the needed property.
function onListItemContentTypePermission(sender, args) {
    ItemSelectedRight = ItemSelectedItem.get_effectiveBasePermissions();
    ItemSelectedContentType = ItemSelectedItem.get_item('ContentTypeId');
    RefreshCommandUI();
}

function failedListItemContentTypePermission(sender, args) {
    alert('Request failed. \nError: ' + args.get_message() + '\nStackTrace: ' + args.get_stackTrace());
}

SharePoint Client Side Object Model (CSOM)

Un petit coup de chapeau pour ce très bon post qui trait du CSOM dans SharePoint 2010, SharePoint 2007, SharePoint 2013.

Et notamment sur la récupération du SP.ClientContext< ainsi que le fonctionnement des executeQueryAsync

http://blog.aptillon.com/2012/09/25/the-sharepoint-javascript-object-modelresources-and-real-world-examples/

vendredi 23 novembre 2012

Soirée Intel et Microsft autour de Windows 8

Microsoft et Intel organisent une soirée au RedLigth ce jeudi 29 Novembre, cette soirée sera dédié aux ultrabooks ainsi qu'au développement d'application Windows 8 "AppTouch"

Des experts Microsoft et Intel seront là pour assurer le show et des stands de démo seront aussi présents pour essayer les dernières technos.

( cocktail / bière / pizza à volonté ) 

Programme de la soirée :

19h30 : Accueil des participants au Red Light & cocktails

19h45 :  Présentation de la Intel Developer Zone
Découvrez la gestion du tactile sous Windows 8 et les APIs natives/C#/HTML vous permettant d’en tirer partie L'accent sera mis sur le développement d'applications pour Ultrabook. 

20h :Guideline de User Interface sur Ultrabook
Formation technique au touch et aux outils de design d'interface pour Ultrabook. Guidelines sur le UI/UX sur Ultrabook.

20h45: Rencontre avec les Sensors
Découvrez toutes les API de Sensors qui sont mises à dispositon des développeurs.

21h30 : Drinks et Pizzas et Démos
Pendant toutes la soirée, vous pourrez profiter d'un espace démo et de coachs qui seront présents pour vous conseiller et répondre à toutes vos questions. 

Le récap de l'événement est ici : 
http://www.meetup.com/Intel-Technologies-Meetup/events/92504522/


Et l'inscription sur le site de intel :
http://applabintel.eventbrite.com/

mardi 20 novembre 2012

The HTTP service located is too busy / Le service HTTP est trop occupé



Pour provisionner un service trop occupé dans SharePoint 2010, exécuter les commande suivantes :

$sts = Get-SPServiceApplication | ?{$_ -match "nom du service"}  
$sts.Status
$sts.Provision()


Erreur sharepoint lié :
An exception occurred when trying to issue security token: Le service HTTP situé sur ../SecurityTokenServiceApplication/securitytoken.svc/actas est trop occupé.
Exception occured while connecting to WCF endpoint: System.ServiceModel.ServerTooBusyException