Sue Hernandez's Blog

January 4, 2012

SharePoint 2007-2010 Web Part Migration Planning

Filed under: MOSS, SharePoint 2010, Visual Studio 2010 — Susan Hernandez @ 11:26 pm

Well, I know I need to post the rest of my “Gantt Chart” blogs, but let me side track for a minute…

We are migrating one of our clients from MOSS 2007 to SharePoint 2010 and we wanted to know what web parts are being used on what sites.  I found a multi-step process you’ll have to go through, and it will take a while, but you CAN get a 70%-90% list.

GET THE WEB PARTS PER WEB

The first step is to use the stsadm command “enumallwebs”.  This apparently has a parameter/switch called “includewebparts” which apparently was added during an Octbver 09 Cumulative Update.

stsadm -o enumallwebs -includewebparts > MyOutputFileName.txt

This will construct for you an XML file that looks approximately like below:

<Databases>
  <Database SiteCount="2" Name="your_sharepoint_content_database_name" DataSource="server">
    <Site Id="12345678-716d-44a3-a973-fffffffffff" OwnerLogin="domain\spadmin" InSiteMap="True">
      <Webs Count="2">
        <Web Id="12345678-17d9-4870-8d94-fffffffffff" Url="/sites/test1" LanguageId="1031"
             TemplateName="STS#0" TemplateId="1">
          <WebParts>
            <WebPart Id="e60f6c95-e86c-4717-2c0d-6d8563c9caf7" Count="1" Status="Missing" />
            <WebPart Id="293e8d0e-486f-e21e-40e3-75bfb77202de" Count="103" Status="Missing" />
            <WebPart Id="b9a7f972-708a-cd77-4ffd-a235dfed5c38" Count="1" Status="Missing" />
            <WebPart Id="2242cce6-491a-657a-c8ee-b10a2a993eda" Count="182" Status="Missing" />
          </WebParts>
        </Web>
        <Web Id="12345678-3bda-4109-aacd-fffffffffff" Url="/sites/test1/subweb1" LanguageId="1031"
             TemplateName="STS#1" TemplateId="1">
          <WebParts>
            <WebPart Id="ce9aa113-48cf-ddee-0c03-597445e5b7ab" Count="1" Status="Missing" />
            <WebPart Id="293e8d0e-486f-e21e-40e3-75bfb77202de" Count="9" Status="Missing" />
            <WebPart Id="2242cce6-491a-657a-c8ee-b10a2a993eda" Count="7" Status="Missing" />
          </WebParts>
        </Web>
      </Webs>
    </Site>
    <Site Id="12345678-730c-46fd-a114-fffffffffff" OwnerLogin="domain\spadmin" InSiteMap="True">
      <Webs Count="1">
        <Web Id="12345678-7cd6-447d-8107-fffffffffff" Url="/sites/test2" LanguageId="1031"
             TemplateName="STS#0" TemplateId="1">
          <WebParts>
            <WebPart Id="d55b3b6b-6281-707b-73d0-0c49581475ad" Count="1" Status="Missing" />
            <WebPart Id="293e8d0e-486f-e21e-40e3-75bfb77202de" Count="83" Status="Missing" />
            <WebPart Id="9f030319-fa14-b625-4892-89f6f9f9d58b" Count="1" Status="Missing" />
            <WebPart Id="c9b34b5d-bf06-dc91-d23e-94ecad31cd0a" Count="2" Status="Missing" />
            <WebPart Id="2242cce6-491a-657a-c8ee-b10a2a993eda" Count="83" Status="Missing" />
            <WebPart Id="669602d9-e116-ccb8-eea3-e37ad589b14b" Count="1" Status="Missing" />
            <WebPart Id="f5897322-ddd4-c990-d012-f9d4fe2180ad" Count="2" Status="Missing" />
          </WebParts>
        </Web>
      </Webs>
    </Site>
  </Database>
</Databases>

* You may have every web part in a “Missing” status – I think you need to run this command on a WFE that has ALL the features installed properly.  Please see one of the following posts for more information:

GET A LIST OF WEB PARTS AND THEIR ASSEMBLIES AND CLASSES

Well see that WebPart “ID” there?  That’s actually not an ID that you can use, even searching in the database, to find the name of the web part.  That is a made up GUID-that’s-not-a-GUID that just happens to “fit” inside a GUID.  More info in the next heading section.

For now, just go to your “Add a Web Part” page, or

https://yourserver.someurl.com/_layouts/newdwp.aspx

From here, you’re going to get a list which shows you 2 pieces of information you need: the full Class Name and the full Assembly Name. 

If you have Excel installed, you “should” be able to right-click inside the list and say “Export to Microsoft Excel”.  From Excel, go ahead and delete columns A and C (Blank and “File Name”).  Now we need to turn this file into an XML file so we can both crunch it through a program, as well as transform it using XSLT.  I personally had a hard time turning it into XML so what I did was I took this schema and saved it as .xml and opened it in Excel:

<WebPartTypeIDs>
   <WebPartTypeID>
      <AssemblyName>Assembly A</AssemblyName>
      <TypeName>Class A</TypeName>
      <GeneratedWebPartTypeID>GUID A</GeneratedWebPartTypeID>
   </WebPartTypeID>
   <WebPartTypeID>
      <AssemblyName>Assembly B</AssemblyName>
      <TypeName>Class B</TypeName>
      <GeneratedWebPartTypeID>GUID B</GeneratedWebPartTypeID>
   </WebPartTypeID>
</WebPartTypeIDs>

Then I copied and pasted everything from the Exported spreadsheet into this XML file.  I think you have to make sure that you have something in the GeneratedWebPartTypeID for at least one of the rows, in order to make sure it doesn’t get rid of that column when you save.

If you’re better at Excel (most will be) and you know an easier way, please let me know.

RUN THE OUTPUT THROUGH A PROGRAM

Next we have to get the generated ID.  Here’s the crazy part.  Here’s what Microsoft does:

  • Take the Assembly Name plus “|” plus the Class / Type Name and put it together in one string
  • Change the string to a Byte array
  • Run the Byte array through an MD5 Hash

So I wrote a little program to ingest in the xml file that we created through Excel.

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Windows.Forms;
using System.Security.Cryptography;
using System.Xml;
using System.Xml.Xsl;
using System.IO;

