All the stuff that bothers software developer in his everyday tasks.
Dec 18, 2008
Telerik RadSkinManager doesn't persist the Skin.
If you programatically change the Telerik RadSkinManager Skin property it won't get persisted in the key you added.
This is because probably in telerik asumed if there is no skin chooser the skins won't change and will be loaded from the markup. It is not a bad decision.
However, you may find yourself in need to programatically change the skin and want it persisted.
To do the things tidy I did a small code to persist the skin where it should be persisted.
Here is the code:
switch (rsMgr.PersistenceMode)
{
case RadSkinManagerPersistenceMode.Cookie:
// Create a cookie to persist the skin selection for the session only:
HttpCookie cookieSkin = new HttpCookie(rsMgr.PersistenceKey, rsMgr.Skin);
Response.Cookies.Add(cookieSkin);
break;
case RadSkinManagerPersistenceMode.Session:
// Create a session variable with the same name:
Session[rsMgr.PersistenceKey] = rsMgr.Skin;
break;
case RadSkinManagerPersistenceMode.ViewState:
// View state variable:
ViewState[rsMgr.PersistenceKey] = rsMgr.Skin;
break;
}
where rsMgr is RadSkinManager.
Now you may paste this code in a method and call this method after you programatically assign skin to the manager. I needed this because I wanted to allow the user to change from some of the skins (not all of them) I couldn't find a way to only hide few skins and display others so I can use the standard functionality of the SkinChooser proerty so I added my own RadCombobox with the skins I want displayed.
Hope this helps someone out there...
Dec 14, 2008
Nice little tool to help me with twitter.
I created a small twitter software what it does is to check each hour if I am listening to Winamp, get the song if possible and write it in twitter for me and the people who are eventually interested in what I am listening.
Here is the deal:

You can download it from here:
TWamp - Nice little twitter software
You can follow me on twitter from the following url:
My twitter profile
Please note: TWamp isn't very user friendly. You need to get along with it in order to use it ;).
Here is the deal:
You can download it from here:
TWamp - Nice little twitter software
You can follow me on twitter from the following url:
My twitter profile
Please note: TWamp isn't very user friendly. You need to get along with it in order to use it ;).
Dec 2, 2008
Understanding the recursion.
Here is the golden rule to understand the recursion:
"In order to understand recursion one must first understand recursion."
"In order to understand recursion one must first understand recursion."
Dec 1, 2008
Microsoft Office Word automation in C# - How to add table to the document?
The following C# code will create a new document, add a table to it and ask the user to save it. Document will look like this:

The following code will add a table in word and then ask the user to provide a filename to save the document:
Microsoft.Office.Interop.Word.Application app = new Microsoft.Office.Interop.Word.ApplicationClass();
app.Visible = false;
object start = 0;
object end = 0;
object oNull = System.Reflection.Missing.Value;
Document doc = new DocumentClass();
doc = app.Documents.Add(ref oNull, ref oNull, ref oNull, ref oNull);
Table tbl = doc.Tables.Add(doc.Range(ref start, ref end), 10, 2, ref oNull, ref oNull);
Random rnd = new Random();
for (int i = 0; i < 10; i++)
{
tbl.Rows[i + 1].Cells[1].Range.Text = "Run# :" + ((int)i + 1).ToString();
tbl.Rows[i + 1].Cells[2].Range.Text = "Value :" + rnd.Next(0, 2000).ToString();
}
object oFalse = false;
app.Visible = true;
try
{
doc.Save();
}
catch (Exception ex)
{
if (ex.Message.ToLower().IndexOf("command failed") == -1)
{
throw ex;
}
}
app.Quit(ref oFalse, ref oFalse, ref oFalse);
What we done is to create a new document, a new table, and fill the table with random values.
Seems very easy but not quite sure how well document :).
The following code will add a table in word and then ask the user to provide a filename to save the document:
Microsoft.Office.Interop.Word.Application app = new Microsoft.Office.Interop.Word.ApplicationClass();
app.Visible = false;
object start = 0;
object end = 0;
object oNull = System.Reflection.Missing.Value;
Document doc = new DocumentClass();
doc = app.Documents.Add(ref oNull, ref oNull, ref oNull, ref oNull);
Table tbl = doc.Tables.Add(doc.Range(ref start, ref end), 10, 2, ref oNull, ref oNull);
Random rnd = new Random();
for (int i = 0; i < 10; i++)
{
tbl.Rows[i + 1].Cells[1].Range.Text = "Run# :" + ((int)i + 1).ToString();
tbl.Rows[i + 1].Cells[2].Range.Text = "Value :" + rnd.Next(0, 2000).ToString();
}
object oFalse = false;
app.Visible = true;
try
{
doc.Save();
}
catch (Exception ex)
{
if (ex.Message.ToLower().IndexOf("command failed") == -1)
{
throw ex;
}
}
app.Quit(ref oFalse, ref oFalse, ref oFalse);
What we done is to create a new document, a new table, and fill the table with random values.
Seems very easy but not quite sure how well document :).
Етикети:
C#,
Software Development,
Windows Forms
Nov 25, 2008
ASP.NET ProgressBar to show percentage
I did this today during my lunch time break: (sorry about the bad quality but couldn't figure out how to ask YouTube not to resize |
It is ugly and unoptimized yet but I hope I will be able to refactor it soon and make it as a user control.
Another post to follow when this happens.
Nov 20, 2008
Cannot have multiple items selected in a DropDownList. Why is this ASP.NET / C# exception rised?
This is a common exception. It happens when you do something like:
ListItem li1 = new ListItem();
li1.Text = "Item 1";
li1.Value = "id1";
li1.Selected = true;
ListItem li2 = new ListItem();
li2.Text = "Item 2";
li2.Value = "id2";
li2.Selected = true;
ddTest.Items.Add(li1);
ddTest.Items.Add(li2);
Let's explain what is going on.
We created a ListItem, set its name and value and make it to be selected.
Then we created another ListItem, again set its value and name and set it to be selected.
ListItem li1 = new ListItem();
li1.Text = "Item 1";
li1.Value = "id1";
li1.Selected = true;
ListItem li2 = new ListItem();
li2.Text = "Item 2";
li2.Value = "id2";
li2.Selected = true;
lb1.SelectionMode = ListSelectionMode.Multiple;
lb1.Items.Add(li1);
lb1.Items.Add(li2);
We will run with no errors and both items will be selected. The problem with the DropDownList control is that shares almost the same functionality with the ListBox and for that reason they both inherit the same base objects.
But the DropDownList doesn't have the ability to display multiple items so ASP.NET team decided to throw an exception when such situation occurs.
You can use DropdownList.SelectedIndex or DropdownList.SelectedValue properties to mark selected item in a safe manner. So if in the firs example we wanted to select the item with id2 we can use the following code:
ListItem li1 = new ListItem();
li1.Text = "Item 1";
li1.Value = "id1";
ListItem li2 = new ListItem();
li2.Text = "Item 2";
li2.Value = "id2";
ddTest.Items.Add(li1);
ddTest.Items.Add(li2);
ddTest.SelectedValue = "id2";
I commonly use this as in most cases I know which value should I select but don't know which index it has.
Now, there is a situation in which you may want to select by index and this in my imagination is the following situation:
Imagine you have the above DropDownList but you want it to be optional. This means that you need to have an item with empty value or value that means "null" to you. Imagine that this value is already inserted in the DropDownList. You know it will always be the first item. Here is the snippet:
ListItem liNull = new ListItem();
liNull.Text = "-- Please Select an Item --";
liNull.Value = "";
ListItem li1 = new ListItem();
li1.Text = "Item 1";
li1.Value = "id1";
ListItem li2 = new ListItem();
li2.Text = "Item 2";
li2.Value = "id2";
// Someone selected item in the code:
ddTest.SelectedValue = "id1";
ddTest.Items.Add(liNull);
ddTest.Items.Add(li1);
ddTest.Items.Add(li2);
// We will select the first one which is "-- Please Select an Item --"
ddTest.SelectedIndex = 0;
But in such cases we can take advantage of the default DropDownList behaviour (the DropDownList will select the first item if there are no items selected explicitly). So if you need the first item selected you can simply clear the selection and ASP.NET will select it for you. But how?
By using the ClearSelection() method. It does what it says - it clears the selected item.
Here is the last snippet:
ListItem liNull = new ListItem();
liNull.Text = "-- Please Select an Item --";
liNull.Value = "";
ListItem li1 = new ListItem();
li1.Text = "Item 1";
li1.Value = "id1";
ListItem li2 = new ListItem();
li2.Text = "Item 2";
li2.Value = "id2";
// Someone selected item in the code:
ddTest.SelectedValue = "id1";
ddTest.Items.Add(liNull);
ddTest.Items.Add(li1);
ddTest.Items.Add(li2);
// We will be sure that everything is clean
// and will expect ASP.NET to select the first item
// by default:
ddTest.ClearSelection();
from work for about a month and need to do some extra work to catch my collegues), some ongoing projects I was stupid enough to take and so on...
However, I've found some time to start two new blogs which I consider more as experiment than real blogs:
Sql Exceptions
and :
.NET Exceptions
Both blogs currently contain about 40 posts with Sql and .NET Exceptions which you may find helpful after time. I am saying after time as I plan to automate those blogs so the information there is posted by software and not by myself.
Also users are welcome to post comments. Soon I will publish special format of posts which you can use in order to give your opinion on specific exception and this exception will be automatically published in the post.
Unfortunatelly there is a limitation - Blogger allow me to only publish about 40 posts daily so I wasn't able to create posts about all the exceptions in SQL and .NET Framework.
I will batch post each day (may miss some of the days like weekends for example ;) so in few weeks both blogs will be up to date.
awesome, you pointed me in the right direction." or "Dude, you saved me a lot of hours" and so on. There are a lot of things I would like to learn about asp.net and I think this forum is a great place to start. Just post a question and in most cases in few minutes some of the experts there will answer you.
Here is a screenshot I will keep close to my heart :D
/> b.Save(@"filename.jpg", System.Drawing.Imaging.ImageFormat.Jpeg);
You will also need to add the PrintWindow function (it is windows API function):
[DllImport("user32.dll")]
private static extern bool PrintWindow(IntPtr hwnd, IntPtr hdcBlt,
uint nFlags);
Not that hard, but not well documented. If you don't know how to get a pointer to a running Internet Explorer class, you can do the following:
1. Add reference to ShDocVw (it is in the COM tab and it should be named "Microsoft Objects Automation library" or something like this)
2. Add the following code:
SHDocVw.ShellWindowsClass windows = new ShellWindowsClass();
foreach (SHDocVw.InternetExplorer explorer in windows)
{
if (explorer.LocationURL == string.Empty)
{
// this is our guy!
ie = explorer;
}
}
NOTE: please be sure to use your own if statement. This one will get an instance to the last found Internet explorer which has an empty string as Location.
Happy C# programming!
the timeOutID (required to clear the timeout).
We have a target function which we want to call in let's say 2 seconds. But we want to pass some parameters to it (for example the sender of the event).
What we do is to create another function (myButtonToTimeOut) in the function body we call the setTimeOut, and pass as parameter a new function which contains our desired call:
function(){onTimeOut(id);}
Voilla. The other things (such as the global variable t) are here only to make this thing work. If you want to test this snippet simply add it to the head of an html page, add few buttons and set their onclick as this one:
onclick="myButtonToTimeOut(this.id);"
When you click on the button, after two seconds you should receive an alert showing you which button was pressed.
Please note: As the code was intended to only show you how to call setTimeOut with parameters, it may have some bugs in it (for example I am not quite sure what will happen if you click two times quickly on the button, or on two diferrent buttons, as t is holding the timeOutId it may get overriden and as a result, some of the alerts may continue to appear).
Have a nice programming!
>
This is the variable which is declared automatically when you create new instance. I suggest you to put it into the exec method of the AddIn:
public void Exec(string commandName, vsCommandExecOption executeOption, ref object varIn, ref object varOut, ref bool handled)
{
_applicationObject.Debugger.Go(false);
SHDocVw.ShellWindowsClass windows = new ShellWindowsClass();
foreach (SHDocVw.InternetExplorer explorer in windows)
{
if (explorer.LocationURL == string.Empty)
{
// this is our guy!
ie = explorer;
}
}
}
You also need to add reference to ShDocVw (Microsoft Shell And Automation Library).
Enjoy!
exactly what Touchless does. It captures an info from your camera and if it finds something that is known to be marker - it raises events, to which you can subscribe and do something.
The better news is that Touchless is Open Source project and can be obtained from CodePlex for free.
You can also whach a video on Touchless:
I downloaded this SDK and in less than a minute I made a small program which let's you move your cursor with fingers (I still can't find a good enough way to left and right click ;).
I hope I will have enough time this week to post this simple project so you can get deeper with Touchless as it seems promising technology to me.
Limitations:
Well every good thing has drawbacks. Don't get it wrong. Touchless isn't the standard in this area. It has problems (however I think after it is open source a lot of people can work on it and improve it).
So what are the limitations?
First of all - Touchless is very very very sensitive to light and to colors. It is because the way it works. In order to work, you need to specify a "marker". Marker is the thing the program looks for. So if you have a red tape on your finger and define it as marker, you will be able to command your computer with it. But if there is a object with the same color on the screen and this object is about the same size, it may be found as another marker.
The second problem (at least for the sample project I did) is that most web cameras are not sensitive enough. They are (most of them offcourse) with 640 x 480 pixels resolution. If you are about to move your cursor and your screen resolutions is 1280 x 1024 you will be only able to move the cursor 640 pixels horizontally and 480 pixels vertically (this can be software corrected by moving the cursor 3 or 4 pixels on each pixel that comes from the camera but for sensitive operations (resizing, drawing) it will not be good enough.
However I think the things above will be resolved and we will have another great way to use our computers for almost no extra charge.
I do really wish those guys luck and I will definatelly watch how this project goes and even if I can I will help a bit.
I really fell in love with this toy!
>
write html in WebBrowserControl with C#:
string strHtml = "you html here";
wb.Navigate("about:" + strHtml);
// Second way to write html in WebBrowserControl with C#:
wb.Navigate("about:blank");
wb.Document.Write(strHtml);
// Third way to write html in WebBrowserControl with C#:
const string strAddress = "test.html";
using (StreamWriter sw = new StreamWriter(strAddress))
{
sw.Write(strHtml);
} wb.Navigate("file://" + Application.StartupPath + "\\" + strAddress);
style="" attribute for each row / cell (not quite sure about the exact rules). And it will generate repeating markup, increasing the size of the page and respectivelly - your bandwidth.
I did a small snipet to fix this (not the best solution again but should be kind of starting point).
Here is my code:
protected override void Render(HtmlTextWriter writer)
{
System.IO.StringWriter stringWriter = new System.IO.StringWriter();
HtmlTextWriter htmlWriter = new HtmlTextWriter(stringWriter);
this.EnsureChildControls();
base.Render(htmlWriter);
string html = stringWriter.ToString();
AnalyzeStyles(html);
html = RepairStyles(html);
writer.Write(html);
}
private void AnalyzeStyles(string html)
{
MatchCollection CSSMatch = Regex.Matches(html, "style=[\"].+?[\"]", RegexOptions.IgnoreCase);
foreach (Match mCss in CSSMatch)
{
if (htDuplicates.ContainsKey(mCss.Value))
{
htDuplicates[mCss.Value] = Convert.ToInt32(htDuplicates[mCss.Value]) + 1;
}
else
{
htDuplicates.Add(mCss.Value, 0);
}
}
}
private string RepairStyles(string html)
{
int classID = 0;
int pos;
IDictionaryEnumerator iOccurences = htDuplicates.GetEnumerator();
this.CSS += "";
InformaticsWeb.Pages.Optimized master = (InformaticsWeb.Pages.Optimized)this.Master;
pos = Regex.Match(html, "", RegexOptions.IgnoreCase | RegexOptions.Singleline).Index + "".Length;
html = html.Insert(pos, CSS);
return html;
}
Please note : AnalyzeStyles adds each of the style="" found on the page (each unique). If it finds secound and third and so on - it increases a counter. The counter is not currently used, but may be later used to decide which of the styles should be converted to CSS classes.
So this code basically takes the page and moves all the style="" attributes in the head section as a CSS classes. I tested and my grid view seems as beautiful as before this code was applied.
Now, does it worth to add this logic?
Well I think you can achieve the same functionality by using Skin files. I am adding this more for reference.
I also did a small excel diagram to show you how much bytes are saved based on the count of the items in the GridView:

Please note that the htDupplicates is a Hashtable, declared as a global variable, so you will need to add it if you want to use this code.
Let me now explain the columns in the excel file shown above.
The “Columns” column displays how much columns does the GridView render. Typically the columns are rendered as a table cells and doesn’t contain any style=”” attributes (at least I couldn’t see any), so this is something you can’t affect. The thing that this optimization affects is the number of rows in your gridview. The more rows you have the more bytes you will get.
The second column displays the number of rows in the grid view.
The third column is the optimized size of the gridview (when the above technique is applied).
The “Size Original” column displays the size for unoptimized page (the same page!).
And the last column shows you the difference before and after.
You can see it in the diagram - for 20 items you have about 842 bytes difference. While for 80 you have about 3,512 (I don’t think there is a live site which displays 80 items at once in a grid view ;).
of a series of links, all the links will change their css class to "visited:" css class (because the browser sees you already have visited the "#" address).
Conclusion : You can apply the above technique but it will not help you much and I think it involves to much efforts for a small effect (few bytes). If you really want to get this benefit you can replace the "javascript:__doPostBack" with "javascript:_dp" and you will get less bytes than if removing the "javascript:" part but the page will work as expected.
I am currently working on other techniques to cut more of the ASP page markup, but they are a bit more serious. I hope I will write another post soon to inform you how it is going.
will win more and more bytes.
So each time we cut the name of something, we win few bytes.
The next question is what can we cut in order to optimize our page?
What is the thing that repeats in each web control?
The answer is the "__doPostBack" function. I tried to replace it during the Rendering of the page and was able to cut a bit of the page size, while keeping the source relatively clean of errors (please note the word "relatively").
Here is a sample code:
protected override void Render(HtmlTextWriter writer)
{
System.IO.StringWriter stringWriter = new System.IO.StringWriter();
HtmlTextWriter htmlWriter = new HtmlTextWriter(stringWriter);
base.Render(htmlWriter);
string html = stringWriter.ToString();
html = html.Replace("\"javascript:__doPostBack", "\"__dpb");
writer.Write(html);
}
I had some issues I haven't yet identified, as I was in a rush to post this as it seems to me a brand new way to optimize pages - to look for repeating elements and cut their names... (I will be happy if there are volunteers to help with this one ;)...
Other things : DoPostBackWithOptions should also be replaced by dpbw for example, this will be done in the future, after I clean the _doPostBack as it still have few problems.
And some more things - we may consider optimizing some of the ASP.NET controls which are known to be "markup unoptimized" like the treeview, gridview for example (At least I think there may be some things in them to optimize).
Any comments are welcome.
style="color:Black;"> Promote(User usr)
{
usr.Occupation = "Chief Officer";
}
}
public class User
{
private string strOccupation;
public User() { }
public string Occupation
{
get { return this.strOccupation; }
set { this.strOccupation = value; }
}
}
}
Here, after the program is executed the Local manager will promote the user and the output will be : After local promotion: Chief Officer
Now imagine that we want to have the name of the manager who promoted the User, so we can store it in a database. Obviously we need to have an instance of the Manager class, and write the information in the database, prior changing the occupation for the user.
We will want to have a method in the User class, which takes the Manager instance, writes everything needed in the database and then changes the Occupation.
But we can't be sure that all developers will use the method and not the property directly.
Firs let's add a property to the LocalManager class to hold the name of the manager. Then I will create a method to change users occupation, which will take an instance of LocalManager. This will be the only way an external class to change the occupation of a user. After this, we will slightly modificate the code in the main program so everything is called properly. Here is the code:
using System;
using System.Collections.Generic;
using System.Text;
namespace Locals
{
class Program
{
static void Main(string[] args)
{
LocalManager mgr = new LocalManager();
mgr.ManagerName = "Pavel Donchev";
User usr = new User();
mgr.Promote(usr);
Console.WriteLine("After promotion: " + usr.Occupation);
}
}
public class LocalManager
{
private string strManagerName = string.Empty;
public LocalManager() { }
public void Promote(User usr)
{
usr.Promote(this, "Chief Officer");
}
public string ManagerName
{
get { return this.strManagerName; }
set { this.strManagerName = value; }
}
}
public class User
{
private string strOccupation;
public User() { }
public string Occupation
{
get { return this.strOccupation; }
private set { this.strOccupation = value; }
}
public void Promote(LocalManager manager, string Occupation)
{
if (null != manager && !string.IsNullOrEmpty(manager.ManagerName))
{
// Do additional work here, for example write the
// name of the manager in the database amoung with
// time stamp of the promotion to have audit...
this.Occupation = Occupation;
}
else
{
throw new Exception("A valid manager instance and occupation should be passed!");
}
}
}
}
Now our classes are ready. You can give your user class away and be sure that no one can modify the property without passing a valid manager instance (actually the sequence of exceptions will guide your peers to follow the correct logic ;).
Oh, one more thing - we didn't proof that no one can assign the User.Occupation property directly. Well try to do so, you should receive compiler error message:
The property or indexer 'Locals.User.Occupation' cannot be used in this context because the set accessor is inaccessible
ListItem li1 = new ListItem();
li1.Text = "Item 1";
li1.Value = "id1";
li1.Selected = true;
ListItem li2 = new ListItem();
li2.Text = "Item 2";
li2.Value = "id2";
li2.Selected = true;
ddTest.Items.Add(li1);
ddTest.Items.Add(li2);
Let's explain what is going on.
We created a ListItem, set its name and value and make it to be selected.
Then we created another ListItem, again set its value and name and set it to be selected.
When we add both ListItems the DropDownList confuses about which one should be selected and throws an exception. But why? Because there is another control - ListBox, which allows multiple selection. If we create a ListBox on the form and add the following code in the code behind: |
ListItem li1 = new ListItem();
li1.Text = "Item 1";
li1.Value = "id1";
li1.Selected = true;
ListItem li2 = new ListItem();
li2.Text = "Item 2";
li2.Value = "id2";
li2.Selected = true;
lb1.SelectionMode = ListSelectionMode.Multiple;
lb1.Items.Add(li1);
lb1.Items.Add(li2);
We will run with no errors and both items will be selected. The problem with the DropDownList control is that shares almost the same functionality with the ListBox and for that reason they both inherit the same base objects.
But the DropDownList doesn't have the ability to display multiple items so ASP.NET team decided to throw an exception when such situation occurs.
This can be confusing in more complicated code, but it is definatelly better than selecting the last item which was marked as "selected" or the first one or something like that. Luckily there are safer ways to select an item without having to worry if there is already selected item or not. |
You can use DropdownList.SelectedIndex or DropdownList.SelectedValue properties to mark selected item in a safe manner. So if in the firs example we wanted to select the item with id2 we can use the following code:
ListItem li1 = new ListItem();
li1.Text = "Item 1";
li1.Value = "id1";
ListItem li2 = new ListItem();
li2.Text = "Item 2";
li2.Value = "id2";
ddTest.Items.Add(li1);
ddTest.Items.Add(li2);
ddTest.SelectedValue = "id2";
I commonly use this as in most cases I know which value should I select but don't know which index it has.
Now, there is a situation in which you may want to select by index and this in my imagination is the following situation:
Imagine you have the above DropDownList but you want it to be optional. This means that you need to have an item with empty value or value that means "null" to you. Imagine that this value is already inserted in the DropDownList. You know it will always be the first item. Here is the snippet:
ListItem liNull = new ListItem();
liNull.Text = "-- Please Select an Item --";
liNull.Value = "";
ListItem li1 = new ListItem();
li1.Text = "Item 1";
li1.Value = "id1";
ListItem li2 = new ListItem();
li2.Text = "Item 2";
li2.Value = "id2";
// Someone selected item in the code:
ddTest.SelectedValue = "id1";
ddTest.Items.Add(liNull);
ddTest.Items.Add(li1);
ddTest.Items.Add(li2);
// We will select the first one which is "-- Please Select an Item --"
ddTest.SelectedIndex = 0;
But in such cases we can take advantage of the default DropDownList behaviour (the DropDownList will select the first item if there are no items selected explicitly). So if you need the first item selected you can simply clear the selection and ASP.NET will select it for you. But how?
By using the ClearSelection() method. It does what it says - it clears the selected item.
Here is the last snippet:
ListItem liNull = new ListItem();
liNull.Text = "-- Please Select an Item --";
liNull.Value = "";
ListItem li1 = new ListItem();
li1.Text = "Item 1";
li1.Value = "id1";
ListItem li2 = new ListItem();
li2.Text = "Item 2";
li2.Value = "id2";
// Someone selected item in the code:
ddTest.SelectedValue = "id1";
ddTest.Items.Add(liNull);
ddTest.Items.Add(li1);
ddTest.Items.Add(li2);
// We will be sure that everything is clean
// and will expect ASP.NET to select the first item
// by default:
ddTest.ClearSelection();
Nov 14, 2008
Two new automated blogs
I've been very busy this month. All the exams (for microsoft certification, in the faculty and so on), my extended work day (from 9 to 20 as I was absent |
However, I've found some time to start two new blogs which I consider more as experiment than real blogs:
Sql Exceptions
and :
.NET Exceptions
Both blogs currently contain about 40 posts with Sql and .NET Exceptions which you may find helpful after time. I am saying after time as I plan to automate those blogs so the information there is posted by software and not by myself.
Also users are welcome to post comments. Soon I will publish special format of posts which you can use in order to give your opinion on specific exception and this exception will be automatically published in the post.
Unfortunatelly there is a limitation - Blogger allow me to only publish about 40 posts daily so I wasn't able to create posts about all the exceptions in SQL and .NET Framework.
I will batch post each day (may miss some of the days like weekends for example ;) so in few weeks both blogs will be up to date.
Nov 5, 2008
On the asp.net official site for the very first time!
Well, a lot of people don't consider showing someone on the official asp.net site a big deal. There is a box "Community recognition program" where the most active members as well as yesterday's most active members are shown. I had 102 points for the previous day so I appeared. It really isn't big deal, but I consider it a big start, because it gave me motivation to continue to contribute. It is not about the recognition. In asp.net site you can find a lot of friends also. It is great to help someone and then see something like : "Dude, you're |
Here is a screenshot I will keep close to my heart :D
Oct 27, 2008
C# - How to take a screenshot of Internet Explorer
Asuming you have InternetExplorerClass instance, named ie, you can do the following to obtain screenshot: int screenWidth = ie.Width; int screenHeight = ie.Height; #region Get IE Bitmap Bitmap b = new Bitmap(ie.Width, ie.Height); Graphics g = Graphics.FromImage(b); IntPtr hdc = g.GetHdc(); bool result = PrintWindow((IntPtr)ie.HWND, hdc, 0); g.ReleaseHdc(); g.Flush(); |
You will also need to add the PrintWindow function (it is windows API function):
[DllImport("user32.dll")]
private static extern bool PrintWindow(IntPtr hwnd, IntPtr hdcBlt,
uint nFlags);
Not that hard, but not well documented. If you don't know how to get a pointer to a running Internet Explorer class, you can do the following:
1. Add reference to ShDocVw (it is in the COM tab and it should be named "Microsoft Objects Automation library" or something like this)
2. Add the following code:
SHDocVw.ShellWindowsClass windows = new ShellWindowsClass();
foreach (SHDocVw.InternetExplorer explorer in windows)
{
if (explorer.LocationURL == string.Empty)
{
// this is our guy!
ie = explorer;
}
}
NOTE: please be sure to use your own if statement. This one will get an instance to the last found Internet explorer which has an empty string as Location.
Happy C# programming!
JavaScript Call SetTimeout or other function with parameters.
I needed to do this few days ago. I struggled to find out how. Hope this will help to other guys in the same situation (it's so simple that you may never figure it out until someone tell you :D ): var t; function myButtonToTimeOut(id) { // We will call the onTimeOut function in a setTimeOut() // and will pass the id as a parameter: t = setTimeout(function(){onTimeOut(id);}, 2000); } function onTimeOut(id) { alert('The caller with ' + id + ' was clicked 2 seconds ago.'); clearTimeout(t); } what do we do here? Well, we have a global variable which will hold |
We have a target function which we want to call in let's say 2 seconds. But we want to pass some parameters to it (for example the sender of the event).
What we do is to create another function (myButtonToTimeOut) in the function body we call the setTimeOut, and pass as parameter a new function which contains our desired call:
function(){onTimeOut(id);}
Voilla. The other things (such as the global variable t) are here only to make this thing work. If you want to test this snippet simply add it to the head of an html page, add few buttons and set their onclick as this one:
onclick="myButtonToTimeOut(this.id);"
When you click on the button, after two seconds you should receive an alert showing you which button was pressed.
Please note: As the code was intended to only show you how to call setTimeOut with parameters, it may have some bugs in it (for example I am not quite sure what will happen if you click two times quickly on the button, or on two diferrent buttons, as t is holding the timeOutId it may get overriden and as a result, some of the alerts may continue to appear).
Have a nice programming!
Oct 24, 2008
Nice game for software developers :)
Some of you may remember the CRobots game. It is a game in which you program your own robot (in C) and put it to fight against other robots. This game is available in 3D variant and I think it may be very userful to improve your programming skills. Try it from here: http://antru.ru/crobots3d/ I also built my own robot, I named it Kamikadze because all it does is to spin around and shout itself :D Documentation can be found here: http://crobots.deepthought.it/html/manual.html#8 Happy playing! |
Oct 21, 2008
C# AddIn - Start Debugging and get the running Internet Explorer instance.
I needed to do this (actually I wanted). I was curious if you can obtain an instance of a Internet Explorer which was started in debugging session. Here is a snipet to do this: _applicationObject.Debugger.Go(false); SHDocVw.ShellWindowsClass windows = new ShellWindowsClass(); foreach (SHDocVw.InternetExplorer explorer in windows) { if (explorer.LocationURL == string.Empty) { // this is our guy! ie = explorer; } } Note : this snipet should be added somewhere where you have access to the _applicationObject. |
public void Exec(string commandName, vsCommandExecOption executeOption, ref object varIn, ref object varOut, ref bool handled)
{
_applicationObject.Debugger.Go(false);
SHDocVw.ShellWindowsClass windows = new ShellWindowsClass();
foreach (SHDocVw.InternetExplorer explorer in windows)
{
if (explorer.LocationURL == string.Empty)
{
// this is our guy!
ie = explorer;
}
}
}
You also need to add reference to ShDocVw (Microsoft Shell And Automation Library).
Enjoy!
Етикети:
.NET,
.NET C# technologies,
C#,
Development,
ShDocVw,
Software Development,
Visual Studio
Oct 19, 2008
Touchless SDK : Very interesting and promising technology each of you guys should play with :)
I came on this yesterday, I was bored because all the projects I am working on are to some degree "standard". No dev chalenge. I wanted to create, to do something interesting. So I started to browse CodePlex and found this SDK. Overview : Touchless SDK is a software development kit to help developers create applications which can be controlled without the standard peripheral devices (mouse, keyboard and so on). It enable you to create a applications which are controlled without the need to touch anything at all, just gestures in the air. How is this done? Well, I think there was a lot of research on this topic. We already have programs to detect motion from your video camera, why not try to extract information from those motions? This is |
The better news is that Touchless is Open Source project and can be obtained from CodePlex for free.
You can also whach a video on Touchless:
I downloaded this SDK and in less than a minute I made a small program which let's you move your cursor with fingers (I still can't find a good enough way to left and right click ;).
I hope I will have enough time this week to post this simple project so you can get deeper with Touchless as it seems promising technology to me.
Limitations:
Well every good thing has drawbacks. Don't get it wrong. Touchless isn't the standard in this area. It has problems (however I think after it is open source a lot of people can work on it and improve it).
So what are the limitations?
First of all - Touchless is very very very sensitive to light and to colors. It is because the way it works. In order to work, you need to specify a "marker". Marker is the thing the program looks for. So if you have a red tape on your finger and define it as marker, you will be able to command your computer with it. But if there is a object with the same color on the screen and this object is about the same size, it may be found as another marker.
The second problem (at least for the sample project I did) is that most web cameras are not sensitive enough. They are (most of them offcourse) with 640 x 480 pixels resolution. If you are about to move your cursor and your screen resolutions is 1280 x 1024 you will be only able to move the cursor 640 pixels horizontally and 480 pixels vertically (this can be software corrected by moving the cursor 3 or 4 pixels on each pixel that comes from the camera but for sensitive operations (resizing, drawing) it will not be good enough.
However I think the things above will be resolved and we will have another great way to use our computers for almost no extra charge.
I do really wish those guys luck and I will definatelly watch how this project goes and even if I can I will help a bit.
I really fell in love with this toy!
Oct 16, 2008
C# - Web Browser Control - Load String in Web Browser control (4th way).
Here is one more way to load string in Web Browser Control (C#). This is in case you are using the managed control. // Fourth way to write html in WebBrowserControl with C#: wb.DocumentText = strHtml; I can tell you (just guessing) that this will be the best one as it became available in the managed control (at least I didn't found it in the old COM versions). That is why I think it was reviewed and probably optimized. |
C# - Web Browser Control - Load String in Web Browser control.
I was thinking about this long time ago. I recently found this post: http://www.xtremevbtalk.com/showthread.php?t=167531 So how to load a string in WebBrowser Control with C#? First - navigate to "about:blank" (as the web browser needs a document to operate on) Then use WebBrowser.Document.Write(string text) to write the string you want to load in the WebBrowser control. Kind of tricky but ... Another way is to write something like: about:your html here And the last one is to write the document on the hard disk with StreamWriter for example, and then to navigate to it. Here is a code to show you all methods discussed: WebBrowser wb = new WebBrowser(); // First way to |
string strHtml = "you html here";
wb.Navigate("about:" + strHtml);
// Second way to write html in WebBrowserControl with C#:
wb.Navigate("about:blank");
wb.Document.Write(strHtml);
// Third way to write html in WebBrowserControl with C#:
const string strAddress = "test.html";
using (StreamWriter sw = new StreamWriter(strAddress))
{
sw.Write(strHtml);
} wb.Navigate("file://" + Application.StartupPath + "\\" + strAddress);
Етикети:
.NET,
.NET C# technologies,
C#,
IE Automation
Oct 7, 2008
One more ASP.NET page optimization ...
I wrote two articles on this topic already. The first was that you can earn few bytes from renaming the "javascript:__doPostBack" to "__dp". Then I noticed that I have problems with this. The problem was that in some cases you need to have the "javascript:" prefix. So my first attempt to do some optimization is considered more unsuccessful than successful. Now I am going to propose another way. It is again based on removing / renaming / moving existing things in the page so they can be a bit more optimized. Let's suppose we have a GridView. We clicked on the "Auto Format" thing and we not only have a GridView, but we have a nice looking grid view. It's great, but it seems to be unefficient. It appears that the GridView will add a |
I did a small snipet to fix this (not the best solution again but should be kind of starting point).
Here is my code:
protected override void Render(HtmlTextWriter writer)
{
System.IO.StringWriter stringWriter = new System.IO.StringWriter();
HtmlTextWriter htmlWriter = new HtmlTextWriter(stringWriter);
this.EnsureChildControls();
base.Render(htmlWriter);
string html = stringWriter.ToString();
AnalyzeStyles(html);
html = RepairStyles(html);
writer.Write(html);
}
private void AnalyzeStyles(string html)
{
MatchCollection CSSMatch = Regex.Matches(html, "style=[\"].+?[\"]", RegexOptions.IgnoreCase);
foreach (Match mCss in CSSMatch)
{
if (htDuplicates.ContainsKey(mCss.Value))
{
htDuplicates[mCss.Value] = Convert.ToInt32(htDuplicates[mCss.Value]) + 1;
}
else
{
htDuplicates.Add(mCss.Value, 0);
}
}
}
private string RepairStyles(string html)
{
int classID = 0;
int pos;
IDictionaryEnumerator iOccurences = htDuplicates.GetEnumerator();
this.CSS += "";
InformaticsWeb.Pages.Optimized master = (InformaticsWeb.Pages.Optimized)this.Master;
pos = Regex.Match(html, "", RegexOptions.IgnoreCase | RegexOptions.Singleline).Index + "".Length;
html = html.Insert(pos, CSS);
return html;
}
Please note : AnalyzeStyles adds each of the style="" found on the page (each unique). If it finds secound and third and so on - it increases a counter. The counter is not currently used, but may be later used to decide which of the styles should be converted to CSS classes.
So this code basically takes the page and moves all the style="" attributes in the head section as a CSS classes. I tested and my grid view seems as beautiful as before this code was applied.
Now, does it worth to add this logic?
Well I think you can achieve the same functionality by using Skin files. I am adding this more for reference.
I also did a small excel diagram to show you how much bytes are saved based on the count of the items in the GridView:
Please note that the htDupplicates is a Hashtable, declared as a global variable, so you will need to add it if you want to use this code.
Let me now explain the columns in the excel file shown above.
The “Columns” column displays how much columns does the GridView render. Typically the columns are rendered as a table cells and doesn’t contain any style=”” attributes (at least I couldn’t see any), so this is something you can’t affect. The thing that this optimization affects is the number of rows in your gridview. The more rows you have the more bytes you will get.
The second column displays the number of rows in the grid view.
The third column is the optimized size of the gridview (when the above technique is applied).
The “Size Original” column displays the size for unoptimized page (the same page!).
And the last column shows you the difference before and after.
You can see it in the diagram - for 20 items you have about 842 bytes difference. While for 80 you have about 3,512 (I don’t think there is a live site which displays 80 items at once in a grid view ;).
Oct 6, 2008
Very elegant way to cut few more bytes from your ASP.NET markup and optimize your bandwidth a bit (2) - Solving the puzzle
As I mentioned in my previous post, I ocassinally received errors when replacing the "javscript:__doPostBack" with "_dpb". It saved few bytes, yes, but for example the ASP Menu stopped working. I finally found what was causing the problem. It is because of links (rendered as "a href"). The ASP Menu renders them as a href="javscript:__doPostBack()". If you remove the "javascript:" part you will have problems as the browser will not be able to understand that you are trying to call a JS function. A possible solution is to move the call to the OnClick of the "a" element, leaving "#" in the "href" attribute like this: a href="#" onclick="_dpb()" This will however cause a small side effect. When the user clicks on the first |
Conclusion : You can apply the above technique but it will not help you much and I think it involves to much efforts for a small effect (few bytes). If you really want to get this benefit you can replace the "javascript:__doPostBack" with "javascript:_dp" and you will get less bytes than if removing the "javascript:" part but the page will work as expected.
I am currently working on other techniques to cut more of the ASP page markup, but they are a bit more serious. I hope I will write another post soon to inform you how it is going.
Етикети:
.NET,
.NET C# technologies,
ASP.NET newbies,
Development
Oct 3, 2008
Very elegant way to cut few more bytes from your ASP.NET markup and optimize your bandwidth a bit
I was thinking about how can I optimize the markup of a page a bit. I found a great way (great but not very very very efficient) to do so. It is based on a strategy that came in my mind recently. Let's think a bit. We already have very interesting methods to cut bandwith of an ASP.NET page like for example compressing the view state and so on and so on. So provided we already have applied those techniques, if we still want to optimize what should we do? I call my method : iterative profit, you will soon understand why ... If we have something that repeats few times in the markup and is relatively long as name, if we make it shorter we should win some bytes right? And if the page is big enough and "the thing" is repeated more times, we |
So each time we cut the name of something, we win few bytes.
The next question is what can we cut in order to optimize our page?
What is the thing that repeats in each web control?
The answer is the "__doPostBack" function. I tried to replace it during the Rendering of the page and was able to cut a bit of the page size, while keeping the source relatively clean of errors (please note the word "relatively").
Here is a sample code:
protected override void Render(HtmlTextWriter writer)
{
System.IO.StringWriter stringWriter = new System.IO.StringWriter();
HtmlTextWriter htmlWriter = new HtmlTextWriter(stringWriter);
base.Render(htmlWriter);
string html = stringWriter.ToString();
html = html.Replace("\"javascript:__doPostBack", "\"__dpb");
writer.Write(html);
}
I had some issues I haven't yet identified, as I was in a rush to post this as it seems to me a brand new way to optimize pages - to look for repeating elements and cut their names... (I will be happy if there are volunteers to help with this one ;)...
Other things : DoPostBackWithOptions should also be replaced by dpbw for example, this will be done in the future, after I clean the _doPostBack as it still have few problems.
And some more things - we may consider optimizing some of the ASP.NET controls which are known to be "markup unoptimized" like the treeview, gridview for example (At least I think there may be some things in them to optimize).
Any comments are welcome.
Етикети:
.NET,
ASP.NET newbies,
Development,
Software Development
Something that a lot of C# developers will miss when designing their classes
The thing is that the developers often forget they can set access modificators at set / get level for a property. Consider the following classes: namespace Locals { class Program { static void Main(string[] args) { LocalManager LocalMgr = new LocalManager(); Remote.RemoteManager RemoteMgr = new Remote.RemoteManager(); User usr = new User(); LocalMgr.Promote(usr); Console.WriteLine("After local promotion: " + usr.Occupation); } } public class LocalManager { public LocalManager() { } public void |
{
usr.Occupation = "Chief Officer";
}
}
public class User
{
private string strOccupation;
public User() { }
public string Occupation
{
get { return this.strOccupation; }
set { this.strOccupation = value; }
}
}
}
Here, after the program is executed the Local manager will promote the user and the output will be : After local promotion: Chief Officer
Now imagine that we want to have the name of the manager who promoted the User, so we can store it in a database. Obviously we need to have an instance of the Manager class, and write the information in the database, prior changing the occupation for the user.
We will want to have a method in the User class, which takes the Manager instance, writes everything needed in the database and then changes the Occupation.
But we can't be sure that all developers will use the method and not the property directly.
Firs let's add a property to the LocalManager class to hold the name of the manager. Then I will create a method to change users occupation, which will take an instance of LocalManager. This will be the only way an external class to change the occupation of a user. After this, we will slightly modificate the code in the main program so everything is called properly. Here is the code:
using System;
using System.Collections.Generic;
using System.Text;
namespace Locals
{
class Program
{
static void Main(string[] args)
{
LocalManager mgr = new LocalManager();
mgr.ManagerName = "Pavel Donchev";
User usr = new User();
mgr.Promote(usr);
Console.WriteLine("After promotion: " + usr.Occupation);
}
}
public class LocalManager
{
private string strManagerName = string.Empty;
public LocalManager() { }
public void Promote(User usr)
{
usr.Promote(this, "Chief Officer");
}
public string ManagerName
{
get { return this.strManagerName; }
set { this.strManagerName = value; }
}
}
public class User
{
private string strOccupation;
public User() { }
public string Occupation
{
get { return this.strOccupation; }
private set { this.strOccupation = value; }
}
public void Promote(LocalManager manager, string Occupation)
{
if (null != manager && !string.IsNullOrEmpty(manager.ManagerName))
{
// Do additional work here, for example write the
// name of the manager in the database amoung with
// time stamp of the promotion to have audit...
this.Occupation = Occupation;
}
else
{
throw new Exception("A valid manager instance and occupation should be passed!");
}
}
}
}
Now our classes are ready. You can give your user class away and be sure that no one can modify the property without passing a valid manager instance (actually the sequence of exceptions will guide your peers to follow the correct logic ;).
Oh, one more thing - we didn't proof that no one can assign the User.Occupation property directly. Well try to do so, you should receive compiler error message:
The property or indexer 'Locals.User.Occupation' cannot be used in this context because the set accessor is inaccessible
Етикети:
.NET C# technologies,
C#,
Software Development
Aug 22, 2008
ASP.NET / C# - Dynamically change ObjectDataSource SelectMethod may lead to troubles.
First of all - how to reproduce this?
<asp:Panel ID="pnlFilter" runat="server" GroupingText="Category:">
<asp:DropDownList ID="ddProductCategory" runat="server"
onselectedindexchanged="ddProductCategory_SelectedIndexChanged"
AutoPostBack="true">
<asp:ListItem Value="0">All Categories</asp:ListItem>
<asp:ListItem Value="1">Electronics</asp:ListItem>
</asp:DropDownList>
asp:Panel>
<asp:Panel ID="pnlProducts" runat="server" GroupingText="Products:">
<asp:GridView ID="grdProducts"
runat="server"
DataSourceID="odsProducts"
AutoGenerateColumns="true"
AllowPaging="true"
PageSize="2">
asp:GridView>
<asp:ObjectDataSource ID="odsProducts" runat="server"
DataObjectTypeName="string"
TypeName="WebApplication2.ProductsCollection"
SelectMethod="SelectAll">
asp:ObjectDataSource>
asp:Panel>
Here is the code in the code behind:
protected void Page_Load(object sender, EventArgs e)
{
}
protected void ddProductCategory_SelectedIndexChanged(object sender, EventArgs e)
{
if (this.ddProductCategory.SelectedValue == "0")
{
// Select all products from all categories
// SelectAll() doesn't take any parameters.
this.odsProducts.SelectMethod = "SelectAll";
this.odsProducts.SelectParameters.Clear();
}
else
{
this.odsProducts.SelectMethod = "GetByCategoryID";
this.odsProducts.SelectParameters.Clear();
// Pass category id:
this.odsProducts.SelectParameters.Add("categoryID", TypeCode.Int32, "1");
}
}
And finally the sample class:
public class ProductsCollection
{
public ProductsCollection() { }
public List<string> SelectAll()
{
List<string> retList = new List<string>();
retList.Add("Notebook");
retList.Add("PDA");
retList.Add("GSM");
retList.Add("Tomatoes");
return retList;
}
public List<string> GetByCategoryID(int categoryID)
{
// We will imagine that here we have some processing based on
// categoryid.
List<string> retList = new List<string>();
retList.Add("Notebook");
retList.Add("PDA");
retList.Add("GSM");
return retList;
}
}
What we want to achieve here?
Well, we simply want to display all products from all categories when the user loads the page for the first time. Then we want to give him / her a way to narrow down the results, by selecting a concrete category of products (in our case there is only one category named “Electronics”
The most logical is to change the SelectMethod of the ObjectDataSource from SelectAll() to GetByCategoryID and vise versa.
And, yes, at first sight it seems to work like a charm. But try to navigate to the second page of the GridView (I made the PageSize to be 2 items so the paging control can appear).
You will receive exception in some cases. To see do the following.
1. Refresh the page so you can start from the beginning.
2. Select “Electronics” from the Categories Dropdown.
3. Click on page 2 in the GridView.
Where is the problem here?
As you may already noticed the ObjectDataSource is trying to invoke the Products using the SelectAll() method, passing it parameters for GetByCategoryID.
The reason is that the ObjectDataSource seems to maintain only the SelectParameters and get the SelectMethod from the markup. But for some reason this only happens when the GridView asks for rebind (PageIndex changed and Sorted events).
When you change in the dropdown selected index changed it works.
I have kind of workaround which I will post a bit later and it is not proven to work in all cases but did the trick for me.
Add a Grid View, Object DataSource and a dropdown to a web form. Also you will need a class which has two methods with different names and can be marked as SelectMethod (return a List Here is my sample web form: |
<asp:DropDownList ID="ddProductCategory" runat="server"
onselectedindexchanged="ddProductCategory_SelectedIndexChanged"
AutoPostBack="true">
<asp:ListItem Value="0">All Categories</asp:ListItem>
<asp:ListItem Value="1">Electronics</asp:ListItem>
</asp:DropDownList>
asp:Panel>
<asp:Panel ID="pnlProducts" runat="server" GroupingText="Products:">
<asp:GridView ID="grdProducts"
runat="server"
DataSourceID="odsProducts"
AutoGenerateColumns="true"
AllowPaging="true"
PageSize="2">
asp:GridView>
<asp:ObjectDataSource ID="odsProducts" runat="server"
DataObjectTypeName="string"
TypeName="WebApplication2.ProductsCollection"
SelectMethod="SelectAll">
asp:ObjectDataSource>
asp:Panel>
Here is the code in the code behind:
protected void Page_Load(object sender, EventArgs e)
{
}
protected void ddProductCategory_SelectedIndexChanged(object sender, EventArgs e)
{
if (this.ddProductCategory.SelectedValue == "0")
{
// Select all products from all categories
// SelectAll() doesn't take any parameters.
this.odsProducts.SelectMethod = "SelectAll";
this.odsProducts.SelectParameters.Clear();
}
else
{
this.odsProducts.SelectMethod = "GetByCategoryID";
this.odsProducts.SelectParameters.Clear();
// Pass category id:
this.odsProducts.SelectParameters.Add("categoryID", TypeCode.Int32, "1");
}
}
And finally the sample class:
public class ProductsCollection
{
public ProductsCollection() { }
public List<string> SelectAll()
{
List<string> retList = new List<string>();
retList.Add("Notebook");
retList.Add("PDA");
retList.Add("GSM");
retList.Add("Tomatoes");
return retList;
}
public List<string> GetByCategoryID(int categoryID)
{
// We will imagine that here we have some processing based on
// categoryid.
List<string> retList = new List<string>();
retList.Add("Notebook");
retList.Add("PDA");
retList.Add("GSM");
return retList;
}
}
What we want to achieve here?
Well, we simply want to display all products from all categories when the user loads the page for the first time. Then we want to give him / her a way to narrow down the results, by selecting a concrete category of products (in our case there is only one category named “Electronics”
The most logical is to change the SelectMethod of the ObjectDataSource from SelectAll() to GetByCategoryID and vise versa.
And, yes, at first sight it seems to work like a charm. But try to navigate to the second page of the GridView (I made the PageSize to be 2 items so the paging control can appear).
You will receive exception in some cases. To see do the following.
1. Refresh the page so you can start from the beginning.
2. Select “Electronics” from the Categories Dropdown.
3. Click on page 2 in the GridView.
Where is the problem here?
As you may already noticed the ObjectDataSource is trying to invoke the Products using the SelectAll() method, passing it parameters for GetByCategoryID.
The reason is that the ObjectDataSource seems to maintain only the SelectParameters and get the SelectMethod from the markup. But for some reason this only happens when the GridView asks for rebind (PageIndex changed and Sorted events).
When you change in the dropdown selected index changed it works.
I have kind of workaround which I will post a bit later and it is not proven to work in all cases but did the trick for me.
Subscribe to:
Posts (Atom)