Apr
27
2009

C#: AutoSave with WPF



Comments available as RSS 2.0

Creating an automatic save for ResourceBlender Express was actually a lot easier than I thought it would be but I’ll post the source here for anyone else wondering how to do it.

My .xaml.cs file has four class variables to make it work, and the save method executes in a separate thread to prevent it locking the UI during saving (actually a BackgroundWorker).

BackgroundWorker worker;
DispatcherTimer timer;
int autoSaveInterval = 3000;
DateTime lastSave;

The DispatcherTimer times the save at a specified interval and the BackgroundWorker executes the operation. In the class constructor I setup the DispatchTimer:

public WinEditRbt() {
	...
	timer = new DispatcherTimer(TimeSpan.FromMilliseconds(autoSaveInterval), DispatcherPriority.Background, new EventHandler(DoAutoSave), this.Dispatcher);
}

I wanted to allow the user to save manually regardless of whether an autosave had just executed, but prevent autosaving if the user had just recently saved, so the DoWork delegate checks to see when the save method last executed before saving.

private void Save(object sender, ExecutedRoutedEventArgs e) {
    if(worker != null && worker.IsBusy) {
        while(worker.IsBusy) {
            Dispatcher.Invoke(DispatcherPriority.Background, new ThreadStart(delegate() { }));
        }
    }
    ...
    worker.DoWork += (s, dwe) => {
        DateTime dtStart = DateTime.Now;
	if((DateTime.Now - dtStart).TotalSeconds < 4) { // give the user chance to see the message
            worker.ReportProgress(0, "Save Complete");
            Thread.Sleep(2000);
        }
    };
}

Lambdas help minimize the amount of method garbage in the class by reducing the number of methods to one per worker task instead of three (ProgressChanged, DoWork and RunWorkerCompleted). To manually save, you just need to trigger the ApplicationCommands.Save command.

private void CanExecuteSave(object sender, CanExecuteRoutedEventArgs e) {
    e.CanExecute = this.IsLoaded && (worker == null || !worker.IsBusy);
}
 
private void DoAutoSave(object sender, EventArgs e) {
    if((worker == null || (worker != null && !worker.IsBusy)) && DateTime.Now.Subtract(lastSave).TotalMilliseconds >= autoSaveInterval) {
        ApplicationCommands.Save.Execute(null, this);
    }
}
Share and Enjoy:
  • Print
  • Digg
  • Sphinn
  • del.icio.us
  • Facebook
  • Mixx
  • Google Bookmarks
  • Blogplay

Comments

Leave a Comment

Login using OpenID or enter your details below to leave a comment.

OpenID
Anonymous


Comment

Powered by WP Hashcash