How to: Get a StorageDevice Asynchronously
XNA Game Studio Express
This example demonstrates how to call BeginShowStorageDeviceGuide and EndShowStorageDeviceGuide to get a StorageDevice object asynchronously.
To get a StorageDevice asynchronously using IsCompleted
- Create a variable to track when a request for a StorageDevice is pending. In this case, we declare GameSaveRequested.
- When the user needs to access the StorageDevice for the first time (for example, to save a game) call BeginShowStorageDeviceGuide, specifying which player has requested the save.
- BeginShowStorageDeviceGuide returns an IAsyncResult interface that is used to determine when the asynchronous request is finished.
- Set your tracking variable to indicate a request is pending.
- When a request is pending, check IAsyncResult.IsCompleted periodically to determine when the storage device has been selected by the user.
- When IsCompleted is true, call EndShowStorageDeviceGuide, passing the IAsyncResult provided by BeginShowStorageDeviceGuide. The return value is the selected storage device.
- Use IsConnected to ensure that a valid device was chosen (if the user declines to select a device, or the device is removed, IsConnected will be false). If the StorageDevice is connected, use it to load or save data.
- Reset your tracking variable.
// Note: Before you can build this file in a project, you must // add a reference to System.xml. To to this, right-click // on References in Solution Explorer and click Add Reference. // In the .NET pane, scroll down and select System.Xml. using System; using System.Collections.Generic; using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Graphics; using Microsoft.Xna.Framework.Input; using Microsoft.Xna.Framework.Storage; using System.IO; using System.Xml.Serialization; IAsyncResult result; Object stateobj; bool GameSaveRequested = false; protected override void Update( GameTime gameTime ) { // Allows the default game to exit on Xbox 360 and Windows if (GamePad.GetState( PlayerIndex.One ).Buttons.Back == ButtonState.Pressed) this.Exit(); if (GamePad.GetState( PlayerIndex.One ).Buttons.A == ButtonState.Pressed) { // Set the request flag GameSaveRequested = true; result = StorageDevice.BeginShowStorageDeviceGuide( PlayerIndex.One, null, null ); } // If a save is pending, save as soon as the // storage device is chosen if ((GameSaveRequested) && (result.IsCompleted)) { StorageDevice device = StorageDevice.EndShowStorageDeviceGuide( result ); if (device.IsConnected) { DoSaveGame( device ); } // Reset the request flag GameSaveRequested = false; } base.Update( gameTime ); }
To get a StorageDevice asynchronously using an AsyncCallback
- Create an AsyncCallback object that represents the method that will be called when the player chooses a device. That function must take an IAsyncResult as a parameter and return void.
- When the user needs to access the StorageDevice for the first time (for example, to save a game) call BeginShowStorageDeviceGuide, specifying which player has requested the save, and your AsyncCallback object. You may optionally pass a tracking object to identify the request (or null).
- In your callback method, call EndShowStorageDeviceGuide, passing the same IAsyncResult that was passed into the callback method. The return value is the selected storage device.
- Use IsConnected to ensure that a valid device was chosen (if the user declines to select a device, or the device is removed, IsConnected will be false). If the StorageDevice is connected, use it to load or save data.
// Note: Before you can build this file in a project, you must // add a reference to System.xml. To to this, right-click // on References in Solution Explorer and click Add Reference. // In the .NET pane, scroll down and select System.Xml. using System; using System.Collections.Generic; using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Graphics; using Microsoft.Xna.Framework.Input; using Microsoft.Xna.Framework.Storage; using System.IO; using System.Xml.Serialization; IAsyncResult result; Object stateobj; bool GameSaveRequested = false; protected override void Update( GameTime gameTime ) { // Allows the default game to exit on Xbox 360 and Windows if (GamePad.GetState( PlayerIndex.One ).Buttons.Back == ButtonState.Pressed) this.Exit(); if (GamePad.GetState( PlayerIndex.One ).Buttons.B == ButtonState.Pressed) { // Reset the device device = null; AsyncCallback ac = new AsyncCallback( this.GetDevice ); stateobj = (Object)"GetDevice for Player One"; StorageDevice.BeginShowStorageDeviceGuide( PlayerIndex.One, ac, stateobj ); } base.Update( gameTime ); } StorageDevice device; void GetDevice( IAsyncResult result ) { device = StorageDevice.EndShowStorageDeviceGuide( result ); if (device.IsConnected) { DoSaveGame( device ); } }
To get a StorageDevice asynchronously using Game.Tick and IsCompleted
- Create a variable to indicate that the Storage Device Guide is active, and set it to false.
- When a new StorageDevice is requested, set the variable to true, then call BeginShowStorageDeviceGuide. If the variable is already true, do not call BeginShowStorageDeviceGuide.
- Call Game.Tick until the IAsyncResult returned by BeginShowStorageDeviceGuide is completed.
- When IsCompleted is true, call EndShowStorageDeviceGuide, passing the IAsyncResult provided by BeginShowStorageDeviceGuide. The return value is the selected storage device.
- Use IsConnected to ensure that a valid device was chosen (if the user declines to select a device, or the device is removed, IsConnected will be false). If the StorageDevice is connected, use it to load or save data.
- Reset your tracking variable.
The Complete Example
// Note: Before you can build this file in a project, you must // add a reference to System.xml. To to this, right-click // on References in Solution Explorer and click Add Reference. // In the .NET pane, scroll down and select System.Xml. using System; using System.Collections.Generic; using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Graphics; using Microsoft.Xna.Framework.Input; using Microsoft.Xna.Framework.Storage; using System.IO; using System.Xml.Serialization; using Microsoft.Xna.Framework.Content; public class Game1 : Microsoft.Xna.Framework.Game { GraphicsDeviceManager graphics; ContentManager content; public Game1() { graphics = new GraphicsDeviceManager( this ); content = new ContentManager( Services ); } protected override void Initialize() { base.Initialize(); } protected override void LoadGraphicsContent( bool loadAllContent ) { if (loadAllContent) { // TODO: Load any ResourceManagementMode.Automatic content } } protected override void UnloadGraphicsContent( bool unloadAllContent ) { if (unloadAllContent == true) { content.Unload(); } } bool ShowingStorageDeviceGuide = false; IAsyncResult result; Object stateobj; bool GameSaveRequested = false; protected override void Update( GameTime gameTime ) { // Allows the default game to exit on Xbox 360 and Windows if (GamePad.GetState( PlayerIndex.One ).Buttons.Back == ButtonState.Pressed) this.Exit(); if (GamePad.GetState( PlayerIndex.One ).Buttons.A == ButtonState.Pressed) { // Set the request flag GameSaveRequested = true; result = StorageDevice.BeginShowStorageDeviceGuide( PlayerIndex.One, null, null ); } if (GamePad.GetState( PlayerIndex.One ).Buttons.B == ButtonState.Pressed) { // Reset the device device = null; AsyncCallback ac = new AsyncCallback( this.GetDevice ); stateobj = (Object)"GetDevice for Player One"; StorageDevice.BeginShowStorageDeviceGuide( PlayerIndex.One, ac, stateobj ); } // If a save is pending, save as soon as the // storage device is chosen if ((GameSaveRequested) && (result.IsCompleted)) { StorageDevice device = StorageDevice.EndShowStorageDeviceGuide( result ); if (device.IsConnected) { DoSaveGame( device ); DoLoadGame( device ); DoCreate( device ); DoOpen( device ); DoCopy( device ); DoEnumerate( device ); DoRename( device ); DoDelete( device ); DoOpenFile(); } // Reset the request flag GameSaveRequested = false; } if (GamePad.GetState( PlayerIndex.One ).Buttons.X == ButtonState.Pressed) { // make sure we don't call BeginShowStorageDeviceGuide when the guide // is already being shown if (!ShowingStorageDeviceGuide) { ShowingStorageDeviceGuide = true; // reset the device device = null; result = StorageDevice.BeginShowStorageDeviceGuide( PlayerIndex.One, null, null ); while (!result.IsCompleted) { // Call Update and Draw to draw the guide this.Tick(); } device = StorageDevice.EndShowStorageDeviceGuide(result); if (device.IsConnected) { DoSaveGame( device ); DoLoadGame( device ); DoCreate( device ); DoOpen( device ); DoCopy( device ); DoEnumerate( device ); DoRename( device ); DoDelete( device ); DoOpenFile(); } ShowingStorageDeviceGuide = false; } } base.Update( gameTime ); } StorageDevice device; void GetDevice( IAsyncResult result ) { device = StorageDevice.EndShowStorageDeviceGuide( result ); if (device.IsConnected) { DoSaveGame( device ); DoLoadGame( device ); DoCreate( device ); DoOpen( device ); DoCopy( device ); DoEnumerate( device ); DoRename( device ); DoDelete( device ); DoOpenFile(); } } protected override void Draw( GameTime gameTime ) { graphics.GraphicsDevice.Clear( Color.CornflowerBlue ); base.Draw( gameTime ); } [Serializable] public struct SaveGameData { public string PlayerName; public Vector2 AvatarPosition; public int Level; public int Score; } private static void DoSaveGame( StorageDevice device ) { // Create the data to save SaveGameData data = new SaveGameData(); data.PlayerName = "Hiro"; data.AvatarPosition = new Vector2( 360, 360 ); data.Level = 11; data.Score = 4200; // Open a storage container StorageContainer container = device.OpenContainer( "StorageDemo" ); // Get the path of the save game string filename = Path.Combine( container.Path, "savegame.sav" ); // Open the file, creating it if necessary FileStream stream = File.Open( filename, FileMode.OpenOrCreate ); // Convert the object to XML data and put it in the stream XmlSerializer serializer = new XmlSerializer( typeof( SaveGameData ) ); serializer.Serialize( stream, data ); // Close the file stream.Close(); // Dispose the container, to commit changes container.Dispose(); } private static void DoLoadGame( StorageDevice device ) { // Open a storage container StorageContainer container = device.OpenContainer( "StorageDemo" ); // Get the path of the save game string filename = Path.Combine( container.Path, "savegame.sav" ); // Check to see if the save exists if (!File.Exists( filename )) // Notify the user there is no save return; // Open the file FileStream stream = File.Open( filename, FileMode.OpenOrCreate, FileAccess.Read ); // Read the data from the file XmlSerializer serializer = new XmlSerializer( typeof( SaveGameData ) ); SaveGameData data = (SaveGameData)serializer.Deserialize( stream ); // Close the file stream.Close(); // Dispose the container container.Dispose(); // Report the data to the console Console.WriteLine( "Name: " + data.PlayerName ); Console.WriteLine( "Level: " + data.Level.ToString() ); Console.WriteLine( "Score: " + data.Score.ToString() ); Console.WriteLine( "Position: " + data.AvatarPosition.ToString() ); } private static void DoCreate( StorageDevice device ) { // Open a storage container StorageContainer container = device.OpenContainer( "StorageDemo" ); // Add the container path to our filename string filename = Path.Combine( container.Path, "demobinary.sav" ); // Create a new file if (!File.Exists( filename )) { FileStream file = File.Create( filename ); file.Close(); } // Dispose the container, to commit the data container.Dispose(); } private static void DoOpen( StorageDevice device ) { // Open a storage container StorageContainer container = device.OpenContainer( "StorageDemo" ); // Add the container path to our filename string filename = Path.Combine( container.Path, "demobinary.sav" ); FileStream file = File.Open( filename, FileMode.Open ); file.Close(); // Dispose the container container.Dispose(); } private static void DoCopy( StorageDevice device ) { // Open a storage container StorageContainer container = device.OpenContainer( "StorageDemo" ); // Add the container path to our filename string filename = Path.Combine( container.Path, "demobinary.sav" ); string copyfilename = Path.Combine( container.Path, "copybinary.sav" ); File.Copy( filename, copyfilename, true ); // Dispose the container, to commit the change container.Dispose(); } private static void DoRename( StorageDevice device ) { // Open a storage container StorageContainer container = device.OpenContainer( "StorageDemo" ); // Add the container path to our filename string oldfilename = Path.Combine( container.Path, "demobinary.sav" ); string newfilename = Path.Combine( container.Path, "renamebinary.sav" ); if (!File.Exists( newfilename )) File.Move( oldfilename, newfilename ); // Dispose the container, to commit the change container.Dispose(); } private static void DoEnumerate( StorageDevice device ) { // Open a storage container StorageContainer container = device.OpenContainer( "StorageDemo" ); ICollection<string> FileList = Directory.GetFiles( container.Path ); // Dispose the container container.Dispose(); } private static void DoDelete( StorageDevice device ) { // Open a storage container StorageContainer container = device.OpenContainer( "StorageDemo" ); // Add the container path to our filename string filename = Path.Combine( container.Path, "demobinary.sav" ); // Delete the new file. if (File.Exists( filename )) File.Delete( filename ); // Dispose the container, to commit the change container.Dispose(); } private static void DoOpenFile() { FileStream file = OpenTitleFile( "Sprite.dds", FileMode.Open, FileAccess.Read ); Console.WriteLine( "File Size: " + file.Length ); file.Close(); } private static FileStream OpenTitleFile( string filename, FileMode mode, FileAccess access ) { string fullpath = Path.Combine( StorageContainer.TitleLocation, filename ); return File.Open( fullpath, mode, access ); } }