Index: /stable/HeuristicLab.Common/3.3/Content/ContentManager.cs
===================================================================
--- /stable/HeuristicLab.Common/3.3/Content/ContentManager.cs	(revision 17067)
+++ /stable/HeuristicLab.Common/3.3/Content/ContentManager.cs	(revision 17068)
@@ -21,4 +21,5 @@
 
 using System;
+using System.Threading;
 
 namespace HeuristicLab.Common {
@@ -43,5 +44,5 @@
       if (instance == null) throw new InvalidOperationException("ContentManager is not initialized.");
       var func = new Func<string, IStorableContent>(instance.LoadContent);
-      func.BeginInvoke(filename, delegate(IAsyncResult result) {
+      func.BeginInvoke(filename, delegate (IAsyncResult result) {
         Exception error = null;
         IStorableContent content = null;
@@ -49,6 +50,5 @@
           content = func.EndInvoke(result);
           content.Filename = filename;
-        }
-        catch (Exception ex) {
+        } catch (Exception ex) {
           error = ex;
         }
@@ -58,19 +58,18 @@
     protected abstract IStorableContent LoadContent(string filename);
 
-    public static void Save(IStorableContent content, string filename, bool compressed) {
+    public static void Save(IStorableContent content, string filename, bool compressed, CancellationToken cancellationToken = default(CancellationToken)) {
       if (instance == null) throw new InvalidOperationException("ContentManager is not initialized.");
-      instance.SaveContent(content, filename, compressed);
+      instance.SaveContent(content, filename, compressed, cancellationToken);
       content.Filename = filename;
     }
-    public static void SaveAsync(IStorableContent content, string filename, bool compressed, Action<IStorableContent, Exception> savingCompletedCallback) {
+    public static void SaveAsync(IStorableContent content, string filename, bool compressed, Action<IStorableContent, Exception> savingCompletedCallback, CancellationToken cancellationToken = default(CancellationToken)) {
       if (instance == null) throw new InvalidOperationException("ContentManager is not initialized.");
-      var action = new Action<IStorableContent, string, bool>(instance.SaveContent);
-      action.BeginInvoke(content, filename, compressed, delegate(IAsyncResult result) {
+      var action = new Action<IStorableContent, string, bool, CancellationToken>(instance.SaveContent);
+      action.BeginInvoke(content, filename, compressed, cancellationToken, delegate (IAsyncResult result) {
         Exception error = null;
         try {
           action.EndInvoke(result);
           content.Filename = filename;
-        }
-        catch (Exception ex) {
+        } catch (Exception ex) {
           error = ex;
         }
@@ -79,5 +78,5 @@
 
     }
-    protected abstract void SaveContent(IStorableContent content, string filename, bool compressed);
+    protected abstract void SaveContent(IStorableContent content, string filename, bool compressed, CancellationToken cancellationToken);
   }
 }
Index: /stable/HeuristicLab.Core/3.3/PersistenceContentManager.cs
===================================================================
--- /stable/HeuristicLab.Core/3.3/PersistenceContentManager.cs	(revision 17067)
+++ /stable/HeuristicLab.Core/3.3/PersistenceContentManager.cs	(revision 17068)
@@ -21,4 +21,5 @@
 
 using System.IO.Compression;
+using System.Threading;
 using HeuristicLab.Common;
 using HeuristicLab.Persistence.Default.Xml;
@@ -32,6 +33,6 @@
     }
 
-    protected override void SaveContent(IStorableContent content, string filename, bool compressed) {
-      XmlGenerator.Serialize(content, filename, compressed ? CompressionLevel.Optimal : CompressionLevel.NoCompression);
+    protected override void SaveContent(IStorableContent content, string filename, bool compressed, CancellationToken cancellationToken) {
+      XmlGenerator.Serialize(content, filename, compressed ? CompressionLevel.Optimal : CompressionLevel.NoCompression, cancellationToken);
     }
   }
Index: /stable/HeuristicLab.Optimizer/3.3/FileManager.cs
===================================================================
--- /stable/HeuristicLab.Optimizer/3.3/FileManager.cs	(revision 17067)
+++ /stable/HeuristicLab.Optimizer/3.3/FileManager.cs	(revision 17068)
@@ -23,4 +23,5 @@
 using System.Collections.Generic;
 using System.IO;
+using System.Threading;
 using System.Windows.Forms;
 using HeuristicLab.Common;
@@ -98,6 +99,7 @@
         else {
           MainFormManager.GetMainForm<HeuristicLab.MainForm.WindowsForms.MainForm>().SetAppStartingCursor();
-          SetSaveOperationProgressInContentViews(content, true);
-          ContentManager.SaveAsync(content, content.Filename, true, SavingCompleted);
+          var cancellationTokenSource = new CancellationTokenSource();
+          AddProgressInContentViews(content, cancellationTokenSource);
+          ContentManager.SaveAsync(content, content.Filename, true, SavingCompleted, cancellationTokenSource.Token);
         }
       }
@@ -130,10 +132,9 @@
         if (saveFileDialog.ShowDialog() == DialogResult.OK) {
           MainFormManager.GetMainForm<HeuristicLab.MainForm.WindowsForms.MainForm>().SetAppStartingCursor();
-          SetSaveOperationProgressInContentViews(content, true, saveFileDialog.FileName);
-          if (saveFileDialog.FilterIndex == 1) {
-            ContentManager.SaveAsync(content, saveFileDialog.FileName, false, SavingCompleted);
-          } else {
-            ContentManager.SaveAsync(content, saveFileDialog.FileName, true, SavingCompleted);
-          }
+          bool compressed = saveFileDialog.FilterIndex != 1;
+          var cancellationTokenSource = new CancellationTokenSource();
+          AddProgressInContentViews(content, cancellationTokenSource, saveFileDialog.FileName);
+
+          ContentManager.SaveAsync(content, saveFileDialog.FileName, compressed, SavingCompleted, cancellationTokenSource.Token);
         }
       }
@@ -143,23 +144,16 @@
         if (error != null) throw error;
         MainFormManager.GetMainForm<HeuristicLab.MainForm.WindowsForms.MainForm>().UpdateTitle();
+      } catch (OperationCanceledException) { // do nothing if canceled
       } catch (Exception ex) {
         ErrorHandling.ShowErrorDialog((Control)MainFormManager.MainForm, "Cannot save file.", ex);
       } finally {
-        SetSaveOperationProgressInContentViews(content, false);
+        Progress.Hide(content);
         MainFormManager.GetMainForm<HeuristicLab.MainForm.WindowsForms.MainForm>().ResetAppStartingCursor();
       }
     }
 
-    private static void SetSaveOperationProgressInContentViews(IStorableContent content, bool showProgress, string fileName = null) {
-      HeuristicLab.MainForm.WindowsForms.MainForm mainForm = MainFormManager.GetMainForm<HeuristicLab.MainForm.WindowsForms.MainForm>();
-      #region Mono Compatibility
-      // removed the InvokeRequired check because of Mono
-      mainForm.Invoke((Action)delegate {
-        if (showProgress) {
-          Progress.Show(content, string.Format("Saving to file \"{0}\"...", Path.GetFileName(fileName ?? content.Filename)));
-        } else
-          Progress.Hide(content);
-      });
-      #endregion
+    private static void AddProgressInContentViews(IStorableContent content, CancellationTokenSource cancellationTokenSource, string fileName = null) {
+      string message = string.Format("Saving to file \"{0}\"...", Path.GetFileName(fileName ?? content.Filename));
+      Progress.Show(content, message, ProgressMode.Indeterminate, cancelRequestHandler: () => cancellationTokenSource.Cancel());
     }
   }
Index: /stable/HeuristicLab.Persistence/3.3/Default/Xml/XmlGenerator.cs
===================================================================
--- /stable/HeuristicLab.Persistence/3.3/Default/Xml/XmlGenerator.cs	(revision 17067)
+++ /stable/HeuristicLab.Persistence/3.3/Default/Xml/XmlGenerator.cs	(revision 17068)
@@ -26,4 +26,5 @@
 using System.Linq;
 using System.Text;
+using System.Threading;
 using HeuristicLab.Persistence.Core;
 using HeuristicLab.Persistence.Core.Tokens;
@@ -61,5 +62,5 @@
     }
 
-    protected enum NodeType { Start, End, Inline } ;
+    protected enum NodeType { Start, End, Inline };
 
     protected static void AddXmlTagContent(StringBuilder sb, string name, Dictionary<string, string> attributes) {
@@ -256,6 +257,5 @@
           {"typeName", lastTypeToken.TypeName },
           {"serializer", lastTypeToken.Serializer }});
-      }
-      finally {
+      } finally {
         lastTypeToken = null;
       }
@@ -284,6 +284,6 @@
     /// <param name="o">The object.</param>
     /// <param name="filename">The filename.</param>
-    public static void Serialize(object o, string filename) {
-      Serialize(o, filename, ConfigurationService.Instance.GetConfiguration(new XmlFormat()), false, CompressionLevel.Optimal);
+    public static void Serialize(object o, string filename, CancellationToken cancellationToken = default(CancellationToken)) {
+      Serialize(o, filename, ConfigurationService.Instance.GetConfiguration(new XmlFormat()), false, CompressionLevel.Optimal, cancellationToken);
     }
 
@@ -296,6 +296,6 @@
     /// <param name="filename">The filename.</param>
     /// <param name="compression">ZIP file compression level</param>
-    public static void Serialize(object o, string filename, CompressionLevel compression) {
-      Serialize(o, filename, ConfigurationService.Instance.GetConfiguration(new XmlFormat()), false, compression);
+    public static void Serialize(object o, string filename, CompressionLevel compression, CancellationToken cancellationToken = default(CancellationToken)) {
+      Serialize(o, filename, ConfigurationService.Instance.GetConfiguration(new XmlFormat()), false, compression, cancellationToken);
     }
 
@@ -307,16 +307,16 @@
     /// <param name="filename">The filename.</param>
     /// <param name="config">The configuration.</param>
-    public static void Serialize(object obj, string filename, Configuration config) {
-      Serialize(obj, filename, config, false, CompressionLevel.Optimal);
-    }
-
-    private static void Serialize(object obj, Stream stream, Configuration config, bool includeAssemblies
-   , CompressionLevel compression) {
+    public static void Serialize(object obj, string filename, Configuration config, CancellationToken cancellationToken = default(CancellationToken)) {
+      Serialize(obj, filename, config, false, CompressionLevel.Optimal, cancellationToken);
+    }
+
+    private static void Serialize(object obj, Stream stream, Configuration config, bool includeAssemblies, CompressionLevel compression, CancellationToken cancellationToken = default(CancellationToken)) {
       Serializer serializer = new Serializer(obj, config);
-      Serialize(stream, includeAssemblies, compression, serializer);
-    }
-
-    private static void Serialize(Stream stream, bool includeAssemblies, CompressionLevel compression, Serializer serializer) {
+      Serialize(stream, includeAssemblies, compression, serializer, cancellationToken);
+    }
+
+    private static void Serialize(Stream stream, bool includeAssemblies, CompressionLevel compression, Serializer serializer, CancellationToken cancellationToken = default(CancellationToken)) {
       try {
+        cancellationToken.ThrowIfCancellationRequested();
         DateTime start = DateTime.Now;
         serializer.InterleaveTypeInformation = false;
@@ -326,4 +326,5 @@
           using (StreamWriter writer = new StreamWriter(entry.Open())) {
             foreach (ISerializationToken token in serializer) {
+              cancellationToken.ThrowIfCancellationRequested();
               string line = generator.Format(token);
               writer.Write(line);
@@ -338,4 +339,5 @@
           if (includeAssemblies) {
             foreach (string name in serializer.RequiredFiles) {
+              cancellationToken.ThrowIfCancellationRequested();
               Uri uri = new Uri(name);
               if (!uri.IsFile) {
@@ -348,4 +350,5 @@
                   byte[] buffer = new byte[1024 * 1024];
                   while (true) {
+                    cancellationToken.ThrowIfCancellationRequested();
                     int bytesRead = reader.Read(buffer, 0, 1024 * 1024);
                     if (bytesRead == 0)
@@ -360,6 +363,5 @@
         Logger.Info(String.Format("serialization took {0} seconds with compression level {1}",
           (DateTime.Now - start).TotalSeconds, compression));
-      }
-      catch (Exception) {
+      } catch (Exception) {
         Logger.Warn("Exception caught, no data has been serialized.");
         throw;
@@ -375,18 +377,20 @@
     /// <param name="includeAssemblies">if set to <c>true</c> include needed assemblies.</param>
     /// <param name="compression">The ZIP compression level.</param>
-    public static void Serialize(object obj, string filename, Configuration config, bool includeAssemblies, CompressionLevel compression) {
+    public static void Serialize(object obj, string filename, Configuration config, bool includeAssemblies, CompressionLevel compression, CancellationToken cancellationToken = default(CancellationToken)) {
+      string tempfile = null;
       try {
-        string tempfile = Path.GetTempFileName();
+        tempfile = Path.GetTempFileName();
 
         using (FileStream stream = File.Create(tempfile)) {
-          Serialize(obj, stream, config, includeAssemblies, compression);
-        }
-
+          Serialize(obj, stream, config, includeAssemblies, compression, cancellationToken);
+        }
+        // copy only if needed
         File.Copy(tempfile, filename, true);
-        File.Delete(tempfile);
-      }
-      catch (Exception) {
+      } catch (Exception) {
         Logger.Warn("Exception caught, no data has been written.");
         throw;
+      } finally {
+        if (tempfile != null && File.Exists(tempfile))
+          File.Delete(tempfile);
       }
     }
@@ -399,6 +403,6 @@
     /// <param name="stream">The stream.</param>
     /// <param name="compressionType">Type of compression, default is GZip.</param>
-    public static void Serialize(object obj, Stream stream, CompressionType compressionType = CompressionType.GZip) {
-      Serialize(obj, stream, ConfigurationService.Instance.GetConfiguration(new XmlFormat()), compressionType);
+    public static void Serialize(object obj, Stream stream, CompressionType compressionType = CompressionType.GZip, CancellationToken cancellationToken = default(CancellationToken)) {
+      Serialize(obj, stream, ConfigurationService.Instance.GetConfiguration(new XmlFormat()), compressionType, cancellationToken);
     }
 
@@ -411,6 +415,6 @@
     /// <param name="config">The configuration.</param>
     /// <param name="compressionType">Type of compression, default is GZip.</param>
-    public static void Serialize(object obj, Stream stream, Configuration config, CompressionType compressionType = CompressionType.GZip) {
-      Serialize(obj, stream, config, false, compressionType);
+    public static void Serialize(object obj, Stream stream, Configuration config, CompressionType compressionType = CompressionType.GZip, CancellationToken cancellationToken = default(CancellationToken)) {
+      Serialize(obj, stream, config, false, compressionType, cancellationToken);
     }
 
@@ -423,18 +427,15 @@
     /// <param name="includeAssemblies">if set to <c>true</c> include need assemblies.</param>
     /// <param name="compressionType">Type of compression, default is GZip.</param>
-    public static void Serialize(object obj, Stream stream, Configuration config, bool includeAssemblies,
-                                 CompressionType compressionType = CompressionType.GZip) {
+    public static void Serialize(object obj, Stream stream, Configuration config, bool includeAssemblies, CompressionType compressionType = CompressionType.GZip, CancellationToken cancellationToken = default(CancellationToken)) {
       try {
         Serializer serializer = new Serializer(obj, config);
         if (compressionType == CompressionType.Zip) {
-          Serialize(obj, stream, config, includeAssemblies, CompressionLevel.Optimal);
+          Serialize(obj, stream, config, includeAssemblies, CompressionLevel.Optimal, cancellationToken);
         } else {
-          Serialize(stream, serializer);
-        }
-      }
-      catch (PersistenceException) {
+          Serialize(stream, serializer, cancellationToken);
+        }
+      } catch (PersistenceException) {
         throw;
-      }
-      catch (Exception e) {
+      } catch (Exception e) {
         throw new PersistenceException("Unexpected exception during Serialization.", e);
       }
@@ -451,27 +452,27 @@
     /// <param name="compressionType">Type of compression, default is GZip.</param>
     public static void Serialize(object obj, Stream stream, Configuration config, bool includeAssemblies, out IEnumerable<Type> types,
-                                 CompressionType compressionType = CompressionType.GZip) {
+                                 CompressionType compressionType = CompressionType.GZip, CancellationToken cancellationToken = default(CancellationToken)) {
       try {
         Serializer serializer = new Serializer(obj, config);
         if (compressionType == CompressionType.Zip) {
-          Serialize(stream, includeAssemblies, CompressionLevel.Optimal, serializer);
+          Serialize(stream, includeAssemblies, CompressionLevel.Optimal, serializer, cancellationToken);
         } else {
-          Serialize(stream, serializer);
+          Serialize(stream, serializer, cancellationToken);
         }
         types = serializer.SerializedTypes;
-      }
-      catch (PersistenceException) {
+      } catch (PersistenceException) {
         throw;
-      }
-      catch (Exception e) {
+      } catch (Exception e) {
         throw new PersistenceException("Unexpected exception during Serialization.", e);
       }
     }
 
-    private static void Serialize(Stream stream, Serializer serializer) {
+    private static void Serialize(Stream stream, Serializer serializer, CancellationToken cancellationToken = default(CancellationToken)) {
+      cancellationToken.ThrowIfCancellationRequested();
       using (StreamWriter writer = new StreamWriter(new GZipStream(stream, CompressionMode.Compress))) {
         serializer.InterleaveTypeInformation = true;
         XmlGenerator generator = new XmlGenerator();
         foreach (ISerializationToken token in serializer) {
+          cancellationToken.ThrowIfCancellationRequested();
           string line = generator.Format(token);
           writer.Write(line);
