If you want an out-of-the-box solution to this problem you're likely to be disappointed. I haven't found anything that works except ClickOnce, and I dislike it. I did find this:
http://windowsclient.net/articles/appupdater.aspx
My solution was to roll my own. It's actually not that difficult. I wrote a small bootstrapper application that first checks for updates, downloads them if necessary, and then launches my application in a new AppDomain. Pretty easy.
If you want to check for updates while your app is running, you need to write and add a component/class to your project that performs that task, and informs the user (MessageBox or whatever) that an update is available. If they choose to perform the update then you need to launch your bootstrapper (so it can fetch the updates) and kill your current process.
All of this is very possible with a little time and some custom code. It's not as difficult as it sounds. The biggest thing is determining how configurable you want your custom solution to be because that can affect when/where your bootstrapper goes to look for updates (I built mine to look for updates on a network share).