Friday 30 November 2007

Dynamically change the cssclass of a div

I can never remember how to do this, so it's definately worth documenting.

You can add runat="server" and an id tag to any control, and you'll be able to access it from the code-behind, just don't expect to get at all of the attributes that the HTML version presents.

In my case, you can't edit the CSS class of a div just by adding an id and a runat="server" tag.

It turns out that you can, but it's not as direct as you may think. Most of the time properties like that come up by default, but not divs! For divs, you have to add the attribute manually:

myDiv.attributes("class") = "myclass"

If you need to do it for a bind method, you can cast the control to a htmlgenericcontrol.

All I can is that it's easy when you know how.

Thursday 27 September 2007

Premature databinding in a user control

It happens to us all. You go to bind a data repeater to a user control, but it happens far too soon in the event loading process, and you end up with a repeater that doesn't update until you re-refresh the page.

An example of this not working is as follows:

Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load

rptBasket.DataSource = bList
rptBasket.DataBind()

End Sub

The reason this won't work is because the page_load event happens too soon for your repeater to be bound. So use the page_loadcomplete event, right? Wrong. There is no page_loadcomplete event for user controls, so to get your datalist / datarepeater to bind at the right time, you're going to have to use a page_preRender event. It does the same job as the page_loadcomplete event.

Last.FM scrobbling via Creative Zen / Winamp

I know this isn't strictly coding-related, but it's a bit geeky for my other blog, and I know for a fact that there are a lot of deserving people out there who want to scrobble Creative Zen Vision:M tracks on their Last.FM account via Winamp.

The problem is that Winamp grabs the tracks from your player via a http stream which means that audioscrobbler ignores it. The way to get around it is to stop using the latest version of last.fm, and revert to an old version of the audioscrobbler plugin that didn't require the last.fm program.

The version you're looking for is:

audioscrobbler.wa.1.1.11.exe

If you find that, install it instead of your latest plugin, you should be away!

Thursday 6 September 2007

Element.setAttribute and other strange problems

Heed this.

If you're using javascript events like onmouseover and onmouseout, don't bother using them if you want to do something clever.

My plan for these events was as follows:
  • Your image has an onmouseover and onmouseout state. An on / off state.
  • When clicking this image, the onmouseover and onmouseout state change. So does the source of the image.
The trouble with this is that if you want to modify the onmouseover and onmouseout events dynamically in a javascript function depending on whether the image has been clicked or not, you're out of luck. Firefox supports the element.setAttribute('attribute','property') method, but Internet Explorer versions do not.

Even what Firefox does support seems to be patchy, and doesn't complete my image swapping. The event states didn't want to stick across browser versions.

It turns out that if you want to alter those mouse-related events, you can't do it dynamically in a javascript function. IE won't let you at all, and Firefox's support seems to be buggy.

So how did I get around this?

Our creative girl produced a cascading stylesheet which had images with on/off states in them, and then moved the image depending on what the class of the div surrounding our image was. From there, we could alter the class of the div and therefore alter the hover states.

For example:




Where price_result1 in the stylesheet is:

.price_result1 {
width:44px;
height:12px;
background:url(../images/result_headers/price.gif);
float:left;
}

.price_result1 a {
display:block;
width:44px;
height:12px;
background:url(../images/result_headers/price.gif) 0% 0% no-repeat;
}
.price_result1 a:hover {background-position:0% 75%;}

price_result2 is:

.price_result2 {
width:44px;
height:12px;
background:url(../images/result_headers/price.gif) 0% 75% no-repeat;
float:left;
}
.price_result2 a {
display:block;
width:44px;
height:12px;
background:url(../images/result_headers/price.gif) 0% 75% no-repeat;
}
.price_result2 a:hover {background-position:0% 100%;}





And so on.

I hope this helps. Really I do, because it took me three days to work this out.

The XMLHttpRequest object

This is AJAX related, and likely to cause problems if you're doing what I'm doing.

I use the object to write out some HTML into a div of a page.

The HTML I'm writing is from an ASP file, and so the syntax for the (pre-declared object) looks like this:

url = "searchDBaseAjax.asp?" + savedUrl;
url=url+"&sid="+ Math.random();

xmlHttp.onreadystatechange=caravanSearchStateChanged;
xmlHttp.open("GET",url,true);
xmlHttp.send(null);


Now if youre searchDBaseAjax.asp file contains some javascript that you want to write to that div, and you want it to happen straight away, you'll have problems.

Say you put a hidden input field in your ASP file.