namespace GetWebPartTypeIDs
{
 public partial class Form1 : Form
 {
  public Form1()
  {
   InitializeComponent();
  }

  private void button1_Click(object sender, EventArgs e)
  {
   try
   {
    Cursor = Cursors.WaitCursor;
    XmlDocument xDoc = new XmlDocument();
    xDoc.Load(textBox1.Text);

    XmlNodeList nodes = xDoc.SelectNodes("//WebPartTypeID");
    foreach (XmlNode node in nodes)
    {
     string assemblyName = node.SelectSingleNode("AssemblyName").InnerText;
     string typeName = node.SelectSingleNode("TypeName").InnerText;

     string s = GenerateID(assemblyName, typeName);

     XmlNode idNode = node.SelectSingleNode("GeneratedWebPartTypeID");
     idNode.InnerText = s;
    }

    xDoc.Save(textBox1.Text);
   }
   catch (Exception ex)
   {
    richTextBox1.Text = ex.ToString();
   }
   finally
   {
    Cursor = Cursors.Default;
    richTextBox1.AppendText(Environment.NewLine + Environment.NewLine + "*************** DONE **************");
   }
  }

  private string GenerateID(string assemblyName, string typeName)
  {
   string s = assemblyName + "|" + typeName;
   byte[] bytes = Encoding.Unicode.GetBytes(s);
   byte[] b = new MD5CryptoServiceProvider().ComputeHash(bytes);
   return new Guid(b).ToString();
  }
 }
}

ADD THAT GENERATED XML OUTPUT TOGETHER WITH THE STSADM OUTPUT

So now, put the 2 XML’s together, with some made-up root, doesn’t matter what it is.

<DatabasesAndWebPartTypeIDs>
   <WebPartTypeIDs>
      ...
   </WebPartTypeIDs>
   <Databases>
      ...
   </Databases>
</DatabasesAndWebPartTypeIDs>

RUN IT THROUGH XSLT

I am going to include 2 XSLT’s here.  The first one uses XSLT 2.0 so you might need to download the Saxon Parser (http://saxon.sourceforge.net/) if you don’t have XML Spy or if your file is too big for XML Spy to handle, which is what happened to me (250 MB xml file).

Here’s one that outputs an HTML file.  The nice thing about it is it goes “both ways” – it shows on the top which web parts are not being used and it shows on the bottom which web parts you couldn’t ID.

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:fn="http://www.w3.org/2005/xpath-functions">
 <xsl:output method="html" version="1.0" encoding="UTF-8" indent="yes"/>
 <xsl:template match="/">
   <html>
    <body>
     <h1>By Web Part Name - Unused are highlighted in Red</h1>
     <xsl:for-each select="//WebPartTypeID">
      <xsl:sort select="AssemblyName" />
      <xsl:sort select="TypeName" />
      <xsl:variable name="generatedId" select="GeneratedWebPartTypeID" />
      <xsl:variable name="count" select="count(//Databases//Web[WebParts/WebPart/@Id = $generatedId])" />
      <font face="Courier New" style="font-size:12px">
       <xsl:if test="number($count) = 0">
        <xsl:attribute name="color" select="'Red'" />
       </xsl:if>
       <xsl:value-of select="substring-before(AssemblyName, ',')" /> | <xsl:value-of select="TypeName" />:
<xsl:value-of select="$count" />
      </font><br/>
     </xsl:for-each>
     <hr/>
     <h1>By Web Part Type Id - Those with under 15 entries show the webs they're in</h1>
     <xsl:for-each-group select="//WebPart" group-by="@Id">
      <xsl:sort select="current-grouping-key()" />
      <xsl:variable name="count" select="count(//Web[WebParts/WebPart/@Id = current-grouping-key()])" />
      <font face="Courier New" style="font-size:12px">
       <xsl:value-of select="current-grouping-key()" />: <xsl:value-of select="$count" /> --&gt;
<font color="Red"><b><xsl:value-of
select="substring-before(//WebPartTypeID/AssemblyName[../GeneratedWebPartTypeID = current-grouping-key()], ',')"
 /></b> | <xsl:value-of
select="//WebPartTypeID/TypeName[../GeneratedWebPartTypeID = current-grouping-key()]" /></font>
      </font>
      <br/>
      <xsl:if test="number($count) &lt; 15">
       <xsl:for-each select="//Web/@Url[../WebParts/WebPart/@Id = current-grouping-key()]">
        <font face="Courier New" style="font-size:12px">..........<xsl:value-of select="." /></font><br/>
       </xsl:for-each>
      </xsl:if>
     </xsl:for-each-group>
    </body>
   </html>
 </xsl:template>
</xsl:stylesheet> 

The next XSLT is 1.0 compliant.  This one makes a “flat” xml file that you can then pull into Microsoft Access and do Pivot stuff on it to find out what web templates are being used, etc.

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
 <xsl:template match="/">
  <ReportRoot>
   <xsl:for-each select="//Database">
    <xsl:variable name="db" select="@Name" />
    <xsl:for-each select="Site">
     <xsl:variable name="site" select="@Id" />
     <xsl:for-each select="Webs/Web">
      <xsl:variable name="webID" select="@Id" />
      <xsl:variable name="webURL" select="@Url" />
      <xsl:variable name="webTemplate" select="@TemplateName" />
      <xsl:variable name="webTemplateID" select="@TemplateId" />
      <xsl:for-each select="WebParts/WebPart">
       <xsl:variable name="webPartTypeID" select="@Id" />
       <xsl:variable name="nameNode" select="//WebPartTypeID[GeneratedWebPartTypeID = $webPartTypeID]" />
       <xsl:variable name="assembly" select="$nameNode/AssemblyName" />
       <xsl:variable name="class" select="$nameNode/TypeName" />
       <xsl:element name="WebPartType">
        <xsl:element name="WebPartTypeID">
         <xsl:value-of select="$webPartTypeID" />
        </xsl:element>
        <xsl:element name="AssemblyName">
         <xsl:value-of select="substring-before($assembly, ',')" />
        </xsl:element>
        <xsl:element name="FullAssemblyName">
         <xsl:value-of select="$assembly" />
        </xsl:element>       
        <xsl:element name="ClassName">
         <xsl:value-of select="$class" />
        </xsl:element>
        <xsl:element name="Database">
         <xsl:value-of select="$db" />
        </xsl:element>
        <xsl:element name="SiteCollection">
         <xsl:value-of select="$site" />
        </xsl:element>
        <xsl:element name="WebID">
         <xsl:value-of select="$webID" />
        </xsl:element>
        <xsl:element name="WebURL">
         <xsl:value-of select="$webURL" />
        </xsl:element>
        <xsl:element name="WebTemplateName">
         <xsl:value-of select="$webTemplate" />
        </xsl:element>
        <xsl:element name="WebTemplateID">
         <xsl:value-of select="$webTemplateID" />
        </xsl:element>
        <xsl:element name="WebCount">
         <xsl:value-of select="@Count" />
        </xsl:element>
       </xsl:element>
      </xsl:for-each>
     </xsl:for-each>
    </xsl:for-each>
   </xsl:for-each>
  </ReportRoot>
 </xsl:template> 
</xsl:stylesheet>

~Sue

December 13, 2011

Publish Error in InfoPath 2010 after pressing Cancel

Filed under: InfoPath, SharePoint 2010 — Susan Hernandez @ 5:45 pm

So I went to publish my InfoPath 2010 Form into SharePoint 2010.  I was impatient because it was taking a long time and I needed to change just one more thing.  So I pressed Cancel.

Now I’m getting one of 2 error messages when trying to either Quick Publish or Regular Publish:

“InfoPath cannot save the following form: https://servername/web/subweb/infoPathLib The following file(s) have been blocked by the administrator …”

“InfoPath cannot save the following form:  https://servername/web/subweb/infoPathLib This document library was either renamed or deleted, or network problems are preventing the file from being saved.  If this problem persists, contact your network administrator.”

Well, after trying numerous times to publish and I even changed the InfoPath Form Properties, still no luck.  Sounds pretty dumb, but all I did was to completely close out all instances of InfoPath and my browser (maybe not necessary) and then re-open InfoPath and do a Manual Publish (not a Quick Publish).  I didn’t change any url’s or put in IP addresses or anything like that.

Are you having this trouble?  Does it persist after you have completely closed and re-opened?  Leave me a coment – maybe together we’ll put in a bug report to Microsoft.

~ Sue

December 7, 2011

Silverlight Gantt Part 5

Filed under: Client Object Model, SharePoint 2010, Silverlight — Susan Hernandez @ 11:23 pm

I have been writing a series about how to create a simple Gantt chart using the latest version of the Silverlight Toolkit.  My links are in my first post, which you can get to from above.

To continue with the topics…

CHANGING THE SERIES BAR’S TOOL TIP

The only thing we really need to do is to find the following XAML:

<ToolTipService.ToolTip>
    
<ContentControl Content=”{TemplateBinding FormattedDependentValue}” />
</ToolTipService.ToolTip>

and change it to:

<ToolTipService.ToolTip>
    
<ContentControl>
         
<StackPanel Orientation=”Horizontal”>
              
<TextBlock Text=”{Binding StartDateDate, StringFormat=\{0:MM\/dd\/yyyy\}}”></TextBlock>
               
<TextBlock Text=” – “></TextBlock>
              
<TextBlock Text=”{Binding EndDateDate, StringFormat=\{0:MM\/dd\/yyyy\}}”></TextBlock>
         
</StackPanel>
    
</ContentControl>
</ToolTipService.ToolTip>

Now here, we’re using data binding from our custom class “DataItem” which I introduced in the last post.  We’re also telling it to format the resultant value in a particular manner, by using the StringFormat extension.  So as long as you’ve been following along, you should have this part completed.  Again, as I’ve said before, we’ll go over the full code for the preparation and binding in probably the last post in this series.

GETTING THE X AXIS TO DISPLAY DATES INSTEAD OF “Days from Min Date”

As I’ve said before, this implementation seems, on the surface, to be a bit messy.  What we’re doing again, is we’re saying, go get me the earliest date (let’s call it 8/1/2011 for sake of argument).  That Date now is going to be represented as the decimal “0″ on the X Axis.  Whereas the date 8/25/2011 would be represented as the number “24″ on the X Axis – the number of days FROM the minimum date.

Now again, this seems messy but I did try to use the DateTimeAxis object that is provided in the Toolkit.  I couldn’t get it to work using DateTimes.  I posted a forum post and was answered that only Doubles will work as the Dependent Value, not DateTimes.  So I offer that my solution while not pretty, is probably the practical way to do it.

Ok so the first thing to do is to create another Template for the X Axis.  But we also have to make sure we have an XMLNS in our Main Page:

xmlns:layout=”clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Layout.Toolkit”

So after we put the XMLNS in the  User Control, we add this new style to the UserControl.Resources section: 

<!– X Axis –>
<Style x:Key=”HorizontalAxisStyle” TargetType=”chartingToolkit:AxisLabel”>
     <Setter Property=”Margin” Value=”0,5,0,0″/>
     <Setter Property=”Template”>
          <Setter.Value>
               <ControlTemplate TargetType=”chartingToolkit:AxisLabel”>
                    <layout:LayoutTransformer>
                         <layout:LayoutTransformer.LayoutTransform>
                              <RotateTransform Angle=”-60″ />
                         </layout:LayoutTransformer.LayoutTransform>
                         <TextBlock 
                              Padding
=”0″ 
                              DataContext
=”{Binding}”
                             
Text=”{Binding Converter={StaticResource AxisDateFormatConverter}, ConverterParameter={StaticResource axisMinDate}}” />
                    </layout:LayoutTransformer>
               </ControlTemplate>
          </Setter.Value>
     </Setter>
</Style>

and of course set this new style in the chart markup

<chartingToolkit:BarSeries.DependentRangeAxis>
     <chartingToolkit:LinearAxis
          Orientation=”X”
         
AxisLabelStyle=”{StaticResource HorizontalAxisStyle}” />
    
</chartingToolkit:BarSeries.DependentRangeAxis>
<chartingToolkit:BarSeries.IndependentAxis>

The Control Template is doing 2 things here:  (1) It is rotating the labels of the X axis by a – 60 degrees; (2) it is printing the text, data bound to the X Axis Label, and using a Converter class with a Static Resource parameter.  Let’s first talk about the AxisDateFormatConverter class.

// Converter for showing the X Axis lables as DateTimes instead of doubles
// Expects the MinDate to be the smallest date of all of the data points
public class AxisDateFormatterIValueConverter
{
     public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
          if (parameter != null)
                {
               DateTime minDate = DateTime.MinValue;
               DateTime.TryParse(parameter.ToString(), out minDate); 

               if (minDate != DateTime.MinValue && minDate != DateTime.MaxValue)
                         {
                    DateTime dt = minDate.AddDays((double)value);
                    return dt.ToShortDateString();
                         }
                }
                return value;
        }

         public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    
{
                if (parameter != null)
          
{
                        DateTime minDate = DateTime.MinValue;
              
DateTime.TryParse(parameter.ToString(), out minDate);
             
DateTime endDate = DateTime.MaxValue;
             
DateTime.TryParse(value.ToString(), out endDate); 

                       if (minDate != DateTime.MinValue && endDate != DateTime.MaxValue)
             
{
                               return (endDate.Subtract(minDate)).TotalDays;
             
}
                }

                return value;
     
}
}

