January 2003 - Posts
Ok,
my Radio client has just blown up for the last time. Ironic considering I just contacted
Scott to apply as a beta tester for dotnetweblogs. This time my workspace.pt table is just completely blown away. As far as I can tell this contains many important pieces of information related to publishing. I can repair it, because I've got a backup, but I'm sick of Radio doing this to me. How a database-based product can mysteriously just
lose tables is beyond me.
This time my worskspace.pt table was missing.
Ok, I've had it with Radio and its many bugs, lack of updates, quirks, etc. This is not anything new. I have wanted to move for a very long time to something .NET based but I have not had the time. Scott Watermasysk has graciously volunteered access to his ASP.NET solution and hosting. So I am moving. My new site will be here. The new RSS feed is here. It will take some time to move over and get things squared away especially with project and book deadlines, and a new baby so please be patient with me. I hope all my loyal readers will continue to read at the new site and as always, I thank each and every one of you for reading my stuff and hope that it continues to help you in youyr work. [Sam Gentile's Weblog]
Hmm... I might have to try this out myself.
So, I went out to Vegas last weekend for the Super Bowl. It's somewhat of a new ritual that my buddies and I go out there. I took the Bucs on the money line and won myself a decent amount. I was soooo close to winning a hefty prop bet too. I had placed $50 on the fact that there would be a 2pt conversion. Three friggin' tries the Raiders had!!! They missed them all. I held my breath while they reviewed the third to see if the guy would have landed in bounds, but alas there was no irrefutable evidence to overturn the call. It would have paid +300. *sigh*
Unfortunately, I gave over half of it back on the damn Craps tables. We just couldn't get a break this weekend when it came to the tables. For anyone who plays, it was basically the annoying pattern of the shooter getting a point, you putting up your odds, place bets, etc. and then the next roll the shooter would seven out. There were only two streaks the entire weekend where more than two points were made by the same shooter. You just can't win under those conditions, unless you're a "Don't" player, but then everyone else at the table hates you. ;) I think I made the most money playing Carribean Stud Poker this weekend, which is ironic because it's got some of the, if not the, worst odds in the house.
As long as you go out there realizing that the odds are against you and you don't have any silly superstitions, you can always have a good time... and that's exactly what we did.
xbox. Looks like a few people liked the bloggers xbox session idea, but I need some practice, I just got a schoolin' from James. My gamertag is zak42. [Simon Fell]
Ooooh... I missed the original post, but I'd love to get in on the action. My XBL gamertag is drub0y. I'm big on MechAssault and MotoGP. I was a beta tester for the service and while I think it's great and has an insane amount of potential, I'm still waiting for the breakthrough game that keeps me online for days at a time. I'm a big fan of racing games, so I'm looking forward to PGR2. I'm also a big fan of fighting games, but for some reason the recently released and soon to be released fighters don't seem to think there's much value in online play. Capcom vs. SNK EO, which is supposedly due out early next month, is the only fighting game I know of that's got XBL support. Of course, what we're all really waiting for is... Halo2! :)
This is a follow-up to this previous post about sorting a DataGrid. It turns out that the person who originally asked the question about knowing when the sort would occur, wanted to know this for the purpose of re-selecting the currently selected row after the sort. Well, as it turns out this is entirely possible, but it requires some deeper digging into the data-binding aspects of WinForms (which I love btw). ;)
So here's what you'll need to do. First things first, you're going to need to watch for the sort to happen as was detailed in the previous post. Upon detecting the sort about to happen you must record a key value for the currently selected row in a state field (probably in your Form). Now, here's where the deeper knowledge of data-binding comes into play. You must also attach an event listener to the ItemChanged event of the CurrencyManager for the DataTable/DataView you've bound your DataGrid to. The ItemChanged event will fire after the sort takes place at which point you use the DataView's (DataTable::DefaultView if you're bound directly to a DataTable) Find method to locate the row in the view by the key value that you stored in your state field in the sort detection event logic. Once you've found the new position of the row in the DataView after the sort, you set the CurrencyManager's Position property to that index.
Ok, this might sound complex, but lemme show you just how easy it is with some code. For the purposes of keeping this code concise, assume this code is in a Form subclass which contains a DataGrid in a member variable called "myDataGrid". This DataGrid is then bound to a DataTable, stored in a member variable called "myDataTable" which has a key column named "key" of type int:
public class MyForm : Form
{
private int currentlySelectedRowId = -1;
public MyForm()
{
this.InitializeComponent();
// Get the CurrencyManager for the bound DataTable
CurrencyManager dataTableCurrencyManager = (CurrencyManager)this.myDataGrid.BindingContext[this.myDataTable];
// Hook up to the ItemChanged event
dataTableCurrencyManager.ItemChanged += new ItemChangeEventHandler(this.myDataTableCurrencyManager_ItemChanged);
}
private void myDataGrid_MouseUp(object sender, MouseEventArgs args)
{
DataGrid.HitTestInfo hitTestInfo = this.myDataGrid.HitTest(args.X, args.Y);
if(hitTestInfo.Type == DataGrid.HitTestType.ColumnHeader)
{
// Get the CurrencyManager for the bound DataTable
CurrencyManager dataTableCurrencyManager = (CurrencyManager)this.myDataGrid.BindingContext[this.myDataTable];
// Get the current DataRowView
DataRowView currentRowView = (DataRowView)dataTableCurrencyManager.Current;
// Remember the currently selected row ID
this.currentlySelectedRowId = (int)currentRowView["key"];
}
}
private void myDataTableCurrencyManager_ItemChanged(object sender, ItemChangeEventArgs args)
{
// Only execute this logic if we're in the state of sorting
if(this.currentlySelectedRowId != -1)
{
// Find the new position of the row now that it's been sorted
int newPosition = this.myDataTable.DefaultView.Find(this.currentSelectedRowId);
// Get the CurrencyManager for the bound DataTable
CurrencyManager dataTableCurrencyManager = (CurrencyManager)this.myDataGrid.BindingContext[this.myDataTable];
// Change the position of the currency manager
dataTableCurrencyManager.Position = newPosition;
// Reset sorting state
this.currentSelectedRowId = -1;
}
}
}
A good question came up on a the DOTNET-WINFORMS mailing list this morning. I had to think about it which makes me realize that plenty of other people are probably wondering the same thing: How do you detect when a DataGrid is about to be re-sorted?
There is no SortChanged event on the DataGrid. This turns out to be quite annoying, considering the "manual" way to detect a sort. So here's how to do it:
According to the documentation for the DataGrid::AllowSorting property, clicking on the column header will result in the DataGrid being re-sorted by that column. So with that in mind, take the following steps to detect when a column header has been clicked:
- Attach to the DataGrid's MouseUp event.
- In your handler, call DataGrid::HitTest
- Using the DataGrid.HitTestInfo returned, inspect the DataGrid.HitTestInfo::Type property and check the resulting DataGrid.HitTestType for the ColumnHeader value.
It would look a little something like this:
<codeSnippet language="C#">
private void myDataGrid_MouseUp(object sender, MouseEventArgs args)
{
DataGrid sourceGrid = (DataGrid)sender;
\// Perform hit-test
DataGrid.HitTestInfo hitTestInfo = sourceGrid.HitTest(args.X, args.Y);
\// Check if a column header was clicked
if(hitTestInfo.Type == DataGrid.HitTestType.ColumnHeader)
{
\// A column header was clicked, which means a sort occurred.
\// Perform any custom logic here.
}
}
</codeSnippet>
Update: Corrected to use MouseUp event instead of Click event since DataGrid doesn't seem to fire Click event.
Update 2: I don't know what I missed the first time I tried it, but the Click event does work for this scenario. If you choose to hook up to that event you can make the HitTest using Control::MousePosition.
So, I'm sitting here doing a database upgrade and while I was waiting for a ton of data to finish replicating I was looking over the implementation of Simon's PingBack Client for Radio and noticed that in his pingbackSuite.checkPost method he has a support function called extractLinks that does a lot of manual string parsing that could very easily be replaced with some Regex calls. Radio has Regex support via system.extensions.regex. In that library there is an extract method. The regex to find the links would be <a .*?href="?([^">\\s]*). Therefore, extractLinks could be rewritten simply like so:
on extractLinks(txtWP)
local(txt = string(txtWP))
local(linkMatches = nil)
\// Extract the matches, specifying the list returned contain only the URL group
regex.extract("<a .*?href=\"?([^\\">\\\\s]*)", @txt, @linkMatches, { 1 })
return(linkMatches)
Nothin' major, but why write all that annoying parsing logic yourself, ya' know? :)
evolution. So I'm sure I've read how to do this somewhere (perhaps in Ingo's book ?) but I have a .NET struct that has the [Serializable] attribute applied to it, and have a bunch of them serialized to a disk file. Now I want to revise the struct by adding a new field, how do I control the deserialization process that I restore my existing serialized data into the new format structs ? Back in the days where I used to implement IPersistStream by hand, I always had a version # in the serialized stream, so that the deserialization code could rev old formats upto the current format. [Simon Fell]
I believe the only way to control serialization across versions of components is to implement ISerializable and read/write the members yourself to the serializer implementation using the provided SerializationInfo. Then, in order to get the serializer to instantiate the new version of your component for deserialization is to use a bindingRedirect.
Update: Correction. I forgot all about SerializationBinder... it's designed for exactly this scenario. Have a look at the BindToType method documentation for an example of how to implement your own binder.
Update 2: I just walked up to work for a weekend release we're doing and along the way I was thinking about the SerializationBinder scenario some more. I realized that, even though that will help you redirect to a different version of a component, it still won't handle scenario's where serialized fields are changed by name or type or, worse, removed all together. The only way that I can see to have true version safe serializability is by implementing ISerializable on your type and reading the values into your serialized fields yourself. So I think the original scenario I suggested is the right way to go.
Riddle me thiis grasshopper. Why do titles that have been set in Radio and inserted manually into the Item Template not show up on any category pages even if they use the same exact template? [
Sam Gentile's Weblog]
Excellent observation Sam. Time to dive into the publishing code.
Update: Just got the chance to look into this, then I remembered that categories have their own independant templates. So you actually need to go into <Radio Program Files Root>\\www\\categories\\<Your Category> and update the templates there to inclue <%itemTitle%>. You can probably just copy your itemTemplate from the main site since you pretty much want the same look and feel across categories in that respect.
Update 2: Apparently you can just nuke the templates from the category sub-directories and they'll be rendered using the templates from the main directory. Makes sense if you wanted to control each category's rendering independently.
More Posts
Next page »