Thursday, August 26, 2010

Display images from embedded resources in ASP.NET

From one Web application to another, we often reuse the same picture for saving, editing and deleting data. To avoid copying these images again and again, from one site to another, you can embed theses images inside a class library that will be referenced by all your projects. This will have the benefit of sharing the same images/icons across all your Web sites and therefore, if you have new images, you only have to replace the images inside the class library and the changes will be applied on all your Web sites.

Now, let me show how you can do that.

Step 1: Create class library project

The first step is to create a class library project in which we will add the images. Here, I will create two different class libraries, one in C# and the other one in VB to show you the minor differences between both languages. I named the C# class library “MyCSharpClassLibrary” and the VB class library “MyVBClassLibrary”. In both projects, I added the folder Resources/Images. Then, I added in the C# library the images for the delete and edit images and in the VB class library, the save and cancel images. The projects should look like this:

image



Step 2: Embedding images has resource

Now that we have added the images to our class library, we need to make sure these images will be include when building the assembly. To do that we need to change build action on each images using the property window. The default value for this type of files is “Content”. All we need to do is to change that value to “Embedded Resource”.

image


Step 3: Enabling Web resource

Finally, we need to enable these embedded resources in order to be used as Web resource. This is done using the WebResourceAttribute attribute inside the assembly declaration of our class libraries. The WebResourceAttribute constructor take two parameters. The first one is a string representing the name of the Web resource and the second one is a string that represents the content type like “text/javascript” or in our case “image/gif”.



For the first parameter, the name of the Web resource, we need to specify the fully qualified namespace of the embedded resource, which include the full path in c# but not in VB. So to enable the embedded resources as a Web resource in the C# class library, you simply open the assembly file “AssemblyInfo.cs” and add the following lines:

  1. [assembly: WebResource("MyCSharpClassLibrary.Resources.Images.Delete.gif", "img/gif")]
  2. [assembly: WebResource("MyCSharpClassLibrary.Resources.Images.Edit.gif", "img/gif")]




In the VB class library “AssemblyInfo.vb” file, you add the following two line:

  1. <Assembly: WebResource("MyVBClassLibrary.Cancel.gif", "img/gif")>
  2. <Assembly: WebResource("MyVBClassLibrary.Save.gif", "img/gif")>



Note that you will need a "using" or "Import" directive for System.Web.UI, which is where WebResourceAttribute is.



Step 4: Add reference to our class libraries

Once our class libraries are completed and compile, it’s time to add them to our Web project using the add reference dialog and adding a reference to both class libraries.

image image

Step 5: Using the Web resource

Finally, all that is left to do is to used these embedded images. This is done using the ClientScriptManager.GetWebResourceUrl method like this: This method take two parameters: the type of the resource and the fully qualified name of the resource in the assembly. It will return the URL reference to a resource in the assembly. Therefore, to use our embedded image, all we have to do is to set the ImageUrl property to the desired Web resource.

  1. Image1.ImageUrl = Page.ClientScript.GetWebResourceUrl(typeof(MyCSharpClassLibrary.Class1), "MyCSharpClassLibrary.Resources.Images.Edit.gif");
  2. Image2.ImageUrl = Page.ClientScript.GetWebResourceUrl(typeof(MyVBClassLibrary.Class1), "MyVBClassLibrary.Save.gif");








A good example would be in a GridView like this:

image image

This is done by using ImageButton controls in a TemplateField for the edit, update, delete and cancel operations.



  1. <asp:TemplateField>
  2. <ItemTemplate>
  3. <asp:ImageButton ID="btnEdit" runat="server" ImageUrl='<%# (GetEditImageUrl()) %>'
  4. CommandName="Edit" />
  5. <asp:ImageButton ID="btnDelete" runat="server" ImageUrl='<%# (GetDeleteImageUrl()) %>'
  6. CommandName="Delete" />
  7. </ItemTemplate>
  8. <EditItemTemplate>
  9. <asp:ImageButton ID="btnUpdate" runat="server" ImageUrl='<%# (GetUpdateImageUrl()) %>'
  10. CommandName="Update" />
  11. <asp:ImageButton ID="btnCancel" runat="server" ImageUrl='<%# (GetCancelImageUrl()) %>'
  12. CommandName="Cancel" />
  13. </EditItemTemplate>
  14. </asp:TemplateField>








If you notice, I bind the ImageUrl property to simple method that return the assembly resource URL.
  1. public string GetDeleteImageUrl()
  2. {
  3. return Page.ClientScript.GetWebResourceUrl(typeof(MyCSharpClassLibrary.Class1), "MyCSharpClassLibrary.Resources.Images.Delete.gif");
  4. }
  5. public string GetEditImageUrl()
  6. {
  7. return Page.ClientScript.GetWebResourceUrl(typeof(MyCSharpClassLibrary.Class1), "MyCSharpClassLibrary.Resources.Images.Edit.gif");
  8. }
  9. public string GetCancelImageUrl()
  10. {
  11. return Page.ClientScript.GetWebResourceUrl(typeof(MyVBClassLibrary.Class1), "MyVBClassLibrary.Cancel.gif");
  12. }
  13. public string GetUpdateImageUrl()
  14. {
  15. return Page.ClientScript.GetWebResourceUrl(typeof(MyVBClassLibrary.Class1), "MyVBClassLibrary.Save.gif");
  16. }








This is it. Nothing more complicated!

Enjoy,

Bruno

Wednesday, August 4, 2010

TIPS: Hide non visual control in designer

During one of the ASP.NET training I gave, I’ve been ask if it was possible to hide the non visual control from the Visual Studio designer. Well I know for sure how easy it was with Visual Studio 2005, with the “Non Visual Control” option from the “View” menu.

image_thumb

But guess what, in Visual Studio 2008, this option has been regroup under “Visual Aids” option of the “View” menu.

VisualAidsMenu_thumb2

Notice that the shortcut has change from Ctrl+Alt+Q in Visual Studio 2005 to Ctrl+Shift+N in Visual Studio 2008, but don’t get too scary, this hasn't change in Visual Studio 2010!

Enjoy,

Bruno

GridView and HyperLinkField

It’s been a while since I use the GridView control to display data and I just realize that I have never used the HyperLinkField to provide a link to another page with the data from the the database. Every time I needed to do so, I always use a TemplateField with an HyperLink control.

Well with the HyperLinkField, is so easy to provide a link with the data needed in query string! As an example, lets say I want to give a link to the user to display customer information from an order. We would have two web pages, one page showing the orders from the Northwind database and another page that display the customer information from an order. The customer information page will display the customer data from the customer id send via the query string parameter.

In the past, I would have used a TemplateField to provide a link for the customer information like this:
   1: <asp:TemplateField HeaderText="CustomerID" SortExpression="CustomerID">
   2:    <ItemTemplate>
   3:       <asp:HyperLink ID="HyperLink1" runat="server"
   4:          NavigateUrl='<%# "~/CustomerInfo.aspx?CustId=" 
   5:             + DataBinder.Eval(Container.DataItem, "CustomerID") %>'
   6:          Text='<%# Bind("CustomerID") %>' Target="_blank"></asp:HyperLink>
   7:    </ItemTemplate>
   8: </asp:TemplateField>

Here is how to get the same result by using an HyperLinkField and setting the DataNavigateUrlFields and DataNavigateUrlFormatString properties:


   1: <asp:HyperLinkField HeaderText="CustomerID" DataTextField="CustomerId" 
   2:     DataNavigateUrlFields="CustomerId"
   3:     DataNavigateUrlFormatString="~/CustomerInfo.aspx?CustId={0}"  
   4:     Target="_blank" />

The end result is exactly the same but the it is a lot easier to use the HyperLinkField than the TemplateField!

Regards,

Bruno

Monday, August 2, 2010

Use DataFormatString to format GridView fields

In a previous post, is show you how to use the GridView DataKeys property to retrieve multiple  information about the selected row. In this post, I will show you how to format GridView fields using the DataFormatString attribute. Lets start with two simples GridView showing the orders and order details from the Northwind sample database.
image

Currency fields

Lets start by formatting the “Freight” field from the orders and the “UnitPrice” field from the order details into currency. The formatting string used by the DataFormatString property can be any literal string. Usually, it will includes a placeholder for the field’s value. The placeholder consists of two parts separated by a colon and wrapped in braces like this: {A:Bxx}. The value before the colon represents the field value’s index but since there is only one field value in each grid view cells, this value will always be 0. The character after the colon is optional and specifies the format to display the value in. The value after the format character specifies the number of significant digits or decimal places to display.