This class expects to receive the MinDate value, which is the Earliest StartDateDate of all of your data points.  It takes the number that was passed in, adds those in Days to the MinDate, and returns a string version of that Date.

One of the problems with this, is how to get the MinDate parameter into the function??  Well, I chose to use a Static Resource, made up of a light-weight custom class that simply holds the value for the Min Date:

// For use with a Static Resource, to pass in as a 
// parameter to the Conversion function for the
// X Axis values
public class AxisMinDate
{
        public DateTime Value { get; set; }

     public AxisMinDate()
    
{
        }

        public override string ToString()
    
{
                return Value.ToShortDateString();
    
}
}

Then in the UserControl.Resources section, I add the reference to this custom class, and add the reference to the AxisDateFormatter class as well:

<!– Axis Value Formatter –>
<me:AxisDateFormatter x:Key=”AxisDateFormatConverter” />
<me:AxisMinDate x:Key=”axisMinDate” />

In the code-behind, when setting up the min and max date, at the same time, you set it into your resource:

// Get the Min Date and Max Date for determining the intervals
DateTime maxDate = DateTime.MinValue;
DateTime minDate = DateTime.MaxValue;

foreach (DataItem p in dataPoints)
{
        if(p.EndDateDate > maxDate)
    
{
                maxDate = p.EndDateDate;
        }

        if(p.StartDateDate < minDate)
    
{
                minDate = p.StartDateDate;
        }
}

if (minDate > DateTime.Today)
{
        minDate = DateTime.Today.Subtract(newTimeSpan(10, 0, 0, 0));
}

// Set this date into a resource for use later in styling the X axis labels:
// Instead of numbers, we use dates, calculated as the MinDate plus the
// double Value of the dataPoint (in days).
((AxisMinDate)this.Resources["axisMinDate"]).Value = minDate;

Next up:  Updating the X Axis Interval such that it only shows about 6-7 points at one time.

 

 

December 4, 2011

MOSS SPSecurity.RunWithElevatedPrivileges Object Reference Not Set

Filed under: MOSS, Visual Studio 2010 — Susan Hernandez @ 6:58 pm

MOSS (SharePoint 2007) SPSecurity.RunWithElevatedPrivileges Object Reference Not Set to an Instance of an Object.

There are a few post out there regarding permissions on the database, and permissions on a local account group; however I just barely found, and wanted to pass on -

If you’re using Visual Studio and you’re running in Debug mode, and you’re either getting the Object Reference on SPSecurity.RunWithElevatedPrivileges or you’re getting a File Not Found error (“Web application at … could not be found”) on new SPSite(webURL), then you might want to check your configuration options.  Are you running in x86 mode and your site is build on 64 bit? 

What I did was I changed my build configuration from x86 to “Any CPU” and that made both exceptions go away.

~Sue

December 2, 2011

Silverlight Gantt Part 4

Filed under: Client Object Model, SharePoint 2010, Silverlight — Susan Hernandez @ 11:50 pm

In my first post, I started with a teaser of what we’re trying to accomplish; in the second post, I talked about removing the Legend; and in the last post, I talked about putting a “Today” line on the chart.  In that last post, we covered some of the code necessary to data bind the chart, but really didn’t go into deep detail.

ADDING A TEXT LABEL INSIDE OR OUTSIDE OF THE BAR 

So if you look at the picture in the first post, you will notice that there is a Label at the end of the bar that shows the End Date.  That label is by default inside the bar, and has White text.  However, when the bar’s too small, it is displayed outside of the bar, using Black text.

We have to override the Style for the default BarDataPoint style.  Basically you’re telling it how to lay out the bars.  Now I’m going to post the entire style you need to put in your UserControl.Resources section.  Much of it is for stuff I don’t use, like highlighting and selecting; however I’m keeping it in there “just in case”.

So again, put this into your UserControl.Resources section:

<!– BarDataPoint Style and Template –>
<Style x:Key=”BarTemplateStyle1″ TargetType=”chartingToolkit:BarDataPoint”>
    
<Setter Property=”Template”>
         
<Setter.Value>
              
<ControlTemplate x:Name=”BarTemplate” TargetType=”chartingToolkit:BarDataPoint”>
                    
<Grid x:Name=”BarTemplateMainGrid”>
                        
<VisualStateManager.VisualStateGroups>
                             
<VisualStateGroup x:Name=”CommonStates”>
                                  
<VisualStateGroup.Transitions>
                                       
<VisualTransition GeneratedDuration=”0:0:0.1″/>
                                  
</VisualStateGroup.Transitions>
                                  
<VisualState x:Name=”Normal”/>
                                  
<VisualState x:Name=”MouseOver”>
                                       
<Storyboard>
                                            
<DoubleAnimation
                                                  Duration
=”0″ 
                                                  Storyboard.TargetName
=”MouseOverHighlight”
                                                  Storyboard.TargetProperty
=”Opacity”
                                                  To
=”0.6″/>
                                       
</Storyboard>
                                  
</VisualState>
                             
</VisualStateGroup>
                             
<VisualStateGroup x:Name=”SelectionStates”>
                                   <VisualStateGroup.Transitions>
                                       
<VisualTransition GeneratedDuration=”0:0:0.1″/>
                                   </VisualStateGroup.Transitions>
                                  
<VisualState x:Name=”Unselected”/>
                                  
<VisualState x:Name=”Selected”>
                                       
<Storyboard>
                                             <DoubleAnimation
                                                  Duration
=”0″
                                                  Storyboard.TargetName
