How to use the SPGridView filter together with a SPDataSource

Normally you will no problems finding examples on how to use the SPGridView together with an ObjectDataSource and use the filtering mechanism. But what about using the SPDataSource object?

This can also be done fairly simple. You do the basic things as you do using an ObjectDataSource object, however, there are two things that you will have to change.

1. The ObjectDataSource has a FitlerExpression property that set the filter for the data source. That isn’t available on the SPDataSource object. Instead we have the SelectCommand property. The format string for this property is the same as in a standard CAML Query where clause.

2. We will need to set the SPGridView DataSourceID property instead of the more normally used DataSource property.

3. We have to add the SPDataSource control to the Controls colelction of the Web Part.

So let’s look at some code samples.

First, we have our usual suspects, one SPGridView and one SPDataSource:

private SPGridView gridView;
private SPDataSource dataSource;
this.dataSource = new SPDataSource();
this.dataSource.ID = "myDataSource";

 

In our CreateChildControls() method ( if it’s in a Web Part), we can do much of the work. I have commented the code, so I will not say so much about it more.

this.gridView = new SPGridView();
// Get our currnet Web object
SPWeb web = SPContext.Current.Web;
// And the SPList
SPList taskList = web.Lists["Tasks"];
// Assign the SPlist to our SPDataSource object
dataSource.List = taskList;
// Add our SPDataSource object to the Controls collection so that our SPGridView can find it.
this.Controls.Add(dataSource);
// Disable auto generation of columns
this.gridView.AutoGenerateColumns = false;
this.gridView.ID = "gridView1";
// Add the Title column.
BoundField colTitle = new BoundField()
{
DataField = "Title",
HeaderText = "Title",
SortExpression = "Title"
};
this.gridView.Columns.Add(colTitle);
// Add the Status column
BoundField colProgress = new BoundField()
{
DataField = "Status",
HeaderText = "Status",
SortExpression = "Status"
};
this.gridView.Columns.Add(colProgress);
// Enable filtering
this.gridView.AllowFiltering = true;
// We will not filter on the Title, so start with a comma
this.gridView.FilterDataFields = ",Status";
// Set the propertyname of the data source object
this.gridView.FilteredDataSourcePropertyName = "SelectCommand";
// Set the filter format. {1} will contain the column and {0} will contain the value.
this.gridView.FilteredDataSourcePropertyFormat = "<View><Query><Where><Eq><FieldRef Name='{1}'/><Value Type='Text'>{0}</Value></Eq></Where></Query></View>";
// Set the DataSource ID to our SPDataSource.ID
this.gridView.DataSourceID = "myDataSource";
// Add the GridView to our Controls collection
this.Controls.Add(this.gridView);
// Now data bind.
this.gridView.DataBind();

How to target 32bit and 64bit a .NET applications with WiX and separate MSI packages

Target 32bit and 64bit .NET applications

This post will explain how you can build msi packages using WiX for both 32bit and 64bit platforms.  The goal is to create 2 different msi packages. One for 64bit systems, which will install the program in to c:\Program Files on 64bit, and another msi package that will install the program in to c:\Program Files on 32 bit systems. The .NET application itself will be compiled with CPU target Any, which results in that it will run in 64bit mode on 64bit systems and 32bit mode on 32bit systems. Of course, you could also install the 32bit msi package on 64bit systems, which will end up being installed in c:\Program Files (x86).

Pre-requisites:

Microsoft Visual Studio 2008

In my environment, I used 64bit Windows7, so I installed the 64bit version of WiX build 3.0.5419.0-x64-setup

Create a simple .NET application

We will create a simple .NET Winforms application that will show some platform information, like this:

 

image

We will also create a WiX setup project and configure a new platform type in Visual Studio for the 64bit target.

Fire up Visual Studio and create a new Windows Forms project:

image

Add 3 labels to the form:

image

Add code in the Form Load event to fill the labels with info:

 

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Runtime.InteropServices;
using System.Diagnostics;
namespace WindowsSetupTest
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
label1.Text = "Platform: " + System.Environment.OSVersion.Platform.ToString();
label2.Text = "Is 64bit OS: " + Is64Bit().ToString();
label3.Text = "Is 32bit process on 64bit OS: " + Is32BitProcessOn64BitProcessor().ToString();
}
[DllImport("kernel32.dll", SetLastError = true, CallingConvention = CallingConvention.Winapi)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool IsWow64Process([In] IntPtr hProcess, [Out] out bool lpSystemInfo);
private bool Is64Bit()
{
if (IntPtr.Size == 8 || (IntPtr.Size == 4 && Is32BitProcessOn64BitProcessor()))
{
return true;
}
else
{
return false;
}
}
private bool Is32BitProcessOn64BitProcessor()
{
bool retVal;
IsWow64Process(Process.GetCurrentProcess().Handle, out retVal);
return retVal;
}
}
}

 

Create a Wix project

Add a new project to the solution, a WiX Setup project:

image

In the Product.wxs file, enter the following code:

<?xml version="1.0" encoding="UTF-8"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
<?define InstallName  = InsomniacGeek ?>
<!-- Product name as you want it to appear in Add/Remove Programs-->
<?if $(var.Platform) = x64 ?>
<?define ProductName = "InsomniacGeek: Windows Setup Test (64 bit)" ?>
<?define Win64 = "yes" ?>
<?define PlatformProgramFilesFolder = "ProgramFiles64Folder" ?>
<?else ?>
<?define ProductName = "InsomniacGeek: Windows Setup Test" ?>
<?define Win64 = "no" ?>
<?define PlatformProgramFilesFolder = "ProgramFilesFolder" ?>
<?endif ?>
<Product Id="*" Name="$(var.ProductName)"
Language="1033" Version="1.0.1"
Manufacturer="InsomniacGeek"
UpgradeCode="2551D901-A700-484b-B35C-B8E3D358FE73">
<Package Id="CC76D2EF-6A0A-468e-89D6-6953AAEFCD06" Keywords="Installer"
Description="$(var.ProductName)"
InstallerVersion="200" Compressed="yes"
Platform="$(var.Platform)"/>
<Upgrade Id="2551D901-A700-484b-B35C-B8E3D358FE73">
<UpgradeVersion Minimum="1.0.0" IncludeMinimum="yes" Maximum="1.0.1" Property="OLDERVERSIONBEINGUPGRADED"/>
<UpgradeVersion Minimum="1.0.1" OnlyDetect="yes" Property="NEWERVERSIONDETECTED"/>
</Upgrade>
<Media Id="1" Cabinet="media1.cab" EmbedCab="yes" />
<Condition Message="A later version of [ProductName] is already installed. Setup will now exit">
NOT NEWERVERSIONDETECTED OR Installed
</Condition>
<!-- Program Files \ App \  -->
<Directory Id="TARGETDIR" Name="SourceDir">
<Directory Id="$(var.PlatformProgramFilesFolder)">
<Directory Id="INSTALLLOCATION" Name="InsomniacGeek">
<Directory Id="APPLICATIONROOTDIRECTORY" Name="Windows Setup Test"/>
</Directory>
</Directory>
<!-- Start Program menu -->
<Directory Id="ProgramMenuFolder">
<Directory Id="ApplicationProgramsFolder" Name="InsomniacGeek Windows Setup Test"/>
</Directory>
</Directory>
<!-- Files in app path -->
<DirectoryRef Id="APPLICATIONROOTDIRECTORY">
<Component Id='MainApp' Guid='9D181A16-5383-45b8-9D13-A0781060CA16'>
<File Id='MainApp' Name='WindowsSetupTest.exe'
DiskId='1' Source='..\WindowsSetupTest\bin\Debug\WindowsSetupTest.exe'/>
</Component>
</DirectoryRef>
<!-- Shortcut -->
<DirectoryRef Id="ApplicationProgramsFolder">
<Component Id="ApplicationShortcut" Guid="953BEB35-E0BB-40ae-A1C8-F8A88E1E2529">
<Shortcut Id="ApplicationStartMenuShortcut" Name="Windows Setup Test" Description="Application for testing"
Target="[APPLICATIONROOTDIRECTORY]WindowsSetupTest.exe"
WorkingDirectory="APPLICATIONROOTDIRECTORY"/>
<Shortcut Id="UninstallProduct"
Name="Uninstall the InsomniacGeek Windows Setup Test"
Target="[System64Folder]msiexec.exe"
Arguments="/x [ProductCode]"
Directory="ApplicationProgramsFolder"
Description="Uninstalls InsomniacGeek Windows Setup Test" />
<RemoveFolder Id="ApplicationProgramsFolder" On="uninstall"/>
<RegistryValue Root="HKCU" Key="Software\InsomniacGeek\WindowsSetupTest" Name="installed" Type="integer" Value="1"
KeyPath="yes"/>
</Component>
</DirectoryRef>
<!-- Features -->
<Feature Id="Complete" Title="Windows Setup Test" Level="1"
Description="The complete package"
Display="expand" ConfigurableDirectory="APPLICATIONROOTDIRECTORY" >
<Feature Id="MainProgram" Title="Program" Description="The main executable" Level="1">
<ComponentRef Id="MainApp"/>
<ComponentRef Id="ApplicationShortcut"/>
</Feature>
</Feature>
<InstallExecuteSequence>
<RemoveExistingProducts After="InstallInitialize"/>
</InstallExecuteSequence>
<!-- UI -->
<UIRef Id="WixUI_Mondo"/>
<UIRef Id="WixUI_ErrorProgressText" />
<!-- End UI -->
</Product>
</Wix>

 

And add references to WixUIExtension.dll and WixUtilExtension.dll.

What you will notice now is that you have 3 targets in your configuration:

image

The value you choose here will be transferred to the Platform variable in WiX. Unfortunately, the 64bit option is missing, so we must create that one.

Create a x64 configuration entry

Select the Configuration Manager.

image

Select  <New…>

image

image

Select the x64 option and click Ok.

Building

When you now build the Wix project, the output will be created in a new x64 folder. In the Product.wxs code, we also have a title that indicates that is runs in 64bit mode:

image

image

When installed, it will end up in c:\Program Files, just as we wanted.

The 32bit version of the msi is built when you select the x86 platform target

image

image

 

Hope this shed some light on how to deploy .NET applications for multiple targets.

Download the complete solution here.

How to get the full URL from SPListItem in SharePoint

The SPListItem URL property does return the URL for the SPListItem including the List/Documetn Library name, but it doesn’t return the full URL including the server and site names.

To get the full URL, you can either concatenate the SPLIstItem.Web.Url and the SPListItem.URL, or extract the full URL from the SPListItem.XML data like this:

 

foreach (SPListItem item in list.Items)
{
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.LoadXml(item.Xml);
XmlNamespaceManager nsm = new XmlNamespaceManager(xmlDoc.NameTable);
nsm.AddNamespace("z", "#RowsetSchema");
string fullURL = xmlDoc.SelectSingleNode("z:row", nsm).Attributes["ows_EncodedAbsUrl"].Value;
}

 

Of course, you should add the usual error handling and checking.