August 8, 2008
@ 07:48 PM

It looks like it's the week of CodeRush/DXCore plug-ins (I still have one more plug-in coming up).

This plug-in just lets you collapse an XML comment tag to one line (I'll explain it a bit more below). It was actually written as a Refactoring (so it appears when you hit the refactoring key or wait for the ellipses to appear below the code). I put this one together a few days ago and was planning on releasing it after I had a chance to live with it for a while to see if there were any changes or bugs I needed to address. But someone on the DevExpress forums recently posted about wanting a plug-in which did the same thing so I decided to just release it right now.

So what does this really do?

When you add an XML comment to something like a property or field, you end up with the following (in C#):

/// <summary>
///
/// </summary>
private int m_someValue;

The cursor is positioned on the second line. After installing this refactor, you can hit the Refactor key (which I mapped to just the ` key (instead of Shift or Alt or Ctrl ` , whatever the default is) and this comment will get collapsed down to one line:

/// <summary></summary>

This can help eliminate some of the visual noise of the comment, especially if it's just a short comment.

If you have a muli-line comment, it actually collapses it in two stages (that is, you can issue the refactoring twice), so for example:

/// <summary>
/// This is my multi-line
/// comment about nothing.
/// </summary>

The first time you collapse it you end up with:

/// <summary>This is my multi-line
/// comment about nothing.</summary>

The second time you collapse it you end up with:

/// <summary>This is my multi-line comment about nothing.</summary>

You can download the code from the download section on my site or the community site. Like before, there will probably be a few day delay between when it's available here and when I get it put up on the community site.

To install it, copy it into your C:\Program Files\Developer Express Inc\DXCore for Visual Studio .NET\2.0\Bin\Plugins\ folder.

Links:

http://www.rcs-solutions.com/Download.ashx?File=Refactor_Comments.zip
http://code.google.com/p/dxcorecommunityplugins/


 
Categories: CodeRush | Visual Studio

August 5, 2008
@ 08:48 PM

This was an interesting issue I ran into today. We've got a utility I wrote which can search Outlook MSG files from a desktop interface. As part of the program you can print the results to a PDF - I'm using Crystal Reports to do the printing. We had this application installed on a desktop machine for a while but decided to move it over to one of our servers which had a lot more hard drive space. After moving it, when we attempted to print we'd get the error:

"An error has occurred while attempting to load the Crystal Reports runtime"

At first I thought it might be related to needing the CR DLL's installed instead of just being deployed in the app's directory. We installed them and tried again - same exception. Further down in the error (which was actually helpful - imagine that!), "Please install the appropriate Crystal Reports redistributable (snip) containing the correct version of the Crystal Reports runtime (x86, x64, or Itanium).

Hmm...x86 vs x64 - that has to be it - this was Windows 2003 Server (64 bit) vs. XP. I actually just recently listened to a DotNetRocks podcast which talked about .NET applications running under a 64 bit OS. They mentioned that, by default, most .NET applications are compiled under "Any CPU". That means the code get's JIT'ed to 64 bit code under a 64 bit OS - sounds OK. The only catch is that all the components must also be compiled the same way, otherwise you run into problems. I didn't really want to have two different sets of DLL's so I went back into my application and changed it from "Any CPU" to x86 code and recompiled. Order was restored to the universe.

Links:

http://www.dotnetrocks.com


 
Categories: .NET

I've been meaning to post this up for a while but never seemed to get around to it. I've been using CodeRush/Refactor! (CR/R!) from DevExpress for a few years now and this was actually the first plug-in I wrote for it. If you're not familiar with CR/R! it's sort of Intellisense on steroids with a bunch of refactoring tools thrown in. OK, that description really doesn't do it justice - I'd suggest taking a look at a few of the videos they have available over on the DevExpress site to get a better idea of what it does. I'd put CR/R! in the "must have" category for any .NET developer. It's actually annoying to use Visual Studio without it installed.

At any rate, this plug-in does nothing more than make it easy to insert a comment that contains the developers name or initials and the date of a change. For example:

// PCM - 8/4/2008 -

Or, if you happen to be located on an XML comment line, it inserts the following:

/// <developer>Paul Mrozowski</developer>
/// <created>08/04/2008</created>

It's language agnostic, so this should actually work in VB.NET as well (it uses the '/''' comments instead). I've tied it to the CTRL-Insert keypress but you can set it to whatever you'd like. To install it, copy it into your C:\Program Files\Developer Express Inc\DXCore for Visual Studio .NET\2.0\Bin\Plugins\ folder. Then start up Visual Studio and go to DevExpress, Options. You should see a new tree option, "Developer Initials". Fill in your name and initials and select whether you'd like it to insert your initials for a line comment or your full name. Then go to IDE > Shortcuts. Expand the Code folder. I created a new folder named "Custom". Click on the icon for a new keyboard shortcut. On the right-hand side, enter the keyboard shortcut (mine is Ctrl+Insert), then in the Command combo select "Add Initials". Then hit OK.

CR_Initials

CR_Initials2

Exit out of Visual Studio and go back in. At this point the plug-in should be active. Try it out by hitting your shortcut key on a new line (or, enter an XML comment. Hit enter, on the new XML comment line hit the shortcut key).

You can download it from here (http://www.rcs-solutions.com/Download.ashx?File=CR_Initials.zip) and it may show up on the DX Core Community Plug-ins site at some point.

Links:

http://www.devexpress.com
http://code.google.com/p/dxcorecommunityplugins/


 
Categories: CodeRush | Visual Studio

July 31, 2008
@ 07:00 PM

I'm a big fan of "drop in" components which can add functionality to my applications as opposed to what is more commonly thought of as framework-level code which bakes in functionality. What do I mean by that? The common way of building in functionality into an application (usually via a framework) is to develop an class hierarchy, then inherit from those classes in your application as you build up functionality. A form class may have code which remember it's location and size when you close it, an edit box may add some spell checking ability, etc. If you inherit all your forms from these classes they suddenly have all this extra functionality and life is good. Then, as the framework is built you tend to end up with a number of interdependencies between components, which suddenly makes it more difficult to be able to use these components in other applications which don't include most of the framework libraries and inherit from the proper classes. On one level that's fine, since it allows for a fairly high level of functionlity and consistency. However, it requires a high level of "buy in" in order to use even the most basic aspects of the framework. In many cases you just can't use some cool combobox class from the framework in another application without requiring the full framework (and inheritance chain) to come along for the ride, which is a bit of a bummer. There are a huge number of applications written that can't easily be integrated with a framework (as most VFP developers think of them).

What if, instead, components had been built to be highly modular - drop in a small class library, add the control to your form and you're good to go. Until VFP 9 this was actually a bit hard to do - what if your control needed to respond to various form events? Everytime you dropped the control on a new form you suddenly have to do a lot of wiring up by adding code to the various events your control was interested in. Which leads back to the first style of development that just assumes you'll be using these components as a whole. However, in VFP 8 they introduced a set of commands to allow for event binding: BINDEVENT(), UNBINDEVENTS(), RAISEEVENT() and AEVENTS(). So what do these commands do and what do they give you? They give you a mechanism of listening for specific events that fire on an object and handling those events in your own code. You can do this without the "source" object even being aware you are listening to it's events.

A real example might help:

Let's suppose we want to add the ability to sort a column in a grid. The common way of doing that would be to create a subclass of a grid, add some code which does the sorting as methods on the grid, then require the developer to "hook up" the functionality during development so that this new functionality runs when a user double clicks on the row header. In effect, add code to every column's header and adding code to the DblClick() event. You'll even notice that even if we require you to use our new subclassed grid the functionality still isn't really just drop-in seamless. So how can event binding help here? Can it help us achieve both goals of not requiring any glue code and not requiring us to inherit from a specific grid control?

What I'd love to end up with is a control I can drop on a form, point it to some grid control and have the grid "magically" let you sort without requiring a lot of changes to existing code. So let's start from that premise and create a custom control. I'll add cGridEval property which can be filled in with a string which is EVAL'd at runtime to resolve a live object reference to our grid, ex. you can fill in something like "This.grdSample". That's the easy part, now how do we use event binding to let us do everything else?

I'm going to create a BindControl() method in my custom control and we'll first get our object reference to the grid:

loGrid = EVALULATE(This.cGridEval)

Every grid has a Columns collection that we can iterate through and each column has a Controls collection. If we take a look at the BaseClass property of the controls here we can determine which one is the Header column. At that point we can use BINDEVENT() to hook up the DblClick() event to us - when a user double clicks on this grid column the event will fire on the grid and we'll also get a notification that the event has fired.

FOR EACH loColumn IN loGrid.Columns
    FOR EACH loControl IN loColumn.Controls
        IF loControl.BaseClass = "Header"
           BINDEVENT(loControl, "DblClick", This, "Sort")
           EXIT
        ENDIF
    ENDFOR
ENDFOR

The BINDEVENT() function is where the real work happens. We pass the control we want to listen to as the first parameter, in this case the header. Then we pass (as a string) the name of the method we want to listen to, "DblClick". The third parameter is an object reference to the subscribing object (us), and the fourth is the method VFP should call on our object. You must make sure that the method you create on your subscriber accepts all of the same parameters as the event being fired. For example, if we hooked into the KeyPress event accepts two parameters, nKeyCode and nShiftAltCtrl - you have to accept the same parameters in your subscribing method. There is a fifth parameter which can be passed that we're not using which allows you to specify when your code is called - before or after the original control's method fires. DblClick doesn't pass in any parameters, so we're good. All we need to do is create a "Sort" method on our custom object.

At this point, when a user double clicks on a header in a hooked up grid, our Sort event fires. Great - now how do we figure out which header was clicked on? Here's where the AEVENTS() function comes into play - it fills an array with information about the object that triggered the event. We can use this information to get a reference to the actual header the user double clicked on. From there, we can determine which column in the grid to sort.

AEVENTS(laEvent, 0)

This gives us a 3 column array, laEvent:

laEvent[1] - An object reference to the header that was clicked
laEvent[2] - The event that was fired
laEvent[3] - The event type (how the event was raised).

In our case we're really only interested in laEvent[1]. Once we have our header reference we can get the column's control source like this:

loHeader = laEvent[1]
loColumn = loHeader.Parent
lcControlSource = ALLTRIM(loColumn.ControlSource)

All that's left is for us to build up a way of creating temporarily indexes and maintaining a list of which indexes have been created (and whether we're current ascending or descending). One thing that is kind of nice is that since we now have a reference to the column header, we can also do things like add some graphical image to the sorted column to make it easy for the user to see which column has been sorted and in which direction.

You'll notice that I didn't cover the UNBINDEVENTS() and RAISEEVENT() functions. UNBINDEVENTS does just what you'd expect - it unhooks an event handler so that it no longer receives the bound event. RAISEVENT() lets you "fire" an event (both things like custom events and events on native VFP objects). I don't have a nice example of this so I'll leave that for some other time.

You can download the finished control below.

Links:

http://www.rcs-solutions.com/Download.ashx?File=rcsGridSort.zip
 

Categories: VFP

July 12, 2008
@ 10:34 AM

I mentioned Dependency Injection / Inversion of Control (DI/IoC) recently and I really didn't explain what it is, why you might want to use this particular pattern, and why on earth you'd need a framework for it. It's a fancy name for a fairly simple concept. Instead of creating objects inside of your classes, you let the calling code "inject" the necessary instances into your code. It's probably easiest to see this in some code. I'm going to show both C# and VFP code, since I don't want you to get the idea that this is a .NET-only type thing.
 

   1 public class SampleDependency

   2 {

   3    public string SayHello()

   4    {

   5       return "Hello";

   6    }

   7 }

   8 

   9 public class Sample

   10 {

   11    protected SampleDependency m_depend;

   12 

   13    public SampleDependency Depend

   14    {

   15       set { this.m_depend = value; }

   16    }

   17 

   18    public Sample(SampleDependency depend)

   19    {

   20       m_depend = depend;

   21    }

   22 }

 

      Sample sample = new Sample(new SampleDependency());

 

VFP Version
DEFINE CLASS SampleDependency AS Session 
   FUNCTION SayHello() 
      RETURN "Hello" 
   ENDFUNC 
ENDDEFINE 

DEFINE CLASS Sample AS Session 
   oDepend = NULL 
   FUNCTION Init(toDepend) 
      This.oDepend = toDepend 
   ENDFUNC 
ENDDEFINE 

loSample = CREATEOBJECT("Sample", CREATEOBJECT("SampleDependency"))
 

Notice that in both cases, we are passing in the instance we want the class to use instead of letting the class create the instance itself. That's all DI/IoC is. Honest, that's it. This is DI via a constructor (you can also do it via a property setting instead; notice in the sample C# code I created a write-only property which could hold the reference).

So the next obvious question is, why? What's wrong with just creating the object inside of the class?

One thing DI gives you is the ability to easily swap in different objects. In the C# example, we probably would change the parameter from a specific type to an interface. Now any class which implements that interface can be injected into this class. In VFP, since it's not strongly typed, you can just pass in whatever instance you'd like (it's up to you to make sure it doesn't blow up at runtime by accessing some method or property which isn't on the passed in object). My initial thought after seeing this was, well, can't I just use an abstract factory pattern instead? In an abstract factory you delegate object creation to a "object factory" - usually passing in a name or calling a method which returns the actual instance you'd like to use. This sounds like almost the same thing.

An abstract factory does let you do that, but it doesn't let you easily do something the DI/IoC pattern does: test your objects. Let's suppose you want to write a test for a class which uses another class to send out an e-mail. You aren't really trying to test sending an e-mail - that's just one of the things the class you're testing happens to do during some process. In fact, you really don't want to send out an e-mail; we don't want to spam our users. If you happen to use the abstract factory pattern, you would need to modify it to create your dummy/stub/mock object for sending an e-mail (in VFP that's most likely by editing a record in a table, but the idea is the same), then test the object in question. If you used the DI/IoC pattern the only thing you need to do is pass in your dummy/stub/mock object. No other modifications are necessary.

OK, so this all looks simple enough. Why would you need a framework for the above?! One of the biggest reasons - less typing. You'll notice that in order to use any of these objects you may have to pass in a bunch of other dependency objects (which themselves may have other dependencies). For a complex set of objects that could really suck. A DI framework does that for you along with the benefits of an abstract factory, all rolled up into one. In your code you call the DI framework and tell it to get you an instance of a class - it figures out what objects need to be passed in for you so you don't need to do it. In your tests, you can instanciate the objects directly and pass in your stub/dummy/mock objects instead.

Links:

http://weblogs.asp.net/rosherove/archive/2007/09/16/mocks-and-stubs-the-difference-is-in-the-flow-of-information.aspx
http://www.hanselman.com/blog/ListOfNETDependencyInjectionContainersIOC.aspx


 
Categories: .NET | Software | VFP

July 11, 2008
@ 08:42 PM

I just ran across this and it's a welcome option - you can add "(loband)" to any of the MSDN documentation links on the website and it will serve up a much faster version of the docs. For example,

Instead of:

http://msdn.microsoft.com/en-us/library/cc707819.aspx

Try:

http://msdn.microsoft.com/en-us/library/cc707819(loband).aspx

There is also an option at the top of the page once you've selected this option to persist the low bandwidth view, so all of the pages come up like this by default. I appreciate the treeview when I'm just poking around, but sometimes the site is just painful to navigate to since it takes a bit to render them.


 
Categories: MSDN

July 6, 2008
@ 12:24 PM

I attended a Day of Dot Net event in Lansing a few week back. If you're not familiar with them, they are free mini-conferences (one day) about, not surprisingly, .NET.

I had originally planned on driving out to it Saturday morning, but then Jenn pointed out I'd have to get up really early to get there around 8am. I already work in Farmington, which is 45 minutes to 1 hour from home (and 45 minutes to 1 hour closer to Lansing) and would end up being a really long day for me. So I ended up just staying at a hotel in Lansing Friday night. That turned out to be a great idea. Note to self: the Best Western in Lansing feels and smells like a 80's style bowling alley.

When I got to the hotel, I had some time to look up directions to the college where it was being held. It was only a few miles away, so I decided to not bother to drive over there on Friday night (which is what I would normally have done). In the morning I followed the directions Google Maps had given and found myself in a church parking lot (hmm..."Day of Dot Net and Evangelical Revival??"). I checked the map a few times and it looked OK, and I was exactly where it said I should be. I think that was about the point where I starting cursing out Google maps. I had left all my information about the conference in the trunk so I had to get out of the car to get at it. I happened to notice that the road I was on looked like it actually continued around the side of the church (imagine a light bulb going off above my head: "hey...maybe...."). I jumped back in the car and drove around the parking lot and sure enough, the trees suddenly cleared on my left hand side where the college was hiding. I noticed another car stop right about where I stopped, so it wasn't just me being dense (honest!). Note to organizers - great event, but a small sign would have been appreciated.

When I got into the building (which also wasn't marked, so I still wasn't entirely sure I was at the right entrance), I was surprised at how few people were there - that kind of surprised me since I wasn't able to make it to the last DoDN because it had filled up. It turns out that as the morning wore on the sessions really started to fill up.

The sessions were an hour long - which is REALLY short; they flew by. The sessions all seemed to run a few minutes long which pushed into the next session running a bit longer. The lunch break helped to reset everything.

A few notes to the various presenters:

  • The bottom 1/3 of the screen really isn't visible if you're sitting in the back of the room. I was sitting in the second row and couldn't read some of it.
  • White text on a black background might be easier on your eyes for development, but it's impossible to read when it's projected up on a screen. I'd suggest sticking with black text on a white background.
  • Don't try to wing demo's. Only a few people can successfully pull that off - you're probably not one of them.

I actually ran into a few people I knew - one was someone from the local VFP user group, the other was a old-VFP developer that I haven't seen in a few years. That was a nice surprise. Overall, I was impressed by the number of people who attended, considering you're basically giving up a weekend day to attend. It's nice to see that some people actually care about getting better as developers (either that or they, like me, needed a few new shirts for their wardrobe).

One session happened to stand out in my mind - a session about Dependency Injection / Inversion of Control (specifically, the Windsor framework) by Jay Wren. Well organized, hit every question I had about DI/IoC. Honestly, I didn't "get" DI/IoC before this session; yeah, I understood what it was, but not really why on earth I might need a framework for it. It is actually an elegant way of solving a particular development problem, giving you the benefits of a factory pattern and the flexibility of DI, without getting in your way (at least that's what my notes say). I had the "a ha!" moment, then promptly lost it in one of the other sessions. I'm sure it will come to me at some point, although at this point I'm getting a bit nervous ;-)

At the end of the conference, they ended up giving away of ton of stuff. Just not to me. Oh well, maybe next time.

Overall, I definitely attend another one - a big thanks to the organizers and presenters and sponsors, I know it's a lot of work to put something like this on - it was appreciated. Just try to make sure you've got some soft drinks (Coke, Mt. Dew, etc.) available in the morning next time around <g>. It's hard for some of us to get moving in the morning without some caffeine (for us non-coffee drinkers). Sure I feel all healthy from the orange juice I ended up drinking, but it didn't help much to put a spring in my step.

Links

http://www.dayofdotnet.org/Lansing/2008/
http://jrwren.wrenfam.com/blog/


 
Categories: .NET | Conference

I've been working on an application which relies heavily on WCF to communicate. I have a very simple interface (contract) that the server supports to connect and disconnect: it exposes the methods Register() and Unregister(). When the client starts up and connects, it calls the Register() method, passing in some identification info. I save this information in a List<T> so that it can be used by the server to provide callbacks. When the client disconnects, it calls Unregister() which then removes the client from the collection.

That works well enough, right up until a client abruptly disconnects (ex. a connection error, network line goes down, etc.) Then suddenly I end up with a reference to a disconnected client on the server. If I attempt to use this connection to send a message back to the client an exception is thrown (which still works OK). It would be nice to know immediately as soon as a client disconnects.

If you are using TCP (full duplex) as the communication channel, you can do this pretty easily - note: this doesn't work for some of the other communication modes, like HTTP duplex. For those, you might have to rely on the various timeout settings in the .config file.

Here's what that ends up looking like (I happen to be taking advantage of LINQ here, but you can easily adjust that code if you're using an older vesion of the framework):

  203 private void IServer.Register(string systemName)

  204 {

  205     IClientCallback remoteMachine = OperationContext.Current.GetCallbackChannel<IClientCallback>();

  206     // Hook up events to let us know if the client disconnects w/o telling us.

  207     OperationContext.Current.Channel.Faulted += new EventHandler(ClientFaulted);

  208     OperationContext.Current.Channel.Closed += new EventHandler(ClientClosed);

  209 

  210     // Get object reference to figure out the IP address of the connected client

  211     MessageProperties prop = OperationContext.Current.IncomingMessageProperties;

  212     RemoteEndpointMessageProperty endpoint = prop[RemoteEndpointMessageProperty.Name] as RemoteEndpointMessageProperty;

  213 

  214     // (threading/locking code removed)

  215 

  216     client = m_callbackList.Find(c => c.SystemName == systemName);

  217     if (client == null)

  218     {

  219         // It's not already on our list, add it

  220         m_callbackList.Add(new RegisteredClient(systemName, endpoint.Address, remoteMachine));

  221     }

  222 }

 

When the client disconnects, the ClientFaulted/ClientClosed events will be fired. Honestly, at this point, the Unregister method isn't really needed, assuming you follow the same disconnection process in both cases.
 
Categories: WCF

April 19, 2008
@ 08:07 PM

 

I admit it - the above comic could be about me. I can be easily distracted by shiny things, so I sometimes have to fight off the urge to spend way too much time playing around with some cool bit of technology, code, or idea. If you're like me, these links may be your downfall. Lot's of things to sidetrack you with. The site I snagged the above comic from is just one of them.

http://www.xkcd.com

MIX is a web development conference put on by Microsoft. They've made all (well, at least I think it's all of them) of the conference topics available online. Very cool - there are bunch of really good sessions available here. Silverlight is looking interesting.

http://visitmix.com/

The TED (Technology, Entertainment, Design) conference is a four day conference with one "track" of speakers that each get 18 minutes to there thing. From what I've gathered, it's mostly an "invite only" type of event of around 1000 people (and even if it wasn't, the $6000 membership fee would probably keep the number of people attending under control). At any rate, they've made something like 200 of the talks available for free, so there are a ton of interesting videos to watch here. Since they're all under 18 minutes, it's easy to fit a video or two in a sitting. Then you can waste another few hours Googling some of the things they talk about.

http://www.ted.com

Google Earth - An "oldie" but a goodie. I can waste a ton of time with this one. Something about the interactivity of it really appeals to me. I can't say I was ever really a map-person until apps. like this and GPS became readily availble. And if you get bored, there are a bunch of neat 3D buildings and map overlays to download. Zoom in, zoom out, zoom in, zoom out...

http://earth.google.com/

Photosynth - If Google Earth appeals to you, you'll probably also love this one. It's basically a Microsoft research project (well, Microsoft owns it now) that takes pictures of some scene and projects it (or builds it, I'm not exactly sure) onto a 3d framework of the original location. Check out the Collections they've got - I swear I wasted a good 45 minutes rotating and zooming into the images. Even if you've seen this in the past, visit it again: they've added a few new collections that are pretty cool.

http://labs.live.com/photosynth/

The above should keep you busy for a while. I had planned on "featuring" a timewaster once a week or so, but at my current blogging pace it'd probably be closer to once a month, so I decided to just group a bunch of the more general ones together into one post. Have fun.


 
Categories: Other

April 15, 2008
@ 10:18 PM

One request that comes up from time to time is to embed a checkbox inside of an ASP.NET grid control for boolean data.

Unfortunately, one of the downsides to this is that the controls are "read only" - they don't let you check or uncheck them

without putting the row into edit mode. That works, but in some cases this isn't all that great either. What do you do if you just want a checkbox on each row, that's "live" and causes a postback as you check/uncheck items? Thankfully this doesn't take much code but figuring out the first time can be really painful. To get the "live" checkbox, just wrap it inside of a template. (In the example code I created a new Web Form named "GridCheckbox").

<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="GridCheckbox.aspx.cs" Inherits="WebApplication1.GridCheckbox" %>

 

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

 

<html xmlns="http://www.w3.org/1999/xhtml" >

<head id="Head1" runat="server">

    <title>Untitled Page</title>

</head>

<body>

    <form id="form1" runat="server">

    <div>       

        <asp:GridView runat="server" ID="grdList" AutoGenerateColumns="false"

            onrowdatabound="grdList_RowDataBound">

            <Columns>

                <asp:TemplateField>

                    <ItemTemplate>                       

                        <asp:CheckBox runat="server" ID="chkItem" Checked='<%# Container.DataItem %>' AutoPostBack="True" OnCheckedChanged="CheckChanged"/>                                              

                    </ItemTemplate>

                </asp:TemplateField>

            </Columns>

        </asp:GridView>

    </div>

    </form>

</body>

</html>

 

Make sure you set the "AutoPostBack" to true. Then set it's OnCheckedChanged event handler to call your server side code.

Now let's add some code to the Page_Load to give our grid something to bind to:

protected void Page_Load(object sender, EventArgs e)

{

    bool[] items = { true, true, false, false, true };

    if (!Page.IsPostBack)

    {

        this.grdList.DataSource = items;

        this.grdList.DataBind();

    }

}

 

 

In my example code, I'm just binding to a simple boolean collection to keep things simple. Now we need an event handler to respond to our checkbox event:

protected void CheckChanged(object sender, EventArgs e)

{          

}

 

The code doesn't do anything yet but at this point you might be wondering how we figure out which checkbox we checked - normally, your grid is bound to a different row in some table. Each checkbox is related to that specific row. How or where do we get that from? The grid isn't much help in this case because it's not raising the event. If we were using a Button we could set it's CommandName and/or CommandArgument properties to hold something like the primary key of the row in our table. The checkbox control doesn't have any such properties. ASP.NET controls have an InputAttributes collection where you can place name/value pairs - this information is passed to the client (and back to the server), so it makes this relatively painless.

First, add an event to onRowDataBound of the grid (already shown in the ASPX above). Now add the event in our code-behind:

protected void grdList_RowDataBound(object sender, GridViewRowEventArgs e)

{       

}

 

We can't reference the control directly by name, since it was embedded in the grid and ASP.NET has made sure it's uniquely named. Let's use the FindControl method to do this. I've also added the code to add a Value attribute and added a member called m_row. I'm just using this so we can have a different value on each and every row of the grid. In a real application this is where you'd pull the primary key value from your datasource (probably using e.Row.DataItem).

private int m_row = 0;

protected void grdList_RowDataBound(object sender, GridViewRowEventArgs e)

{

    CheckBox chk = e.Row.FindControl("chkItem") as CheckBox;

 

    if (chk != null)

        chk.InputAttributes.Add("Value", this.m_row.ToString());

    this.m_row++;

}


Now we're just about done - all that's left is retrieving this value back on the server when the Checkbox is checked or unchecked:

protected void CheckChanged(object sender, EventArgs e)

{

    CheckBox chk = sender as CheckBox;

    string val = "";

    if (chk != null)

        val = chk.InputAttributes["Value"];

}


So our completed codebehind page looks like this:

using System;

using System.Collections;

using System.Configuration;

using System.Data;

using System.Web;

using System.Web.Security;

using System.Web.UI;

using System.Web.UI.HtmlControls;

using System.Web.UI.WebControls;

using System.Web.UI.WebControls.WebParts;

 

namespace WebApplication1

{

    public partial class GridCheckbox : System.Web.UI.Page

    {

        private int m_row = 0;

        protected void Page_Load(object sender, EventArgs e)

        {

            bool[] items = { true, true, false, false, true };

            if (!Page.IsPostBack)

            {

                this.grdList.DataSource = items;

                this.grdList.DataBind();

            }

        }

 

        protected void CheckChanged(object sender, EventArgs e)

        {

            CheckBox chk = sender as CheckBox;

            string val = "";

            if (chk != null)

                val = chk.InputAttributes["Value"];

        }

 

        protected void grdList_RowDataBound(object sender, GridViewRowEventArgs e)

        {

            CheckBox chk = e.Row.FindControl("chkItem") as CheckBox;

 

            if (chk != null)

                chk.InputAttributes.Add("Value", this.m_row.ToString());

            this.m_row++;

        }

    }

}

Now when you run this every time you check or uncheck an item you should see the page post-back (set a breakpoint on CheckChanged). You can now update your data, or whatever else you need to do in response to this event.
 
Categories: ASP.NET

April 4, 2008
@ 06:15 PM

This has hit me more than once already. If you create an HTTP Handler (ASHX) file, by default the context object reference (passed in to ProcessRequest) doesn't contain a reference to the Session object, so attempting to access context.Session will fail.

The fix is to add a "using System.Web.SessionState" to the using section, then inherit from the IReadOnlySessionState interface.

 

Ex.

 

using System.Web.SessionState;

public class MyAshx : IHttpHandler, IReadOnlySessionState
{

}

 

This will give you read only access to the session state. If you need to add to the session, inherit from IRequiresSessionState instead.


 
Categories: ASP.NET

April 3, 2008
@ 08:19 PM

I've been playing around a bit with WPF lately (with Visual Studio 2008) and was disappointed that there wasn't any intellisense in the designer (like what you'd see in the ASP.NET designer). I happened to mention this on the UT and John Fenton there pointed me to this link:

 

http://blogs.msdn.com/windowssdk/archive/2008/02/22/workaround-installing-win-sdk-after-vs2008-breaks-xaml-intellisense.aspx

 

Apparently installing the Windows SDK after installing VS2008 breaks XAML intellisense. The link above walks through fixing it (very simple registry entry fix).

 

Links

 

http://www.universalthread.com
http://blogs.msdn.com/windowssdk/archive/2008/02/22/workaround-installing-win-sdk-after-vs2008-breaks-xaml-intellisense.aspx


 
Categories: Visual Studio | WPF

March 23, 2008
@ 12:05 PM

I've finally gotten all set-up in Microsoft's Empowerment program. I wish I could say it went smoothly, but that definitely wasn't the case. I think I may have signed up at the worst possible time - they were in the process of revamping their website which caused me a bunch of different problems. I finally got tired of playing e-mail tag and called Partner support a few weeks ago. They had been telling me to complete the application process, but every time I tried to log back into the Empowerment site it just told me my application had been denied and it wouldn't let me sign back up (or even tell me WHY it had been denied). When I called they took a look at it then told me they needed to have someone else take a look at the problem. I received an e-mail a few days later claiming the problem should be resolved.

I tried logging back in but had the same problem I had been having. I called them again two weeks ago Monday and while I was on the phone they were finally able to clear whatever flag was keeping me from being able to resubmit my application - they definitely added a few more required fields from when I initially signed up. Last Monday I figured I'd try logging back into the Partner site and see if they had any way of checking the status. I ended up trying to sign up again but this time I got to a page which wanted me to agree to some EULA, but the buttons were all disabled. Was that a good sign or a bad sign?

I found out two days later (on Wednesday) when I received my Empowerment CD's and DVD's. Unfortunately, they don't include any kind of documentation about how to actually get your license keys. Since I've worked at a few places which had their Universal subscription (when it was available), I assumed I might just be able to log into the MSDN subscriber download section using my MS Live ID. I clicked on the "Associate your subscription with your WIndows Live ID" link but it also wanted me to enter my

MSDN

Benefit Access Number, Subscriber ID, or MSPP Technical Contact ID. Unfortunately I didn't receive anything labeled that way in the kit they sent me. I tried using my partner ID and my MCP ID, neither of which worked. I dug through the partner website and found that I actually had a "Technical ID" associated with my name. To find this - log into the partner site and click on the "Requirements & Assets" menu at the top, then select "Associated People"

PartnerAssoc

At the bottom of the screen that opens is a list of all people associated with your company and their technical ID. I tried entering this and it unfortunately didn't work. I thought (maybe) the site required a Live ID e-mail address instead of my other e-mail address, so I entered it instead and saved it. Then I tried signing in again. At that point the site complained that I had entered the wrong info. in too many times and to try again in 5 minutes. At that point I gave up.

The next day I dug up the MSDN support number and gave them a call. They had me re-enter the information I had tried the night before, fiddled with a few things and suddenly it let me log in!

I know someone who is planning on signing up as well and I'm curious to see if it goes smoother for them than it did for me - hopefully it does.

 

Links:

http://www.rcs-solutions.com/blog/2007/10/12/MicrosoftsEmpowerProgramForISVs.aspx
http://www.rcs-solutions.com/blog/2007/11/20/EmpowermentProgramUpdate.aspx
https://partner.microsoft.com/40011351
http://msdn2.microsoft.com/en-us/default.aspx


 
Categories: Software

March 9, 2008
@ 10:48 AM

Wow, local DAFUGer Frank Perez has actually posted new content on his blog. He's worse than I am with keeping it updated regularly (and I'm pretty sure only 3 or 4 people even knew he HAD a blog; that probably keeps the pressure to update it regularly to a minimum). Anyway, he's showing off a neat plug-in tool for Beyond Compare that let's you run comparisons against various VFP-specific filetypes (DBF/MNU/SCX/VCX among others). Check it out.

Links:

http://www.dafug.org
http://www.pfsolutions-mi.com/blog/2008/03/08/BeyondCompare.aspx


 
Categories: VFP

March 8, 2008
@ 02:16 PM

We ran into an interesting performance issue a few weeks back. We had migrated our primary fileserver over to a new machine (it was previously running on the same machine as our website). We expected some of the pages on our website to be a bit slower since the files were no longer on the same box (we have both data in VFP and in SQL Server 2005), but some of them were suddenly painfully slow. They went from 1-2 seconds to more than 7+ seconds. We talked about installing a dedicated network card to link two servers to help, but it still didn't seem like the performance should take that much of a hit.

My boss spent some time tracing the problem and found it was really slow when we opened the company file from our accounting system (Sage Pro). I've talked about the performance of USE in the past, but it was still amazing to see how slow it was. He tried using a mapped drive and UNC mapping but the performance of each was about the same. This particular table is part of a database, so he tried prefixing the USE statement with the database name, ex. USE F:\PathTo\Data\MyDatabase!MyTable IN 0 - the difference was amazing. That 7+ seconds dropped back down to 1-2 seconds: a bit slower than it was when it was local, but still much faster than it had been. Resolving the database is apparently very slow.


 
Categories: VFP

March 8, 2008
@ 02:00 PM

I was just checking out the PPCGeeks website, checking up to see if anyone had any status updates on the Sprint Mogul PPC. I've had this phone since late August, and have been waiting for a promised upgrade which is supposed to finally enable the built-in GPS-A support and support for EVDO Rev A. It finally looks like it may actually see the light of day on Monday, according to this post. It would have been nice to have had it released on Friday so I'd have the weekend to get it installed and get my phone customized again, but as a developer, I can appreciate not doing a release on a Friday.

I'm hoping Google Maps will support the built-in GPS. I've got an external blue tooth GPS I could use, but it's just not as convenient as something built-in. I'm not really looking forward to reinstalling all of my applications and customizing it with the HTC Touch interface (which is a MUCH nicer interface than the stock one), but thankfully this isn't something I have to do on a regular basis.

Links:

http://forum.ppcgeeks.com/showthread.php?t=20363
http://www.america.htc.com/support/mogul/software-downloads.html
http://www.google.com/gmm


 
Categories: Cellphones

February 10, 2008
@ 01:17 PM

I just uploaded a new version of the VFP calendar. I've fixed the problem where the drop-down version of the calendar wouldn't collapse if you clicked away from it. I initially thought it would be a simple matter of just adding some code to the calendar form's LostFocus event. That appeared to work, but had the side effect of breaking the drop-down button. If the calendar was being displayed and you then tried to click on the drop-down button to hide the calendar, the LostFocus would fire (hiding the calendar), then the Click event of the button would fire which would redisplay the calendar. Not quite what I was expecting.

I experimented with a few different ways of attempting to address this, but I just couldn't get the events to fire the way I wanted. Ultimately, I ended up adding code in the Click event to save off the last time since the calendar was hidden. If it is under the configured minimum interval, we don't do anything (the assumption is the the LostFocus just fired and hide the calendar). If the interval has been exceeded, the calendar is displayed as normal. A little weird, but relatively simple to code.

I've also added another sample to show how the rcsDateTimePicker controls can be hooked together for Start/End date scenarios. The controls keep the start date from being later than the ending date. The parent (Start) / child (End) relationship is setup via two properties on the control: uParentPicker and uChildPicker. These properties are evaluated to resolve to an object reference to the proper control.

 

Links

http://www.rcs-solutions.com/downloads.aspx


 
Categories: VFP

January 13, 2008
@ 05:33 PM

I'm happy to say my winter cleaning give away was a success. Almost all of the books that were available have new owners (although they may still be waiting for them, since they were shipped at the book rate which can take forever), and my huge pile of computer equipment is also gone. I had a taker for the computer equipment within a day of posting it on my local Freecycle site. I thought he'd pick through the rubble, but he ended up taking the whole pile (including my Windows NT 3.51, NT 4.0, and Windows 2000 Resource Kits - those alone took up a full bookshelf).

There are a few books still available, if anyone is interested.

Img_4417

 

Links:

http://www.rcs-solutions.com/blog/2007/12/13/WinterCleaning.aspx
http://www.freecycle.org


 
Categories: Other | VFP

January 13, 2008
@ 05:17 PM

I was just reading some of the threads over on the UT and ran across one where someone was looking for a drop-down calendar control. Someone suggested they look at the one that I've got in the downloads section on my site. Unfortunately, the version I've had up forever doesn't actually have a "drop down" version of the control. I've had an updated version for a long time now, but I've never gotten around to posting it (until now). This thread kicked me in the butt a little to update this on the site.

Here's a screenshot of the updated control:

DropdownCalendar

Hopefully you find it useful.

 

Links:

http://www.universalthread.com
http://www.rcs-solutions.com/Downloads.aspx


 
Categories: VFP

December 12, 2007
@ 10:23 PM

I've been spending a lot of time lately doing some winter cleaning. We're trying to free up some space in the basement for a play area for Brendan. It's amazing how much stuff you can collect. We've thrown away a LOT of stuff - I'm pretty sure the garbage guys hate us by now. Jenn mentioned that