=”SelectionHighlight”
                                                  Storyboard.TargetProperty
=”Opacity”
                                                  To
 =”0.6″/>
                                       
</Storyboard>
                                  
</VisualState>
                             
</VisualStateGroup>
                              
<VisualStateGroup x:Name=”RevealStates”>
                                  
<VisualStateGroup.Transitions>
                                       
<VisualTransition GeneratedDuration=”0:0:0.5″/>
                                  
</VisualStateGroup.Transitions>
                                  
<VisualState x:Name=”Shown”>
                                       
<Storyboard/>
                                  
</VisualState>
                                  
<VisualState x:Name=”Hidden”>
                                       
<Storyboard/>
                                  
</VisualState>
                             
</VisualStateGroup>
                        
</VisualStateManager.VisualStateGroups>
                        
<ToolTipService.ToolTip>
                              <!– ######### THIS WILL BE CHANGED LATER –>
                              
<ContentControl Content=”{TemplateBinding FormattedDependentValue}”/>
                         </ToolTipService.ToolTip>
                        
<Rectangle x:Name=”SelectionHighlight”
                              Opacity
=”0″ 
                              Fill
=”Red” 
                              Grid.RowSpan
=”2″
                              Grid.ColumnSpan
=”3″
                              Margin
=”1.332,0,-1.332,0″/>
                        
<Rectangle x:Name=”MouseOverHighlight”
                              Opacity
=”0″
                              Fill
=”White”
                              Grid.RowSpan
=”2″ 
                              Grid.ColumnSpan
=”3″/>
                        
<Grid x:Name=”GanttDataPointBody”>
                             
<Rectangle Fill=”#FF284B70″/>
                             
<Path Stretch=”Fill” 
                                   Data
=”F1 M16.9979,-38.6618 L304.96201,-38.6618 L295.85101,-12.98486 C293.37601,-10.55966 290.95508,-6.5848103 288.04709,-5.3772006 C285.1391,-4.1696005 266.16092,-4.4174142 262.82092,-4.4273643 L60.699768,-5.1715899 C56.235268,-5.1848698 37.786591,-5.2874784 34.107491,-6.7409983 C30.428286,-8.1945286 28.571583,-13.514527 25.677784,-16.408327 L16.9979,-38.6618 z”
                                   Height
=”10.008″
                                   VerticalAlignment
=”Top”
                                   d
:LayoutOverrides=”Height, GridBox”>
                                  
<Path.Fill>
                                       
<LinearGradientBrush StartPoint=”0.506944,-0.479586″ EndPoint=”0.506944,0.980026″>
                                            
<GradientStop Color=”#00000000″ Offset=”0″/>
                                             
<GradientStop Color=”#FFB9D6F7″ Offset=”0.496″/>
                                            
<GradientStop Color=”#FF284B70″ Offset=”1″/>
                                       
</LinearGradientBrush>
                                  
</Path.Fill>
                              
</Path>
                             
<!– ######### ADDITION HERE –>
                             
<TextBlock
                                  
x:Name=”DataPointLabel”
                                  
Foreground=”{Binding Foreground}”
                                  
Margin=”{Binding TextLabelMargin}”
                                  
VerticalAlignment=”Center”
                                  
TextAlignment=”Right”
                                   
Text=”{Binding FormattedValue}”>
                              </
TextBlock>
                             
<!– ######### END ADDITION –>
                         
</Grid>
                    
</Grid>
               
</ControlTemplate>
          
</Setter.Value>
     
</Setter>
</Style>

And now you need to update your BarSeries element inside your Chart to point to the new style.

<chartingToolkit:BarSeries
    
x:Name=”BarSeries1″
    
DataPointStyle=”{StaticResource BarTemplateStyle1}”>

 You will notice that in the textblock we have some binding going on

 <!– ######### ADDITION HERE –>
<TextBlock
    
x:Name=”DataPointLabel”
    
Foreground=”{Binding Foreground}”
    
Margin=”{Binding TextLabelMargin}”
    
VerticalAlignment=”Center”
    
TextAlignment=”Right”
    
Text=”{Binding FormattedValue}”>
</
TextBlock>
<!– ######### END ADDITION –>

Well what we’ve done here, is that the Bar Series will be Data Bound to a Custom Class that we create to hold the data.  Let’s take a look at that custom class:

public class DataItem
{
         publicstring Key { get; set; }
    
public DateTime MinDate { get; set; }
    
public double StartDate { get; set; }
    
public double EndDate { get; set; }
    
public string TextLabelMargin { get; set; }
    
public string Foreground { get; set; }

     public
DateTime StartDateDate { get; set; }
    
public DateTime EndDateDate { get; set; }

     public string FormattedValue
    
{
                   get
          
{
                          returnstring.Format(“{0:MM/dd/yyyy}”, EndDateDate);
           
}
        }

        public void SetDateDoubles()
    
{
                if (MinDate != DateTime.MinValue)
         
{
                         StartDate = (StartDateDate.Subtract(MinDate)).Days;
                         EndDate = (EndDateDate.Subtract(MinDate)).Days;
                 }
         }

         public DataI tem(string _key, DateTime _start, DateTime _end, string _margin, string _foreground)
    
{
               Key = _key;
               StartDateDate = _start;
               EndDateDate = _end;
               Foreground = _foreground;
        }

