23 tháng 5, 2010

How to win friends and influence people

How to Win Friends and Influence People is well-known book for everyone who wants to improve their social skills (Vietnamese version). I read it but sometime it's not easy to remember and follow its ideas. Today I found a mind map picture that summarizes all aspects in the book and I think it would be helpful for other




From Internet

20 tháng 5, 2010

Use Feature to create custom list definition with custom fields and views

Recently I worked a SharePoint project and the client wanted to create some lists with their fields. On a list, they wanted to see items grouped by a particular one of their field. Obviously that the client needed custom list definition with fields and views. At first I thought this project would be not hard but it turned out that there are tricks that I need to know about creating custom list definition. So I'd like to note down those tips here to help out others who may be in trouble like me.

Assume that you looked at How to create custom list definition on MSDN.

1. Custom content type
There is a important note that people usually miss (me too :-) . Let say you create content type ABC which inherits from SharePoint standard Item content type (0x01), you must do two things in your content type definition and list definition
  • In content type ABC definition, remember to include fields which belong to the parent content type (Item) whereas adding custom fields for content type ABC
ContentTypeADefinition.xml

<Elements xmlns="http://schemas.microsoft.com/sharepoint/">
<ContentType ID="0x01008B7EF87D021E44fbBD83C21212A0B047"
Name="ABC ContentType"
Description="Custom ABC ContentType inherits from Item" >
<FieldRefs>
<!-- IMPORTANT: Remember to include fields that parent content type (Item for this case) uses -->
<Field ID="{fa564e0f-0c70-4ab9-b863-0177e6ddd247}" /> <!-- Title column is required by Item content type so here we include it in definition of ABC content type -->

<!-- Add custom fields here -->
<FieldRef ID="{7FD2A507-E6CB-4516-8C9A-C73E3C747524}" />
</FieldRefs>
</ContentType>
</Elements>
  • Do the same for list definition: include fields required by parent content type
schema.xml

<List xmlns:ows="Microsoft SharePoint" Title="Custom list"
Id="bc53ee2c-46b3-41ea-8deb-e75013c92eed" FolderCreation="FALSE"
Direction="$Resources:Direction;" BaseType="0">
<MetaData>
<Fields>
<!-- IMPORTANT: Add fields required by parent content type (Item) -->
<Field Name="Title" ID="{fa564e0f-0c70-4ab9-b863-0177e6ddd247}" DisplayName="$Resources:core,Last_Name;" Sealed="TRUE" SourceID="http://schemas.microsoft.com/sharepoint/v3" StaticName="Title"><!-- _locID@DisplayName="camlid1" _locComment=" " -->
</Field>

<!-- Add custom fields here -->
<Field ID="{7FD2A507-E6CB-4516-8C9A-C73E3C747524}" DisplayName="Item Name"
Name="ItemName" Type="Text" Group="Custom Columns" Required="TRUE"
SourceID="http://schemas.microsoft.com/sharepoint/v3" />
</Fields>

<!-- Other stuffs -->

</Metadata></List>

You can use SharePoint Manager to browse the SharePoint content types and its fields for getting field info easier.


2. Custom view
In order to define custom view, you probably need to know CAML and View schema . But there is another easier way to make it by making use of SharePoint Manager .
First, you create a custom view on desired list on SharePoint UI.



Second, after the view is created, you use SharePoint Manager to get the view definition by copy value of property HtmlSchemaXml in SharePoint Manager to schema.xml to make a new custom view. And there is one more important step





On the <View> element, make sure that those attributes are inserted

<View BaseViewID="2" Type="HTML" WebPartZoneID="Main" DisplayName="Custom view" SetupPath="pages\viewpage.aspx" ImageUrl="/_layouts/images/events.png" Url="CustomView.aspx" >

  • BaseViewID : this is an integer, make the attribute value uniquely with other View in schema.xml
  • WebPartZoneID="Main"
  • SetupPath : should be pages\viewpage.aspx so that the viewpage.aspx (this page is available in \\12\TEMPLATE\Pages\) is called when user uses your view

3. Use standard SharePoint forms in custom list

Normally, a custom list definition template created by WSS 3.0 Tools for Visual Studio usually has several files such as NewForm.aspx, DispForm.aspx, AllItems.aspx , ... And all those files are totally same as standard form in SharePoint. So if you don't have any plan to customize them, you can remove them from definition and tell SharePoint to use its standard form instead. The tip here is to add SetupPath attribute on <Form> element. Look at below xml fragment in schema.xml

schema.xml

<Forms>

<!-- I have a customized Display Form so that I keep the file DispForm.aspx in definition and SharePoint will called my customized DispForm.aspx when it renders Display Form -->
<Form Type="DisplayForm" Url="DispForm.aspx" WebPartZoneID="Main" />

<!-- For other forms, I don't change any on them so I use SetupPath attribute to tell SharePoint that calls its standard forms instead -->
<Form Type="EditForm" Url="EditForm.aspx" SetupPath="pages\form.aspx" WebPartZoneID="Main" />
<Form Type="NewForm" Url="NewForm.aspx" SetupPath="pages\form.aspx" WebPartZoneID="Main" />
</Forms>

4. Use Lookup field on list instance
You're creating two list definition called AL and BL. In AL you have a lookup field that references to Title field in BL. But the problem is that both AL and BL are custom lists and doesn't exist in site. It means you don't have List ID of BL required for lookup field.