Say that you then want to test this within the function that you write your ASP file from (just below the code mentioned above).

if (document.getElementById('hideHeaders').value == '1') {
document.getElementById('resultsHeader').className = ' none';
}
else {
document.getElementById('resultsHeader').className = 'floatleft paddingtop15';
}

Because this is an asynchronous call, it's likely that the processing of the AJAX method will not be completed by the time that your javascript underneath executes, and therefore your input field will not be tested properly.

One solution was to make this method synchronous. (Change the true in the open method to false). Trouble is, that doesn't work.

So to fix it, I used the xmlHttp.onreadystatechange attribute to specify the method caravanSearchStateChanged which is mentioned in the first code-snippet.

That method now looks like this:

function caravanSearchStateChanged()
{
if (xmlHttp.readyState==4)
{
document.getElementById("ajaxSearchResults").innerHTML=xmlHttp.responseText;

if (document.getElementById('hideHeaders').value == '1') {
document.getElementById('resultsHeader').className = ' none';
}
else {
document.getElementById('resultsHeader').className = 'floatleft paddingtop15';
}
}
}

So basically, the ready state for our open method is 4 and I've checked that this is the case before I fire off my new javascript that tests the input field.

Days of messing about, this took.

For more information, check out the MSDN entry.

Friday 8 June 2007

An introduction to indexing

I'm writing this blog because there's no solid guide on indexing services with ASP.NET, so I'm going to pull together a bit of a guide on how to do it in the hope it helps someone else.

Setting up

Setting up the indexing service itself is fairly simple.

Follow this guide:

http://www.windowsnetworking.com/articles_tutorials/Making-Windows-Server-2003-Indexing-Service-Useful.html

That guide'll only give you information on creating a query form for ASP.

To create one with .NET I'll explain some sample code later on.

Indexing PDFs

If you're looking to index PDFs as well, download and install this on your server:

http://www.adobe.com/support/downloads/detail.jsp?ftpID=2611

That'll automatically work after you stop and re-start the indexing service. It does take a while so be patient.

.NET Query Form

Basic implementation of .NET query forms is explained in the links below:

http://www.codeproject.com/aspnet/search.asp

and

http://idunno.org/articles/278.aspx

The .NET implementation of a form itself is dead easy. The problem is that most forms would require a search for "Any phrase" and "Exact match" as options.

The exact match bit is the tricky bit. Code's explained a bit below:

'Any Words
Select DocTitle,Filename,Size,PATH,URL, Rank, Characterization, Write from SCOPE('deep traversal of ""/documents""') where FREETEXT('" & strSearch & "')

'Search Exact Phrase
strSearch = """" + strSearch + """"
Select DocTitle,Filename,Size,PATH,URL, Rank, Characterization, Write from SCOPE('deep traversal of ""/documents""') where contains('" & strSearch & "')

The search phrase is double-quoted because the indexing service needs quotes around it to conduct an exact search. That took me quite a while to work out!

The standard contains statement seems to work for me, although I may come back and correct this if it turns out to not do quite the job I'd expected.

If anybody has any questions on this, leave a comment with your email address and I'll get back to you.

Tuesday 22 May 2007

Opening a new window with a linkbutton control

I couldn't do it, and it turns out that lots of other people can't do it either.

They tried to set the navigateurl attribute to the url they want, and then when they tried to open the link in a new window, they got a load of javascript in the address bar and no link.

There is a legitimate way around this, but it involves extending the linkbutton, which I didn't have time to do.

If you do want to do it though, you should try the 4guysfromrolla article, because it does give quite a nice explanation.

If you want a quick workaround, I suggest that you do the following:

Swap your linkbutton link with a regular anchor tag.


<a href="#" id="linkTag" runat="server">This is an example link</a>


That'll be enough for your aspx page. The runat tag and id tags are new and allow you to get to the control from the code-behind.

If you're modifiying the control within a datalist or a datarepeater, you'll need to use findcontrol to get hold of it. If you do, you'll need this code:

Dim link as new htmlAnchor

link = e.item.findControl("linkTag")

The above creates a new anchor tag control and finds the one on your page.

However, if you're just accessing it within a regular function that isn't binding data, you can assign the bits you need like this:

linkTag.HRef = "http://karlitr0s.blogspot.com"
linkTag.innerText = "Karl's Blog"
linkTag.title = "Karl's Blog"
linkTag.target = "_blank"

The innertext tag is for labelling your link.
The href tag points to where you need to go.
The target tag is the html equivalent, and opens up the new window for you.