        public DataItem()
    
{
         }

We basically populate it with the Start and End dates, and provide it a “Minimum Date” to calculate the number of days it’s been since the first date on the graph we want to use.  So for example if the MinDate was 10/1/2011 and the StartDateDate was 10/11/2011 then the StartDate value would be 10.  That’s how we’re using Doubles to plot the values on the X axis.

When we go through setting up our values into this custom class, we use the default values of “0,0,10,0″ for the Margin, which puts a 10 pixel margin on the right (the text box is right-aligned).  We start with the default Foreground color of “White”.

foreach (ListItem item in spItems)
{
         try
    
{
                 // Populate the DataItem collection (dataPoints)
          
//…

          DataItem point = new DataItem(key, StartDate, EndDate, “0,0,10,0″, “White”);

                dataPoints.Add(point);
        }
        catch (Exception ex1)
    
{
                MessageBox.Show(ex1.ToString());
    
}
}

Then we calculate the Minimum and Maximum dates, so that we can set those values in the data points.  Yea, it’s a twice go-round of the data points, but it was either that or make 2 Server calls.

// Get the Min Date and Max Date for determining the intervals
DateTime maxDate = DateTime.MinValue;
DateTime minDate = DateTime.MaxValue;

foreach (DataItem p in dataPoints)
{
        if(p.EndDateDate > maxDate)
    
{
                maxDate = p.EndDateDate;
        }

        if(p.StartDateDate < minDate)
    
{
               minDate = p.StartDateDate;
        }
}

if (minDate > DateTime.Today)
{
        minDate =DateTime.Today.Subtract(newTimeSpan(10, 0, 0, 0));
}

// Total number of days from start to finish
double max = (maxDate.Subtract(minDate)).Days;

if(max == 0)
{
        mcChart.Title =“Sample Data”;
    
return;
}

foreach (DataItem p in dataPoints)
{
        p.MinDate = minDate;
        p.SetDateDoubles(); 

     // This is an approximation, as the actual X Axis points 
    
// have not yet been set
     
int daysWidth = (p.EndDateDate.Subtract(p.StartDateDate)).Days;

     if(daysWidth < 100)
    
{
                p.TextLabelMargin =“-75,0,-75,0″;
         
p.Foreground =“Black”;
    
}
}

By setting a negative Right margin here, you effectively bring it outside and to the right of the end of the bar.  I noticed I also had to change the left margin too, or the date was getting cut off for some reason.

Next you data bind, but again, we’ll be talking more in depth about that in a later post, probably toward the end of the series.

Next time, Changing the ToolTip for the bar.  See you next time!

November 30, 2011

Silverlight Gantt Part 3

Filed under: Client Object Model, SharePoint 2010, Silverlight — Susan Hernandez @ 11:39 pm

In my first post, I started with a teaser of what we’re trying to accomplish; in the last post, I show you how to remove the Legend from the chart.

PUTTING A “TODAY” LINE ON THE CHART

The way I handled this was to create a custom class which Inherits the Chart class.

We’ll implement the new “Today” line by (1) adding a custom class; (2) adding a red line (2 px wide Rectangle) to the Control Template of the (now custom) chart; (3) Data Binding the Margin on the Rectangle to put it where it belongs; (4) Data Binding the Tool Tip; and (5) adding code to our codebehind that sets that margin by binding the data to the custom chart.

1)  Add a Custom Class

In your project, add another class file and call it something like GanttChart.cs.

using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.DataVisualization.Charting;

namespace SilverlightGantt
{
     public class GanttChartChart
   
{
          public string TodaysDateMargin
      

                get { return (string)GetValue(TodaysDateMarginProperty); }
         
set { SetValue(TodaysDateMarginProperty, value); }
     
}

          public static readonly DependencyProperty TodaysDateMarginProperty = DependencyProperty.Register(“TodaysDateMargin”
          
typeof(string), typeof(GanttChart), null);

      public GanttChart()
     
{
          }
     }
}

(2) Add a red line  

Inside your ChartStyle1 template for the Chart (in the UserControl.Resources section), add XAML so that the ChartAreaBorder looks like this [Get the XAML from the last post and add this to it]:

<Border x:Name=”ChartAreaBorder”
     BorderBrush
=”#FF919191″
     BorderThickness
=”1″
     Canvas.ZIndex
=”10″>
    
<Grid DataContext=”{Binding}”
          Margin
=”{Binding ElementName=testChart, Path=TodaysDateMargin}”
          x
:Name=”todaysDateLine”
          HorizontalAlignment
=”Left”
          Grid.Row
=”1″>
         
<Rectangle Fill=”Red”
               Width
=”2″>
              
<ToolTipService.ToolTip>
                   
<TextBlock x:Name=”todaysDateToolTip” Loaded=”todaysDateToolTip_Loaded” />
               </ToolTipService.ToolTip>
         
</Rectangle>
    
</Grid>
</ Border>

We also have to change the  Target Type at the top of the Style and the top of the Control Template to reflect the custom chart’s new type

<Style x:Key=”ChartStyle1″ TargetType=”me:GanttChart”>
    
<Setter Property=”Template”>
         
<Setter.Value>
              
<ControlTemplate TargetType=”me:GanttChart”>

(3) Data Binding the Margin on the Rectangle

If you copied the XAML code from above, you’ve already set the binding, but let’s talk about what this is.  Notice that I have set a DataContext property as well as the Margin property.

 <Grid DataContext=”{Binding}” Margin=”{Binding ElementName=testChart, Path=TodaysDateMargin}”

 To my understanding, the DataContext gets the current context of the DataBinding that happened on the back end.  The binding in the Margin property is giving it a “Parent” data context to look at.  The ElementName is equal to the name of your Chart, and the Path is the Public Property inside that custom Chart class that is used to bind the value. 

(4) Data Binding the Tool Tip

You will notice that in the XAML I provided I have bound the Tooltip not to data, but rather by giving it an Event Handler.  There was something about the way that Tool Tips work that was not allowing me to do a direct {Binding}

<ToolTipService.ToolTip>
    
<TextBlock x:Name=”todaysDateToolTip” Loaded=”todaysDateToolTip_Loaded” />
</ToolTipService.ToolTip>

So we need to implement this method in the Code Behind for the MainPage.xaml.cs file.

private void todaysDateToolTip_Loaded(object sender, RoutedEventArgs e)
{
     TextBlock tip = sender as TextBlock;
  
if (tip != null)
  
{
           tip.Text = DateTime.Today.ToShortDateString();
   
}
}

(5) Set the margin of the rectangle

We’ll use in this code example the “minDate” variable. 

If you recall in my first post I mentioned how I didn’t necessarily like the implementation of the Linear Axis when really you should be using a Date Time Axis.  Basically what I did was I cycled through all of my data points, and I retrieved the lowest date.  I use that as data point “0″.  All of the other dates are a Days difference from that Minimum date.  For example, one year from that date would be the X axis value “365″ as that’s how many days difference there are from the minimum date.

So first you get your data, then you cycle through it to find the min and max dates.  This gives you what number the X axis “Stops” at, so you can calculate your “Interval” if you don’t want to use the default one that comes with the Chart (too many that they go on 2 lines).  We’ll cover this code a little more in a later post.

((LinearAxis)(((BarSeries)(mcChart.Series[0])).DependentRangeAxis)).Minimum = 0;
((LinearAxis)(((BarSeries)(mcChart.Series[0])).DependentRangeAxis)).Maximum = max + (max * .1);
((LinearAxis)(((BarSeries)(mcChart.Series[0])).DependentRangeAxis)).Interval = interval;