If we do not specified any value, it will take the default value from the settings in the Regional and Language Options item in the Control Panel. Since the character to displays numeric values in currency format is ‘C’, and my default number of digits after the decimal is set to two, I can set the DataFormatString for the freight and unit price field to “{0:c}”.

image
To set the value of the DataFormatString property, we can either edit the fields from the GridView smart tag “Edit columns” options or set the value manually from the source window.
image 
   1: <asp:BoundField DataField="Freight" DataFormatString="{0:c}" 
   2:       HeaderText="Freight" SortExpression="Freight" />

If we want to display the unit price with 4 decimals, all we have to do is to specify the number of digits after the decimal like this: “{0:c4}”.


   1: <asp:BoundField DataField="UnitPrice" DataFormatString="{0:c4}"
   2:       HeaderText="UnitPrice" SortExpression="UnitPrice" />
This will produce the following output:

image

Date and time fields

Now, to format date and time fields, we can specify our own format string with characters like ‘d’, ‘M’ and ‘y’ like this “{0:yyyy/MM/dd}”. We can also refer to the following table that list the most common format string used to format date and time:

Format PatternNameExample
d
Short date pattern
8/16/2010
D
Long date pattern
Monday, August 16, 2010
t
Short time pattern
2:42 PM
TLong time pattern2:42:00 PM
fFull date/time pattern (short time)Monday, August 16, 2010 2:42 PM
F
Full date/time pattern (long time)
Monday, August 16, 2010 2:42:00 PM
gGeneral date/time pattern (short time)8/16/2010 2:42 PM
GGeneral date/time pattern (long time)8/16/2010 2:42:00 PM
m or MMonth day patternAugust 16
r or RRFC1123 patternMon, 16 Aug 2010 14:42:00 GMT
y or YYear month patternAugust, 2010

Therefore, by setting DataFormatString of the date fields OrderDate, RequiredDate and ShippedDate like this:


   1: <asp:BoundField DataField="OrderDate"DataFormatString="{0:f}"
   2:    HeaderText="OrderDate" SortExpression="OrderDate" />
   3: <asp:BoundField DataField="RequiredDate" DataFormatString="{0:yyyy/MM/dd}"
   4:    HeaderText="RequiredDate" SortExpression="RequiredDate" />
   5: <asp:BoundField DataField="ShippedDate" DataFormatString="{0:D}"
   6:    HeaderText="ShippedDate" SortExpression="ShippedDate" />

We now have the following display:

image

Again, this is important to remember that the output is based on the settings in the Regional and Language Options item in the Control Panel. Here is how it look like for me:

image

I hope this will help you,

Bruno

Sunday, August 1, 2010

Master details with multiple data keys

In this post, I will show you how simple it is to get many information from a single ASP.Net grid view control. To do that, we will use the Northwind sample database.

Let start first with a simple web page with only a GridView and a SqlDataSource. We use the GridView to display the data from the Orders table. After applying a little bit of style to the GridView, the web form should look like this:

image

Now that we have our orders displayed, the first thing we might want to show when selecting an order is the details of that selected order. To do that, we simply drag another GridView controls from the toolbox to the design surface. We use a GridView since we want to display all the order details at the same time. From the GridView smart tag, we add a new SqlDataSource and we select all fields from the “Order Details” table like this:

image

Then, we select the “Where” option to specify that the OrderID field should be equals to the selected OrderID of the orders GridView control.

image

From the previous screen shot, we can see that the value will be the “SelectedValue” property of the orders GridView control. Click Add and then OK, Next and Finish to complete the data source configuration wizard.

Now, we can view our web page in the browser to see if everything is working fine.

image  image

Good. From the above captures, we can see that everything work has expected. But maybe you don’t really know why!! Well if you remember, we have set the source of the select parameters for the order details data source to the property SelectedValue of our master grid view. That return the value of the first key field of the selected row. If we look at the source of our master grid view, we can remark that the DataKeyNames for that grid view is set to “OrderId”. That means that the SelectedValue property of our grid view will return the OrderId of the grid view selected row.

image

