Monday, August 31, 2009

Format DateTime in a dropdownlist (with different CultureInfo)

It turned out to be very easy, but it took me at least 30 minutes to figure out the easiest way to do it.
So i figured it's worth a little blog post.

The magic happens by using the DataTextFormatString property of the dropdownlist.
But i didn't know how to format the date properly until i figured out i had to use {0}.
Here is how to do it:

// Create a list with dummy dates
List<DateTime> dates = new List<DateTime>();
for (double i = 1; i <= 31; i++)
{
dates.Add(DateTime.Now.AddDays(i));
}

// Specify the dateformat (e.g. outputs today as "31-08-2009 18:40")
ddlMyDropdown.DataTextFormatString = "{0:dd-MM-yyyy hh:mm}";

// Databinding
ddlMyDropdown.DataSource = dates;
ddlMyDropdown.DataBind();

Note that .NET uses the culture of the current thread to format the date.
So if i used format {0:dd MMMM yyyy} which would output as "31 August 2009" and i want to write it out in another culture, let's say dutch (31 augustus 2009).
Then i need to execute the following code before i perform the databinding:

// Set current culture for current thread to dutch
System.Threading.Thread.CurrentThread.CurrentCulture = new System.Globalization.CultureInfo("nl-NL");

Hope this saves you some time googling for it ;)

/Ruud

Friday, August 21, 2009

Call document OnLoad after an AJAX.NET request

When you use your own JavaScript combined with AJAX.NET, you might bump into the problem that your document OnLoad event is not fired after AJAX requests.
This can be solved by using AJAX.NET's endRequest event.
Please note that i use jQuery, so you will need that in order for this example to work.

var documentReady = function() {
// here you do all the stuff you would normally do in $(document).ready()
}

$(document).ready(documentReady);

// This will call the documentReady() function every time an AJAX request is finished
Sys.WebForms.PageRequestManager.getInstance().add_endRequest(function() {
documentReady();
});

This can of course be used to call any function after an AJAX request.

2009-08-25: I just found out that you can also use add_pageLoaded() instead of add_endRequest().

/Ruud

Thursday, August 20, 2009

jQuery removeOptionByValue plugin for dropdown list

I needed to remove an option with a specific value from a select element with JavaScript.
It seems that jQuery lacks something like a removeOptionByValue() method.
I tried to use a selector to remove one option, like this: $("#mySelect option[@value=ToBeRemoved]").remove() but that resulted in an error.
So i wrote a little plugin for it.

This is the example HTML:

<select id="ddlTest">
<option value="">- Please choose -</option>
<option value="first">First option</option>
<option value="second">Second option</option>
<option value="third">Third option</option>
</select>

<input id="btnTest" value="Test" type="button">

We would like to remove the option with value "first" when the button is clicked.
This is the javascript i wrote:

(function($) {
$.fn.removeOptionByValue = function(optionValue) {
if ($(this).is("select")) {
var itemIndex = -1;
var dropdownId = $(this).attr("id");

$("#" + dropdownId + " option").each(function() {
itemIndex++;
if ($(this).val() == optionValue) {
$("#" + dropdownId)[0].remove(itemIndex);
}
});
}
}
})(jQuery);

// Test if it works
$("#btnTest").click(function() {
$("#ddlTest").removeOption("first");
});

Download the solution as jQuery plugin here: jquery.removeoptionbyvalue.js

/Ruud

Wednesday, August 19, 2009

window.open resulting in "Invalid argument" error in IE

I kept getting an Invalid Argument error in IE while trying to execute window.open() in JavaScript.
Appearantly in IE you cannot use spaces in the name you give to the window.

So...

window.open("mypage.html", "my window name");

...does not work, while...

window.open("mypage.html", "mywindowname");

...works fine.

/Ruud

Friday, August 14, 2009

TechSite CMS

When i started dotTech i decided to write my own .NET based Content Management System.
My goal was to expand my knowledge of .NET and to be able to offer my customers an easy-to-use content management solution.
I think the result is a steady base for an easily expandable CMS with great possiblities.
As interest towards this CMS grows, i decided to make a blog post about it.


TechSite explained
The CMS is item-based and the user interface is build around a treeview that represents the website's content structure.
From the tree the items can be added, changed, renamed, removed and moved.
When adding an item, the user can choose between different item templates (for example, a product item or a news item).
Item templates consist of regions (e.g. content, specifications) and regions constist of fields (see screenshot).
Fields can be of different types, for example single line text, html text, image or a date.
The current version contains 8 fieldtypes and these are very easy to expand.
How the item templates are treated on the frontend depends on the implementation and is independent of the backend.
That is one of the things i really like about this solution: i can provide the customer with a fully working backend before i start with the implementation of the frontend.

A quick peek at the highlights and features:
- Based on .NET 2.0
- Support for all major browsers (IE6-8, FF2-3, Safari, Chrome)
- Built on .NET DataProviders for future support of other databases
- Uses MooTools for all clientside scripting
- Integrated FCKEditor for user-friendly content editing
- Supports friendly Urls
- Provides an API for development of the frontend

Future
TechSite's future development relies on the needs of my customers.
The CMS is provided for free and the customer pays only for the implementation and for the development of custom features.
So as the usage of TechSite expands, the possiblities grow with it.