// Points show from bottom to top, so reverse it to show “1″ at the top -
// dataPoints is a List<> of a Custom Class that holds the data you retrieve
dataPoints.Reverse();
((BarSeries)(mcChart.Series[0])).ItemsSource = dataPoints.ToArray();

// First render the chart to get the actual pixel width
testChart.UpdateLayout();

double leftThickness = ((LinearAxis)(((BarSeries)(mcChart.Series[0])).DependentRangeAxis)).
     GetPlotAreaCoordinate((
DateTime.Today.Subtract(minDate)).Days).Value;
testChart.TodaysDateMargin = 
string.Format(“{0},0,0,0″, leftThickness);

What we did here was we used the GetPlotAreaCoordinate from the LinearAxis class, specifying that we’re using the chart’s Dependent Axis – that’s the X axis, the one on the bottom.  Notice though how we first had to call the UpdateLayout() method, as this “renders” the chart and makes it so that the GetPlotAreaCoordinate actually works and doesn’t return 0.

In our next post we will cover adding a Text Label for the end date, and having that label be either inside or outside the box depending on how big the box was.

November 29, 2011

Silverlight Gantt Part 2

Filed under: Client Object Model, SharePoint 2010, Silverlight — Susan Hernandez @ 11:55 pm

In my first post, I prep you with a teaser of what I’m trying to do with a creating a simplified Gantt Chart.  Now let’s start looking at some of the features I specified in my bulleted list in the first post, as to the tasks we have to accomplish.

GETTING RID OF THE LEGEND

Before we begin, what we’ll need to do is to put 2 more xmlns references in our XAML:

xmlns:dataVisualizationToolkit=”clr-namespace:System.Windows.Controls.DataVisualization;assembly=System.Windows.Controls.DataVisualization.Toolkit”

xmlns:toolkitChartingPrimitives=”clr-namespace:System.Windows.Controls.DataVisualization.Charting.Primitives;assembly=System.Windows.Controls.DataVisualization.Toolkit”

Now we can create a custom Style with a Control Template in it – basically the control structure that overrides the way it’s laid out by default.  So above your Grid, you want to add a new section called <UserControl.Resources>.  Inside this section, we’ll paste in some code:

<UserControl.Resources>
    
<!– Chart Template Style and Template –>
    
<Style x:Key=”ChartStyle1″ TargetType=”chartingToolkit:Chart”>
         
<Setter Property=”Template”>
              
<Setter.Value>
                   
<ControlTemplate TargetType=”chartingToolkit:Chart”>
                        
<Border BorderBrush=”{TemplateBinding BorderBrush}”
                             
BorderThickness=”{TemplateBinding BorderThickness}”
                              Background
=”{TemplateBinding Background}”
                              Padding
=”{TemplateBinding Padding}”>
                             
<Grid>
                                  
<Grid.RowDefinitions>
                                       
<RowDefinition Height=”Auto”/>
                                       
<RowDefinition Height=”*”/>
                                  
</Grid.RowDefinitions>
                                   
<dataVisualizationToolkit:Title 
                                        Content
=”{TemplateBinding Title}”
                                        Style
=”{TemplateBinding TitleStyle}”/>
                                   
<Grid Margin=”0,15,0,15″ Grid.Row=”1″>
                                       
<Grid.ColumnDefinitions>
                                            
<ColumnDefinition Width=”*”/>
                                             
<ColumnDefinition Width=”Auto”/>
                                        
</Grid.ColumnDefinitions>
                                       
<dataVisualizationToolkit:Legend x:Name=”Legend”
                                             Grid.Column
=”1″ 
                                             Header
=”{TemplateBinding LegendTitle}” 
                                             Style
=”{TemplateBinding LegendStyle}”/>
                                       
<toolkitChartingPrimitives:EdgePanel x:Name=”ChartArea”>
                                            
<Grid Canvas.ZIndex=”-1″/>
                                             
<Border x:Name=”ChartAreaBorder” 
                                                  BorderBrush
=”#FF919191″ 
                                                  BorderThickness
=”1″
                                                  Canvas.ZIndex
=”10″>

                                                                           </Border>
                                        
</toolkitChartingPrimitives:EdgePanel>
                                   
</Grid>
                              
</Grid>
                         
</Border>
                    
</ControlTemplate>
               
</Setter.Value>
          
</Setter>
    
</Style>
</
UserControl.Resources>

Now down below where we have our Chart, we add a new Property underneath Width called Style:

<chartingToolkit:Chart
    
x:Name=”testChart”
    
BorderBrush=”Transparent”
     Height=”400″
    
Width=”400″
    
Style=”{StaticResource ChartStyle1}”>

To get rid of the Legend, all we have to do is comment it out in the Control Template:  dataVisualizationToolkit:Legend (just put <!– before and –> after that whole line to comment it out). 

Next post we’ll talk about how to add the “Today” red line to the chart template (I gave you a little teaser above – in the XAML notice how I have a space inside one of the borders?)

Simple Silverlight Gantt Chart using Toolkit

Filed under: Client Object Model, SharePoint 2010, Silverlight — Susan Hernandez @ 11:23 pm

I had the need to create a VERY simple Gantt chart – with no moving parts – just to show project start and end date ranges, along with a line for today’s date, and throw in some “health” statistics – like below:

Simple Custom Silverlight Gantt Chart using Toolkit

This turned out to have many working pieces, due to the fact that I had to “Template” out a lot of controls (like the chart itself, the series bars, and the axis).

 
Now I want to point out that my implementation is not perfect – there’s a lot that I want to try to improve upon.  For best example, I use a LinearAxis instead of a DateTimeAxis to display my dates, because I could not get the DateTimeAxis to work even for a simple example.
 
But first, let’s list out the pieces that I had to implement individually, starting from a starting point of using a simple run-of-the-mill BarSeries:
  • Getting rid of the Legend
  • Getting a Today Line added to the chart
  • Getting a ToolTip for the Today Line
  • Adding a Text Label for the end point, and having that label be either inside or outside the box depending on how big it was
  • Changing the bar’s ToolTip (this was easy)
  • Getting the X Axis to display Dates instead of “Days from Min Date”  (Messy, yes)
  • Getting the X Axis to have a dynamic interval such that it only shows about 6 -7 points at a time
  • Getting the X Axis to Rotate
  • Getting “Extra Stuff” inside the Y Axis Label area
  • And last but hardest, setting the “Start Date” so that the bars do not go all the way across starting from 0.