Now, what if we want to display also the customer information for the selected order? We can add a DetailsView control to the web form and again, use the smart tag to configure the data source. This time, we want to display data from the Customer table.

image

Again, for the where clause, we should specify that the CustomerId column should be equal to the orders grid view control SelectedDataKeys property. The only problem is that we cannot change source value from the wizard and by default, it uses the grid view SelectedValue property.

image

How can we change this value? Well even if we are using the data source configuration wizard, it doesn’t mean that we cannot change manually the code that was generated from the wizard! So let’s change the the property name of the select parameters from SelectedValue to SelectedDataKey.Value[CustomerId].

image

image

Now, if we look at the page in the browser and we select an order, you should have the following result:

image

You can notice that we don’t have the customer information displayed. The reason is simple, the master grid view does not have the CustomerID in his data keys. All we have to do is to add it in the grid view DataKeyNames attribute like this:

image

And now, we have the order details and customer information for the selected order.

image

Now, if I ask you how I can display the Employee information for the selected order, I’m pretty sure you all know how to do it! :)

Regards,

Bruno

Friday, July 30, 2010

ASP.NET Menu issue with Safari

The popular Apple Safari browser is available on Windows since 2007. So now, the famous “I don’t have a Mac” reason is no longer acceptable when developing Web site that target everyone. This is not a big deal, unless you want to use the ASP.NET Menu control on your web site. There is as small issue with the rendering of that control inside Safari browser and prevent sub-menu items to be displayed.
Here is a sample Web page viewed with Safari 5. The page contains a Menu control and some labels to show information about the selected menu items.
image
We can see that the “Support” menu items contains sub-menu items but even when the mouse hover that menu items, the sub-menu doesn’t show. One quick and easy solution to fix this problem is to set the Page.ClientTarget property to “uplevel” in the page pre init event.
For those of you who don’t know, the Page.ClientTarget property allows you to override the automatic detection of browser capabilities and to specify how a page is rendered for a particular browser client.
More information about the ClientTarget property can be found on MSDN Web site:
http://msdn.microsoft.com/en-us/library/system.web.ui.page.clienttarget.aspx
Here is the C# code for setting the Page.ClientTarget property:
   1: protected void Page_PreInit(object sender, EventArgs e)
   2: {
   3:     if (Request.ServerVariables["http_user_agent"].IndexOf("Safari", StringComparaison.CurrentCultureIgnoreCase) != -1)
   4:     {
   5:         Page.ClientTarget = "uplevel";
   6:     }
   7: }

And the VB code:


   1: Protected Sub Page_PreInit(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.PreInit
   2:     If (Request.ServerVariables("http_user_agent").IndexOf("Safari", StringComparaison.CurrentCultureIgnoreCase) <> –1) Then
   3:         Page.ClientTarget = "uplevel"
   4:     End If
   5: End Sub

image

Please note that this needs to be implemented on all Web pages on which the menu should be.

For those of you that would like to see how their Web sites look on Safari but doesn’t have an Apple computer, you can download the Windows version of Safari browser here:

http://www.apple.com/safari/

Best regards,

Bruno

Technorati Tags: ,,

Sunday, July 25, 2010

Hello World!

Hello everyone. My name is Bruno Pelletier and I’m a senior .NET Analyst-Programmer-Developer. I lived in the great Montreal (QC) region.

I started my career as an analyst programmer for a company in the supply chains industry. I was developing windows application with VB6 and web sites with classic ASP. I start programming with Microsoft .NET Framework in 2002 and since then, I cannot live without it!!!

I got my first Microsoft Certification in August 2008 (MCTS Web Applications) and I’m currently looking to get more Microsoft certification.

This blog is related to Microsoft .NET technologies and more specifically ASP.NET, Silverlight and AJAX. As a member of the Montreal .NET Community, formerly known has the GUVSM (Groupe d’Usagers Visual Studio Montréal), I will occasionally give a brief resume and comments about the meeting that I will attend. I also invite you to visit the Montreal .NET Community web site www.dotnetmontreal.com to have more information about the group and for upcoming meetings. I will also discuss about events that I will participate like the DevTeach, Tech-Ed and others.

Don’t hesitate to send me feedback and comments about this blog. We’d love getting your feedback about and let us know what you want to see discussed in the future.

Bruno