A few features that i expect to see in the future:
- PHP connector to enable linux-based customers to use TechSite for their website
- More advanced File Explorer
- Out-of-the-box implementations
- Multi-language support

Demo
There is an online demo of the backend available here: http://techsite.dottech.nl/techsite/default.aspx.
All the save actions (such as adding, updating, (re)moving) have been disabled for the demo!
The demo comes with a simple (unfinished) website which is available here.

EDIT: Demo is temporarily offline due

Last words
Like i said before, TechSite is a steady base for a CMS, but it's not yet a final product so keep that in mind while checking out the demo.
I will keep track of TechSite's development here on my blog.
Feel free to leave any comments or questions you have about TechSite here.

If you would like to use TechSite for your own website, you can contact me by email.

/Ruud

Wednesday, July 29, 2009

JavaScript TreeView component using MooTools library

Some time ago i wrote this TreeView component using the MooTools javascript library.
As far as i know there are not many treeviews around for MooTools, so i decided to put it up for grabs here.

Key Features:
- Load tree data from JSON file
- Load child nodes on demand using AJAX
- Select multiple nodes

View the demo here.
Download DotTech Tree v1.0.1: dottech.tree-1.0.1.zip.

UPDATE: Unfortunately the code is not available at the moment (i lost it and didnt have time to search for it yet)

/Ruud

Tuesday, July 28, 2009

PHP var_dump() method for C#

In PHP there is the var_dump() and print_r() function that displays the contents of an object.
Sometimes i miss this functionality in ASP.NET, especially when you are working with large objects and don't want to step into your code every time.
I came up with this method to list all the properties of a given object by name and value.
It also lists any child properties recursively, until it reaches a certain level of recursion (in this case it stops after 5 recursions).

using System;
using System.Text;
using System.Reflection;
using System.Collections;

public string var_dump(object obj, int recursion)
{
StringBuilder result = new StringBuilder();

// Protect the method against endless recursion
if (recursion < 5)
{
// Determine object type
Type t = obj.GetType();

// Get array with properties for this object
PropertyInfo[] properties = t.GetProperties();

foreach (PropertyInfo property in properties)
{
try
{
// Get the property value
object value = property.GetValue(obj, null);

// Create indenting string to put in front of properties of a deeper level
// We'll need this when we display the property name and value
string indent = String.Empty;
string spaces = "| ";
string trail = "|...";

if (recursion > 0)
{
indent = new StringBuilder(trail).Insert(0, spaces, recursion - 1).ToString();
}

if (value != null)
{
// If the value is a string, add quotation marks
string displayValue = value.ToString();
if (value is string) displayValue = String.Concat('"', displayValue, '"');

// Add property name and value to return string
result.AppendFormat("{0}{1} = {2}\n", indent, property.Name, displayValue);

try
{
if (!(value is ICollection))
{
// Call var_dump() again to list child properties
// This throws an exception if the current property value
// is of an unsupported type (eg. it has not properties)
result.Append(var_dump(value, recursion + 1));
}
else
{
// 2009-07-29: added support for collections
// The value is a collection (eg. it's an arraylist or generic list)
// so loop through its elements and dump their properties
int elementCount = 0;
foreach (object element in ((ICollection)value))
{
string elementName = String.Format("{0}[{1}]", property.Name, elementCount);
indent = new StringBuilder(trail).Insert(0, spaces, recursion).ToString();

// Display the collection element name and type
result.AppendFormat("{0}{1} = {2}\n", indent, elementName, element.ToString());

// Display the child properties
result.Append(var_dump(element, recursion + 2));
elementCount++;
}

result.Append(var_dump(value, recursion + 1));
}
}
catch { }
}
else
{
// Add empty (null) property to return string
result.AppendFormat("{0}{1} = {2}\n", indent, property.Name, "null");
}
}
catch
{
// Some properties will throw an exception on property.GetValue()
// I don't know exactly why this happens, so for now i will ignore them...
}
}
}

return result.ToString();
}

For my example i used an object called Category, but this can be an instance of any class.
Category has a few basic properties and one called Parent which holds another Category object (so we have child properties).
I call the method like this:

Category category = LoadCategory(123);
Response.Write(var_dump(myObject, 0)); // Always start at recursion 0,
// you might want to add an override
// that sets this argument by default

The output of this example is:

CategoryId = 685
ParentId = 287
Name = "Beans"
Description = ""
Parent = MyProject.Data.Category
|...CategoryId = 287
|...ParentId = 174
|...Name = "Cheap food"
|...Description = ""
|...Parent = MyProject.Data.Category
| |...CategoryId = 174
| |...ParentId = 173
| |...Name = "Food"
| |...Description = ""
| |...Parent = MyProject.Data.Category
| | |...CategoryId = 173
| | |...ParentId = 0
| | |...Name = "Things to eat"
| | |...Description = ""
| | |...Parent = null
| | |...Count = 0
| |...Count = 0
|...Count = 13
Count = 0
TestList = System.Collections.Generic.List`1[MyProject.Data.Category]
|...TestList[0] = MyProject.Data.Category
| |...CategoryId = 1
| |...ParentId = 0
| |...Name = "Bla"
| |...Description = ""
| |...Count = 0
|...Count = 1

It's not exactly PHP's var_dump() method, but it works for me! :)
I might expand it some day so it dumps array/list elements too and maybe add some XHTML formatting.

Update on 29-07-2009:
Added support for collection properties.

/Ruud