Showing posts with label winforms. Show all posts
Showing posts with label winforms. Show all posts

Wednesday, June 20, 2007

Friend Photosaver for Facebook

By now everybody who knows what Facebook is, knows they announced an open platform for integrating with it. Interestingly enough Microsoft was a launch partner of theirs so there is also a shared source .NET API layer available. We decided to jump on the opportunity and published SoapBox for Facebook. Chris mentioned this in his announcement blog earlier.

But, as with anything that goes to production, adding cool features quickly turned into fixing uncool bugs, scope discussions, planning sessions, and then it became work.

I had a bit of a realization yesterday. I hadn't written code for the sheer fun of it in a really long time. Don't get me wrong, I love the stuff I do (almost) every day. We're coding cutting edge stuff here and it's a blast. But, I wanted to do something for me! So I wrote a screensaver.

Strange, huh? The guy that writes blogs on memory management, async programming, and other maddening things decided to hack together a screensaver. You'll just have to get over the shock of it all... Research was done, scope was decided, fingers flew. A few hours later, I had a screensaver! At 2am I decided on its name (probably a bad idea), Friend Photosaver for Facebook, whipped up an installer and submitted the app to Facebook. Catchy isn't it? Yeeeah. Anyway, though the name stinks, I think it's a pretty cool screensaver.

It aggregates the list of all your photos with all of the photos of your friends, and picks them at random. It then stuffs the photo in a random spot on the screen where it will be visible. Right now it only displays on the primary screen. Secondary screens are blank. Here's a little preview:

Screen Saver

If you're a Facebook user you can login and install my screensaver. The rest of you... well, this is pretty useless. But you should be on Facebook too. Oh, and (shameless plug), don't forget to use SoapBox for Facebook. :)

Tuesday, April 10, 2007

Building Reactive User Interfaces in .NET: ISynchronizeInvoke on Idle Time

One of the most common things to do in a multi-threaded .NET Windows Forms application is to use the ISynchronizeInvoke interface on a Control to marshal things into the UI thread. The basic jist of things is: you can have the Windows Forms engine call your delegate on the thread that created the Control instance you're using. It does this using the window message pump. Typical uses of the ISynchronizeInvoke are: you want to read some data from a file, database, socket, or web service and you want your application to be responsive while you do it. When you're done you do a BeginInvoke/Invoke on the Control to update some UI elements. Well, sometimes using a Control's ISynchronizeInvoke leads to hung GUI's.

If you have a lot of asynchronous operations pending and they complete in bunches the affect on your UI can be the appearance of a hang or sluggishness as drawing is queued behind the delegates you registered with BeginInvoke on your control. During the login sequeunce in SoapBox Communicator there are potentially thousands of events that need to be processed on the UI thread. Yup, thousands. Your roster arrives from the server. You receive the current avialability from every online person on your roster. You got 10 messages while you were offline. Each of your contact's cached profiles (avatars, names, client capabilities, etc) are read from disk and compared with the user's current presence. This onslought of activity can be handled a number of ways. The basic principles I stumbled into after much trial and error is:

  1. Never, ever, ever, ever, ever do IO on a UI thread. Even something as simple as reading a 1KB image from disk can bring your UI to a halt under the right circumstances.
  2. Use timers and update common pieces of UI (like list views) in batches whose changes were caused changes by background operations. This will reduce flicker as you invalidate areas to redraw.
  3. Use Application.Idle to your advantage. (see my take on this below)
  4. Be careful how many window handles you create. Controls are useful, but sometimes you've just gotta draw your own.
  5. Profile your code where it seems sluggish.

I mentioned above that you should use Application.Idle to your advantage. The articles I've found on it all mention coding precise things you want to do in that event, like updating a single form. I wanted to do it more generically. So, I created an implementation of ISynchronizeInvoke that uses the Application.Idle event to process qeued items. I've created a (only slightly) contrived example that uses a Pi Calculator I found and an animated Gif to demonstrate a hanging GUI.