PREREQUISITES

The key to the Charts, and apparently Silverlight in General (this was only my second big Silverlight Project) is having controls where their style overwrites their “Control Template”.  Basically this just means that you start with how it is currently laid out and you change it up by adding, removing, and updating the controls.

So the first thing you want to do is to set up your project.  Although I was going to use this in SharePoint for SharePoint data pulling, I just created a vanilla Silverlight Application and said “Yes” to create the sample Web application that lets you debug.  You need to download the Silverlight Toolkit, which gives you TONS of really cool controls, including some basic-to-intermediate charting (http://silverlight.codeplex.com).  You’ll note that it puts the files (by default) in C:\Program Files (x86)\Microsoft SDKs\Silverlight\v4.0\Toolkit\Apr10, and from there you have the Bin folder where the dll’s are stored, and in the Source folder are ZIP files with the FULL SOURCE CODE!  There’s also a nifty Samples folder that has one page that shows you a bunch of generated charts.  So grab your references from the BIN folder, and make sure you include System.Windows.Controls.Data.Toolkit, System.Windows.Controls.Toolkit, and System.Windows.Controls.DataVisualization.Toolkit.  I just added them all to be lazy, so I don’t know if I missed telling you about one of them, or if one I listed is redundant for this project.

Once you have your project set up, the first thing you should do is to create a very simple out-of-the-box Bar Chart to see what it looks like.  You’ll need to go to your XAML file and add a reference to the Charting components:

xmlns:chartingToolkit=”clr-namespace:System.Windows.Controls.DataVisualization.Charting;assembly=System.Windows.Controls.DataVisualization.Toolkit”

and if you want some sample data, add a reference to the System dll:

xmlns:sys=”clr-namespace:System;assembly=mscorlib”

 Next, inside your Grid that serves as your Layout Root, “draw” a chart with a Dependent axis (X – bottom horizontal) and an Independent axis (Y – left vertical).  Throw in some sample data, and your chart XAML looks like this:

 <chartingToolkit:Chart
    
x:Name=”testChart”
    
BorderBrush=”Transparent”
     
Height=”400″

     Width=”400″>
    
<chartingToolkit:Chart.Series>
         
<chartingToolkit:BarSeries>
               <chartingToolkit:BarSeries.DependentRangeAxis>
                   
<chartingToolkit:LinearAxis
                        
Orientation=”X” />
               
</chartingToolkit:BarSeries.DependentRangeAxis>
              
<chartingToolkit:BarSeries.IndependentAxis>
                   
<chartingToolkit:CategoryAxis
                        
Orientation=”Y” />
              
</chartingToolkit:BarSeries.IndependentAxis>
              
<chartingToolkit:BarSeries.ItemsSource>
                   
<DoubleCollection>
                        
<sys:Double>50</sys:Double>
                        
<sys:Double>100</sys:Double>
                        
<sys:Double>250</sys:Double>
                   
</DoubleCollection>
              
</chartingToolkit:BarSeries.ItemsSource>
         
</chartingToolkit:BarSeries>
    
</chartingToolkit:Chart.Series>
</chartingToolkit:Chart>

Next post we will start looking into customizing all of these pieces.

October 3, 2011

SPListItem.DoesUserHavePermissions doesn’t work…or does it?

Filed under: Best Practices, Custom Web Parts, MOSS, Visual Studio 2010 — Susan Hernandez @ 8:48 pm

Don’t you hate when you make dumb – and upon later inspection, rather obvious – mistakes?

I was struggling (I’m too embarrassed to tell you how many hours) with the fact that even though I had broken permission inheritance, my code was always saying that the Current User had access to the list item – and full access at that (that should have been my first clue).

bool hasPermissions = false;
try
{
       //http://blogs.msdn.com/b/ryanrogers/archive/2004/07/15/184594.aspx
       site.CatchAccessDeniedException = false;

       hasPermissions = item.DoesUserHavePermissions(SPBasePermissions.ViewListItems);
}
catch (Exception ex2)
{
       hasPermissions = false;
}
finally
{
       site.CatchAccessDeniedException = true;
}

if (!hasPermissions)
{
       ShowError("User does not have permissions to list item");
       return;
}

So I thought the above code would work.  From everything I could see on the web, it SHOULD have worked.  So why didn’t it?

Turns out that I was running in Elevated Privileges mode, so the “Current User” was the system account.  Now mind you, that code above was NOT inside that Elevated Privileges wrapper – that’s what threw me I think.  But, what I did do (and I’m questioning now WHY did I do it this way) is that I had an SPWeb object variable that I set inside the RunWithElevatedPrivillges method.

SPList list = null;
SPWeb web = null;
SPSite site = null;
try
{
       SPSecurity.RunWithElevatedPrivileges(delegate()
       {
              using (SPSite secureSite = new SPSite(webURL))
              {
                     site = secureSite;
                     using (SPWeb secureWeb = secureSite.OpenWeb())
                     {
                           web = secureWeb;
                     }
              }
       });
}
catch
{
       ShowError("Could not retrieve web at '" + webURL + "'");
       return;
}

try
{
       list = web.Lists[listID];
}
catch
{
       ShowError("List ID '" + strListID + "' not found in web");
       return;
}

try
{
       SPListItem item = list.GetItemById(itemID);

So apparently the web object stayed elevated, thus the list was elevated, thus the List Item was elevated.  All I had to do was use the overload of the DoesUserHavePermissions method.  But that being said, I’m rethinking this whole, “pull it out of the elevated wrapper” thing I have going on here.  I’m marking this post as “Best Practices” as in what NOT to do :-) .

hasPermissions = item.DoesUserHavePermissions(SPContext.Current.Web.CurrentUser, SPBasePermissions.ViewListItems);

September 14, 2011

Posts from my company’s blog

Filed under: MOSS, SharePoint 2010 — Susan Hernandez @ 9:56 pm

I’ve been writing a few posts lately on my company’s blog.   Here’s a summary:

Older Posts »

Theme: Silver is the New Black. Blog at WordPress.com.

Follow

Get every new post delivered to your Inbox.