Login | Register   
Twitter
RSS Feed
Download our iPhone app
TODAY'S HEADLINES  |   ARTICLE ARCHIVE  |   FORUMS  |   TIP BANK
Browse DevX
Sign up for e-mail newsletters from DevX


advertisement
 

Using LINQ to Manage File Resources and Context Menus : Page 4

LINQ queries simplify deep introspections of control collections to help manage embedded file resources and context menu initialization.


advertisement

The ResourceMgr.ResetResources Method

The static ResourceMgr.ResetResources method invoked by some instances of the IResourceUser.ResetResources method is the final piece of code needed to complete the picture. It attempts to delete all the files matching the filePattern supplied in the subdirectory of Application Data named for the currently running application. Even if two different applications use the same library on the same machine, each will have its own copies of externalized file resources, so there is no contention or confusion between applications. The method adds any files that it fails to delete to the returned collection, but with an error indicator prefix and a suffix indicating why it failed. The resetResources flag, as mentioned earlier, is so that only one instance of any class will execute the main code. Any subsequent attempts will be blocked by the gatekeeper flag. Here's the code:

public static Collection<string> ResetResources( string filePattern, ref Boolean resetResources) { Collection<string> names = new Collection<string>(); if (!resetResources) { resetResources = true; // flag that it has been done string appDirName = ApplicationSpecificApplicationData(); string[] fileList; try { fileList = Directory.GetFiles(appDirName, filePattern); } catch (DirectoryNotFoundException) { fileList = new string[] { }; } catch (PathTooLongException) { fileList = new string[] { }; } foreach (var fileName in fileList) { FileInfo fileInfo = new FileInfo(fileName); try { fileInfo.Delete(); names.Add(fileInfo.Name); } catch (Exception e) { names.Add("*** " + fileInfo.Name + ": " + e.Message); } } } return names; } public static string ApplicationSpecificApplicationData() { return Path.Combine( Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), Path.GetFileNameWithoutExtension(Application.ExecutablePath)); }

That completes the discussion of how to purge resource files generically when a new application version runs. The next section examines the second part of the algorithm: regenerating the necessary resource files.

The ResourceMgr.InstantiateResource Method

Typically, the InstantiateResource method is all you need to generate or regenerate a resource file stored in the exe or dll. As an example, consider the QueryPicker control from the CleanCodeControls library, which contains a resource file named QueryLibrary. The control calls InstantiateResource to create the file when it does not exist. The call returns the full path and name of the externalized file, ready for use:

string fileName = ResourceMgr.InstantiateResource( "QueryLibrary.xml", Properties.Resources.QueryLibrary);

The code for the InstantiateResource method is relatively simple: it generates the full path name, checks whether the file exists, and if not, creates the new file, writes the passed-in contents, and returns the full name:



public static string InstantiateResource(string fileName, string resourceText) { string appDirName = ApplicationSpecificApplicationData(); string fullName = Path.Combine(appDirName, fileName); if (!File.Exists(fullName)) { try { DirectoryInfo appDirInfo = new DirectoryInfo(appDirName); if (!appDirInfo.Exists) { appDirInfo.Create(); } File.WriteAllText(fullName, resourceText); } catch (Exception) { /* no action */ } } return fullName; }

Storing a File as a Resource

 
Figure 4. Packaging a File Resource: The figure shows the steps to embed a file resource in your application.
Figure 4 shows the steps to include a file resource into your application (.exe) or library (.dll). First, open the properties editor (1) from the Solution Explorer. Select the Resources page (2). In the resource type drop-down (3) select files. In the Add Resource drop-down select Add Existing File (4). Select the file you wish to include (5). The file is added to the canvas as a resource (6).

The only remaining piece you need to know to use embedded resource files is how to store one in your executable in the first place. Note that you may attach resources to your Visual Studio project whether it is an executable (EXE) or a library (DLL). The techniques for handling such resources are identical in either case. There are several different types of resources that Visual Studio knows about, but for this discussion the file resource is the only one of interest.

Open the Resources page of the properties editor in Visual Studio. The Resources page defaults to showing image resources on the canvas. Switch to the collection of file resources using the resource type drop-down selector. The canvas then shows any file resources in your project, and you may add or delete additional file resources. Visual Studio derives new resources names from the name of the file you selected, converted to a valid identifier name. Typically this is just the file name without the extension; however, the domain of valid characters for file names is slightly larger than the domain of identifier characters, so some characters may be either deleted or mapped. In Figure 4, which illustrates the entire procedure, the example file name Context-Oracle.xml gets mapped to Context_Oracle. Note that the hyphen in the file name gets mapped to an underscore in the resource name.

Whenever you add a resource, Visual Studio generates backing code so that you can access the resource from your application via the Properties.Resources class. Continuing the example in Figure 4, you would use the expression Properties.Resources.Context_Oracle to access the resource. That expression returns the contents of the original file. The previous section shows an example of using a file resource such as this in the call to InstantiateResource.

Dynamic Resource Lookup

The previous section described how to use file resources when you can hardwire the resource name a priori. As an added bonus, this section describes how to dynamically access a resource when the name is not specified in advance. That is, instead of using code like this (as was shown from the QueryPicker control)...

string fileName = ResourceMgr.InstantiateResource( "QueryLibrary.xml", Properties.Resources.QueryLibrary);

... you could use code like this (drawn from the ChameleonRichTextBox control):

string filename = ResourceMgr.InstantiateResource( string.Format(CONTEXT_FILE_FORMAT, contextName), GetResourceText(contextName));

The ChameleonRichTextBox control manages a set of file resources; a user's choice from this set is stored in the contextName variable. That value is passed to its private GetResourceText method to dynamically grab the resource associated with that particular name:

private string GetResourceText(string contextName) { ResourceManager rManager = new ResourceManager( "CleanCodeControls.Properties.Resources", typeof(CleanCodeControls.Properties.Resources).Assembly); string context = rManager.GetString( string.Format(CONTEXT_RESOURCE_FORMAT, contextName), CultureInfo.CurrentCulture); if (context == null) { throw new ArgumentException("resource not found"); } return context; }

The code fragments above rely on these constants to map the user's input to both a file name and a resource name. Compare these formatting templates to the names shown in Figure 4 to see how they match up:

private const string CONTEXT_FILE_FORMAT = "Context-{0}.xml"; private const string CONTEXT_RESOURCE_FORMAT = "Context_{0}";



Comment and Contribute

 

 

 

 

 


(Maximum characters: 1200). You have 1200 characters left.

 

 

Sitemap