Doing it this way instead of using Javascript:window.open('') in the href tag means that you don't get your original page from displaying [object] or whatever your browser does when it doesn't understand where it's going within .NET.

Definately the quickest and easiest way around it, but if you have to use external links a lot in your application or you have to utilise the postback as well, you're probably better off extending the linkbutton.

Monday 21 May 2007

Datasets

"One or more rows contain values violating non-null, unique, or foreign-key constraints."

Very informative error, that. Thanks very much Microsoft.

This can happen for a number of reasons, but for me it was happening because within the datatable in my dataset, I had columns set with smaller sizes than the actual stored procedure fetched. Therefore, I was trying to fit three litres of water into a two litre bottle.

I fixed this by matching the data table's column sizes to match those within the database. Somebody else was experiencing similar problems but with a different solution on the Microsoft Forums.

Monday 14 May 2007

Gridview solution

I've found the solution to most of my problem!

The code for a standard gridview is listed below:

Protected Sub pubSearchResults_RowDataBound(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.GridViewRowEventArgs) Handles pubSearchResults.RowDataBound
If e.Row.RowType = DataControlRowType.DataRow Then
Dim p As New Pub
p = e.Row.DataItem
Select Case p.award
Case 1
e.Row.Cells(1).Text = "Platinum"
Case 2
e.Row.Cells(1).Text = "Gold"
Case 3
e.Row.Cells(1).Text = "Silver"
Case 4
e.Row.Cells(1).Text = "Bronze"
End Select
Dim lnkEdit As New HyperLink
lnkEdit = e.Row.FindControl("lnkEdit")
'lnkEdit.NavigateUrl = "pubSearch_detail.aspx?id=" + p.id
End If
End Sub

The _RowDataBound method is a default gridview method and is called when every row in the grid is created. What I've done is accessed the row's award value (Which was collected from the row) and done a select case on it. From there, I've accessed the row passed in's cell index for the award. It's the second column in on the table, so it's the index 1. I've then assigned the text value Platinum, although I also intend to give it a css class to make it silver, which is just as simple to do.

Friday 11 May 2007

ASP.NET Web Controls

They're not ready yet!

Its web controls are beginning to cause me problems that I'm not entirely sure how I'm going to find a way around, but I'm going to post it here as soon as I do.

Imagebuttons do not have an onmouseover / onmouseout feature, which seems ridiculous to me, so I wrote a custom control that takes care of it instead. It inherits the linkbutton control with some additional methods. There are plenty of howtos floating around on the internet, so this wasn't a bit problem for me.

The big problem is turning out to be the gridview control.

Sorting out paging and sorting seems like a minimum of fuss, and I'm happy for people that require that really badly, but I'm much more concerned with a lack of formatting.

If you want to add columns to a datagrid in the code-behind, you seem buggered as far as I can see. You can't just do:

objGrid.columns.add("Column1", datasource.column1)

Why the hell can't you do that? It's common sense!

Styling fields is also a problem.

Say that your database produces a column that will contain an integer from 1 to 5. If you get number 1, you want it to say "Gold" in a nice gold font. If you get number 2, you want it to say "Silver" in nice silver font, and so on.

How the hell are you supposed to do this? One suggestion was to customise the control by inheriting the grid's class. Why should I have to do this? Why isn't basic styling for the code-behind included? Is this going to happen in .NET 3.0?

To give you a more accurate picture of what I'm talking about, see the link below:

http://www.dabs.com/productlist.aspx?&CategorySelectedId=11146&NavigationKey=11146&PageMode=1

Scroll down to the product listing, and you can quite clearly see that those rows of what I reckon is a gridview are customised to style differently depending on their values.

Some of this was surely done in the code-behind, as an objectdatasource for every page is a bit silly, especially if you want to use a proper data access layer.

If anybody's got any thoughts on this, feel free to leave a comment and let me know what I'm doing wrong that the gridview supports, as I'm at the end of my tether. How on earth you can see fit to release a control that at best binds with basic styling is ludicrous.

Furthermore, how the hell is this seen as an enterprise solution if you have to inherit classes and write new methods that do what should happen anyway?

Rant over, and I'll post a solution with complete explanation as soon as I can.

An introduction

I'm Karl, and I'm starting this blog to vent my frustrations at coding issues in any language I encounter, and to post solutions to problems that have plagued my life since my coding birth. Sounds messy, doesn't it.

It's about time I started trying to give back to the community since I take so much help from howtos and FAQs.

All the best,

Karl.