SharePoint support another way to solve this problem by allowing user to put an relative URL on lookup field. How nice it is :-). On our AL and BL, the trick is to provide the correct URL of BL instance in lookup field definition in AL. And the safe way to ensure the correctness of URL is that you use <ListInstance> to create a new list instead of letting user do.

ListInstances.xml

<ListInstance Id="InstanceOfBL" Title="BL List" TemplateType="10010" Url="Lists/BLInstance01">

You can see that I instruct SharePoint to create a new instance of BL template with Lists/BLInstance01 URL. So I will provide this value into lookup list definition in AL and that solves our problem

schema.xml in AL

<Field Type="Lookup" DisplayName="Lookup Field 1" Required="FALSE" List="Lists/BLInstance01" ShowField="Title"
EnableLookup="TRUE" UnlimitedLengthInDocumentLibrary="FALSE" ID="{7FD2A507-E6CB-4516-8C9A-C73E3C747523}"
SourceID="http://schemas.microsoft.com/sharepoint/v3" Name="LookupField1" />


The List attribute is supposed to have a GUID but here we use relative URL (because the list instance haven't existed yet) and SharePoint accepts the url too.

Read more here

5. Create custom List Template as document library

If you're creating a document library as list template. Remember adding two attributes in the definition. Look at below xml fragment

<ListTemplate
Name="CustomDocLib"
DisplayName="Custom Document Library"
BaseType="1"
Type="101"
OnQuickLaunch="TRUE"
SecurityBits="11"
Sequence="1004"
DocumentTemplate="101" />

  • BaseType="1" : this attribute announces SharePoint that you're creating a document library, not a list. BaseType="1" means document library, BaseType="0" means list
  • DocumentTemplate="101" : this attribute makes the New Item menu item appear in New menu in toolbar. If you don't include this, you won't see New Item :-)
6. How to get the SharePoint item (SPItem) that is associated with the webpart editor in NewForm.aspx , EditForm.aspx and DispForm.aspx ?

There is sometime you need to customize editor forms so that you want to retrieve the SPItem which is processed within the form (i.e. to support for your business). E.x: every time user creates new item, you want to update the lookup field in other list that refers to newly created SPItem.

So in this case, we need a customized NewForm.aspx. Create NewForm.aspx (via Windows SharePoint Services 3.0 Tool) for the list definition. Then replace the code behind of NewForm.aspx with yours (it's created soon)

<%@ Page language="C#" MasterPageFile="~masterurl/default.master"
Inherits="MyAssembly.Features.NewCustomForm" %>


Then create new class called NewCustomForm that inherits from Microsoft.SharePoint.WebParPages.WebPartPage class

namespace MyAssembly.Features
{
public class NewCustomForm : WebPartPage
{
// This is the web part declared by default in NewForm.aspx
protected global::Microsoft.SharePoint.WebPartPages.WebPartZone Main;
}
}
}
}


Now we have a customized NewForm.aspx, before go on. Let I show you how we can retrieve the SPItem in editor first. Here the snipet code to get the SP item go with this web part and this code is going to put on our NewCustomForm class.

// By default, this page only has one webpart
// If user has customized it, we stop
if (this.Main.WebParts.Count == 1)
{
var webpartForm = this.Main.WebParts[0] as ListFormWebPart;
if (webpartForm != null)
{
var listItem = webpartForm.ItemContext.Item; // Got the SPItem going with the webpart editor
// do any thing here
// ...
}
}

You can put above code in Page_Load for example to get the item fields, or in Page_Unload to get newly created item (Note, because when a new item is saved, the page is redirected to Source param and it doesn't fire next events such as PreRender, Render so we have to use Unload event, another way is to override Dispose() method)

In short, by using ListFormWebPart.ItemContext.Item property, we can get the associated SPItem within editor and this property is very helpful in many scenarios.


Other tips

16 tháng 5, 2010

C# 4.0

Main reference at: http://msdn.microsoft.com/en-us/vcsharp/ff628440.aspx

The great feature introduced in C# 4.0 is dynamic programming which is also presented in MSDN lately. And some other new features:
  • Named and optional parameters
  • Variance
How named and optional parameter feature works

The C# compiler supports this feature and the runtime have no idea about named and optional parameter at all. The main idea is that the default value of parameter is transformed into attributes which is marked on parameter itself. And when the C# compiler see any invocation using optional or named feature, it will look into the source definition (method, delegate ...) and use info from attributes on optional parameter and then adjust the invocation again.

Below is the sample code using optional feature



And next picture is the disassembled code. It's observed that C# compiler 4.0 generated automatically Optional and DefaultParameterValue attribute on those parameters. And when any invocation to the method DoThing1() occurs, the C# compiler sees these attributes and it knows what value shoud be put to the missing parameter in the invocation.




In nutshell, how to play with covariance and contravariance

Look at below code snipe

Covariance
IList<Stream> streams = new List<FileStream>();


Contravariance
IList<FileStream> streams = new List<Stream>();

And the reason why this magic can happen are available on net. But I can understand it in this way: two these features allow us to cast generic interface or method to relative its subclass or superclass.

And dynamic

dynamic gives C# wings to make it more stronger. Before NET 4.0, C# is statically typed language. Now with Dynamic Language Runtime (a bunch of new API) and C# 4.0 compiler, you can use coding JavaScript style happily in C#.

Here is summary: dynamic is a type. That means I can declare a variable /property / parameter with type dynamic, return a type dynamic in method / property ... I'm even able to use dynamic with some operators like as , is . The distinct feature of dynamic type is that all operators / invocations on dynamic type isn't checked in compiled-time, it's done in runtime. That's all.

Reference for dynamic: