I believe what you're missing is a call to Task.Run, which is what actually creates the Task that will run the operation on a separate thread and do the marshaling.
That is, your SaveSpreadsheet function says it's returning Task but doesn't actually create the Task anywhere, and is thus just returning a string. Here's the general structure of an async function in a component:
public IAsyncOperation<string> SomeMethodAsync(int id)
{
var task = Task.Run<string>(async () =>
{
var idString = await GetMyStringAsync(id);
return idString;
});
return task.AsAsyncOperation();
}
So I think you just need to change SaveSpreadsheet to return a String (which your code is doing already, so just change Task to String), and make ButtonPress look like this:
public IAsyncOperation<string> ButtonPress()
{
var task = Task.Run<string>(async () =>
{
return await SaveSpreadsheet();
});
return task.AsAsyncOperation();
}
I cover this subject, by the way, in Chapter 18 of my free ebook from MSPress, Programming Windows Store Apps with HTML, CSS, and JavaScript, 2nd Edition, http://aka.ms/BrockschmidtBook2.
P.S. If there's no reason for your component to be instantiable with new, then you can add the static keyboard to ButtonPress (i.e. public static IAsyncOperation ButtonPress()) and then just make the call with the fully-qualified name WindowsRuntimeComponent1.Class1.buttonPress().then(...). That might simplify your code.