Both buttons calculate Pi to 50 digits on the UI thread using 100 separate ISynchronizeInvoke.BeginInvoke calls. The "Idle Invoke" button does so using my ApplicationIdleSynchronizer. The "Direct Invoke" button calls BeginInvoke on the Form directly. You can click the buttons any number of times and more and more Pi calculation runs will be queued. The completed label is incremented after every run. Here's the code:

    public partial class Form1 : Form
{
private const int WorkItems = 100;
private const int PiDigitsToCalc = 50;

private int _workItemsCompleted = 0;

private ApplicationIdleSynchronizer _idleSynchronizer = new ApplicationIdleSynchronizer();

public Form1()
{
InitializeComponent();
}

protected override void OnClosed(EventArgs e)
{
base.OnClosed(e);
_idleSynchronizer.Dispose();
}

private void button1_Click(object sender, EventArgs e)
{
System.Threading.ThreadPool.QueueUserWorkItem(QueueOnBackgroundThread, _idleSynchronizer);
}

private void button2_Click(object sender, EventArgs e)
{
System.Threading.ThreadPool.QueueUserWorkItem(QueueOnBackgroundThread, this);
}

private void QueueOnBackgroundThread(object state)
{
for (int i = 0; i < WorkItems; i )
{
((ISynchronizeInvoke)state).BeginInvoke(new ThreadStart(MyWorkItem), null);
}
}

private void MyWorkItem()
{
PiCalculator.CalculatePi(PiDigitsToCalc);
_workItemsCompleted++;
label2.Text = _workItemsCompleted.ToString();
}
}

Click the buttons. Move the form around. Resize it. You might be suprised by the result (or not). Both very adequately use your CPU, but the Idle Invoke produces a much more reactive UI. You can download the full source code here: ApplicationIdleInvoker.zip. Note, this exact code isn't in use in production. I wrote it for this blog. YMMV. Let me know if it has any issues.

Monday, May 8, 2006

FakeOutTheUserToThinkWeDontUseAnyMemory

There comes a time in every project where the developers realize we are building software for the users, rather than for ourselves. A user's perception can be the difference between a good and a bad reference, and we all know how detrimental bad word of mouth can be. This unfortunate reality hit me square in the face recently when I was told by a customer that "your application is bloatware".

Any desktop application with a user interface, written in .NET, that does anything interesting, can easily be mistaken for bloatware. It's quite easy to create a super elegant application with no memory leaks that appears to use 50MB or more of memory. I say appears, because the figure everyone sees in Task Manager is the "Working Set" size. Users (myself included, up until recently) see large working set sizes as a sign of bloatware and poor programming.

This is simply not the case. The working set is more along the lines of the amount of physical memory the OS thinks your application might need or needed at one point, including shared memory and all sorts of other complicated things that .NET developers aren't supposed to have to think about. If your system was in need of physical memory for other processes much of this perceived bloat would either be reclaimed and put to better use, or paged out to disk.

At the end of the day, the reality of the situation doesn't matter. Your users think your application is bloated. What do you do? Well, you FakeOutTheUserToThinkWeDontUseAnyMemory.


using System.Diagnostics;

namespace Coversant.Utility {
public static class MemoryUtility
{
private static volatile bool _enabled = true;

public static void FakeOutTheUserToThinkWeDontUseAnyMemory()
{
if (!_enabled)
return;

try
{
Process curProc = Process.GetCurrentProcess();
curProc.MaxWorkingSet = curProc.MaxWorkingSet;
}
catch
{
//Some users won't have permission to adjust their working set.
_enabled = false;
}
}
}
}

Yep, that's it. Call that method (.NET 2.0 only -- in 1.x you had to P/Invoke) and watch the magic happen. In our applications we set it up on a timer that runs every 30 seconds and after any events we know will raise the working set, usually after loading new assemblies or after a window is closed . Running this code causes Windows to free up as much of the working set as possible. Usually this sends most of your bloat to the page file where it will remain forever. In our case, the application had a 50MB working set and really only needed about 10MB of physical memory after it was running. There is, however, one big gotcha. An application can only attempt to adjust its working set if it is running with appropriate permissions (typically a local Administrator).

Yes, your users perceptions are reality. Using this trick/hack helps keep reality in line.

About the Author

JD Conley is an entrepreneur and hacker, currently working away his golden handcuffs at Playdom, a subsidiary of the Walt Disney Company, since Hive7 was acquired. We make social games. The views and opinions expressed on this post are his and do not necessarily represent or reflect those of The Walt Disney Company.