Reading and Writing RESX XML Files

I l @ ve RuBoard

Resource files, as we mentioned at the beginning of this chapter, come in several flavors ” .resources files and .resx files. Resx files are the raw, uncompiled XML used as a basic source form for resources. In the previous example, we showed the ResourceReader and ResourceWriter classes. There are corresponding ResXResourceReader and ResXResourceWriter classes that can be used to maintain the XML forms of the resources.

In our last example for this chapter, we've created a simple application that lets you load chosen bitmap, text, and icon files and convert these to a .RESX resource file (see Listing 3.4.8). The complexity of the task and the simplicity of this application show off some of the raw power of the Windows Forms architecture.

Listing 3.4.8 ResXUtilForm.cs: The RESX Writer Utility
 1: using System;   2: using System.Drawing;   3: using System.Collections;   4: using System.ComponentModel;   5: using System.Windows.Forms;   6: using System.Data;   7: using System.IO;   8:   9: /*  10:  * NOTES: A bug in an early version of the .NET framework caused  11:  * the program to raise an exception when the resource name is  12:  * edited. In this file there are two sections of commented code  13:  * that are designed to work around this problem  14:  * If this code fails, simply uncomment the sections marked  15:  * BUGFIXER and re-compile  16:  *  17: */  18:  19: namespace ResxUtil  20: {  21:   /// <summary>  22:   /// Summary description for Form1.  23:   /// </summary>  24:   public class ResXUtilForm : System.Windows.Forms.Form  25:   {  26:     private System.Windows.Forms.ListView listView1;  27:     private System.Windows.Forms.Button button1;  28:     private System.Windows.Forms.Button button2;  29:     private System.Windows.Forms.ImageList imageList1;  30:     private System.Windows.Forms.ColumnHeader columnHeader2;  31:     private System.Windows.Forms.ColumnHeader columnHeader1;  32:     private System.ComponentModel.IContainer components;  33:  34:     public ResXUtilForm()  35:     {  36:       //  37:       // Required for Windows Form Designer support  38:       //  39:       InitializeComponent();  40:  41:       //BUGFIXER uncomment the line below  42:       //this.listView1.LabelEdit=false;  43:     }  44:  45:     /// <summary>  46:     /// Clean up any resources being used.  47:     /// </summary>  48:     protected override void Dispose( bool disposing )  49:     {  50:       if( disposing )  51:       {  52:         if (components != null)  53:         {  54:           components.Dispose();  55:         }  56:       }  57:       base.Dispose( disposing );  58:     }  59:  60:     #region Windows Form Designer generated code  61:     /// <summary>  62:     /// Required method for Designer support - do not modify  63:     /// the contents of this method with the code editor.  64:     /// </summary>  65:     private void InitializeComponent()  66:     {  67:       this.components = new System.ComponentModel.Container();  68:       System.Resources.ResourceManager resources = new graphics/ccc.gif System.Resources.ResourceManager(typeof(ResXUtilForm));  69:       this.columnHeader2 = new System.Windows.Forms.ColumnHeader();  70:       this.columnHeader1 = new System.Windows.Forms.ColumnHeader();  71:       this.imageList1 = new System.Windows.Forms.ImageList(this.components);  72:       this.listView1 = new System.Windows.Forms.ListView();  73:       this.button1 = new System.Windows.Forms.Button();  74:       this.button2 = new System.Windows.Forms.Button();  75:       this.SuspendLayout();  76:       //  77:       // columnHeader2  78:       //  79:       this.columnHeader2.Text = "File name";  80:       this.columnHeader2.Width = 545;  81:       //  82:       // columnHeader1  83:       //  84:       this.columnHeader1.Text = "Resource name";  85:       this.columnHeader1.Width = 220;  86:       //  87:       // imageList1  88:       //  89:       this.imageList1.ColorDepth = System.Windows.Forms.ColorDepth.Depth8Bit;  90:       this.imageList1.ImageSize = new System.Drawing.Size(16, 16);  91:       this.imageList1.ImageStream = ((System.Windows.Forms.ImageListStreamer) graphics/ccc.gif (resources.GetObject("imageList1.ImageStream")));  92:       this.imageList1.TransparentColor = System.Drawing.Color.Magenta;  93:       //  94:       // listView1  95:       //  96:       this.listView1.Anchor = ((System.Windows.Forms.AnchorStyles.Top graphics/ccc.gif System.Windows.Forms.AnchorStyles.Left)  97:          System.Windows.Forms.AnchorStyles.Right);  98:       this.listView1.Columns.AddRange( new System.Windows.Forms.ColumnHeader[] {  99:                                             this.columnHeader1, 100:                                             this.columnHeader2} ); 101:       this.listView1.FullRowSelect = true; 102:       this.listView1.Location = new System.Drawing.Point(8, 8); 103:       this.listView1.Name = "listView1"; 104:       this.listView1.Size = new System.Drawing.Size(792, 304); 105:       this.listView1.SmallImageList = this.imageList1; 106:       this.listView1.TabIndex = 0; 107:       this.listView1.View = System.Windows.Forms.View.Details; 108:       this.listView1.KeyDown += new graphics/ccc.gif System.Windows.Forms.KeyEventHandler(this.listView1_KeyDown); 109:       this.listView1.LabelEdit=true; 110:       // 111:       // button1 112:       // 113:       this.button1.Location = new System.Drawing.Point(696, 328); 114:       this.button1.Name = "button1"; 115:       this.button1.Size = new System.Drawing.Size(104, 32); 116:       this.button1.TabIndex = 1; 117:       this.button1.Text = "Save"; 118:       this.button1.Click += new System.EventHandler(this.button1_Click); 119:       // 120:       // button2 121:       // 122:       this.button2.Location = new System.Drawing.Point(8, 328); 123:       this.button2.Name = "button2"; 124:       this.button2.Size = new System.Drawing.Size(88, 32); 125:       this.button2.TabIndex = 2; 126:       this.button2.Text = "Add..."; 127:       this.button2.Click += new System.EventHandler(this.button2_Click); 128:       //  129:       // ResXUtilForm 130:       // 131:       this.AllowDrop = true; 132:       this.AutoScaleBaseSize = new System.Drawing.Size(5, 13); 133:       this.ClientSize = new System.Drawing.Size(816, 373); 134:       this.Controls.AddRange(new System.Windows.Forms.Control[] { 135:                                       this.button2, 136:                                       this.button1, 137:                                       this.listView1} ); 138:       this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog; 139:       this.Name = "ResXUtilForm"; 140:       this.Text = "ResX Utility"; 141:       this.ResumeLayout(false); 142: 143:     } 144:     #endregion 145: 146:     /// <summary> 147:     /// The main entry point for the application. 148:     /// </summary> 149:     [STAThread] 150:     static void Main() 151:     { 152:       Application.Run(new ResXUtilForm()); 153:     } 154: 155:     private void button2_Click(object sender, System.EventArgs e) 156:     { 157:       int icon=-1; 158:       OpenFileDialog dlg=new OpenFileDialog(); 159:       if(dlg.ShowDialog()==DialogResult.OK) 160:       { 161:         string s=dlg.FileName; 162:         string[] d=s.Split(new char[]{ '.'} ); 163:         string resname="Unidentified"; 164: 165:         if(d.Length<2) 166:           return; 167: 168:         switch(d[d.Length-1].ToLower()) 169:         { 170:           case "bmp": 171:             icon=0; 172:             break; 173:           case "txt": 174:             icon=1; 175:             break; 176:           case "ico": 177:             icon=2; 178:             break; 179:         } 180: 181: 182:         //BUGFIXER remove comment block tags from the 183:         //code below. 184:         /*Form f=new Form(); 185:         f.Size=new Size(350,110); 186:         f.Text="Resource name"; 187:         f.FormBorderStyle=FormBorderStyle.FixedDialog; 188:         Button ok=new Button(); 189:         ok.DialogResult=DialogResult.OK; 190:         ok.Location=new Point(5,32); 191:         ok.Size=new Size(75,22); 192:         ok.Text="Ok"; 193:         f.Controls.Add(ok); 194:         Button can=new Button(); 195:         can.DialogResult=DialogResult.Cancel; 196:         can.Location=new Point(260,32); 197:         can.Size=new Size(75,22); 198:         can.Text="Cancel"; 199:         f.Controls.Add(can); 200:         TextBox tb=new TextBox(); 201:         tb.Location=new Point(5,5); 202:         tb.Size=new Size(330,25); 203:         tb.Text="Resource"+ 204:           ((object)(this.listView1.Items.Count+1)).ToString(); 205:         f.Controls.Add(tb); 206:         if(f.ShowDialog()==DialogResult.Cancel  tb.Text.Trim() == "") 207:           return; 208:         resname=tb.Text.Trim(); 209:         */ 210: 211: 212:         if(icon>=0) 213:         { 214:           ListViewItem item=new ListViewItem(resname,icon); 215:           item.SubItems.Add(s); 216:           this.listView1.Items.Add(item); 217:         } 218:       } 219:     } 220: 221:     private void button1_Click(object sender, System.EventArgs e) 222:     { 223:       if(this.listView1.Items.Count>0) 224:       { 225:         //Check that all resources have a name 226:         foreach(ListViewItem item in this.listView1.Items) 227:         { 228:           if(item.Text=="Undefined") 229:           { 230:             MessageBox.Show("All resources must have names"); 231:             return; 232:           } 233:         } 234: 235:         //Fetch the filename for the resx file 236:         SaveFileDialog dlg=new SaveFileDialog(); 237:         dlg.Title="Save .resx file"; 238:         dlg.Filter="XML resource files.resx"; 239:         if(dlg.ShowDialog()==DialogResult.Cancel) 240:           return; 241: 242:         //Create a resource writer 243:         System.Resources.ResXResourceWriter rw= 244:           new System.Resources.ResXResourceWriter(dlg.FileName); 245: 246:         //Step through the items on the list 247:         foreach(ListViewItem item in this.listView1.Items) 248:         { 249:           switch(item.ImageIndex) 250:           { 251:             case 0: // bitmap images 252:               goto case 2; 253:             case 1: // text files 254:               System.IO.StreamReader sr= 255:                 new System.IO.StreamReader( 256:                   item.SubItems[1].Text); 257:               string inputline; 258:               do 259:               { 260:                 inputline = sr.ReadLine(); 261:                 if(inputline != null) 262:                 { 263:                   string[] splitline= 264:                     inputline.Split(new char[]{ '='} ,2); 265:                   if(splitline.Length==2) 266:                   { 267:                     rw.AddResource( 268:                     item.Text.TrimEnd().TrimStart()+ 269:                     "."+ 270:                     splitline[0].TrimEnd().TrimStart(), 271:                     splitline[1]); 272:                   } 273:                 } 274:               } 275:               while(inputline!=null); 276:               break; 277:             case 2: // icons 278:               System.Drawing.Image im= 279:                 System.Drawing.Image.FromFile( 280:                 item.SubItems[1].Text); 281:               rw.AddResource(item.Text,im); 282:               break; 283:           } 284:         } 285: 286:         rw.Generate(); 287:         rw.Close(); 288:       } 289:     } 290: 291: 292:     private void listView1_KeyDown(object sender, 293:             System.Windows.Forms.KeyEventArgs e) 294:     { 295:       if(this.listView1.SelectedIndices.Count==0) 296:         return; 297:       if(e.KeyCode.Equals(Keys.Delete)) 298:         this.listView1.Items.RemoveAt( 299:           this.listView1.SelectedIndices[0]); 300:     } 301:   } 302: 303: } 

NOTE

Be aware that the style of layout in this and other listings has been modified to fit an 80 column format. In particular, the InitializeComponent method has been modified from its original form. If you download the file from the Sams Web site, it might differ slightly in layout, but it will be functionally identical.


By now, you should be able to go through the InitializeComponent and understand what's happening, so we'll just pick out highlights of the application.

Lines 79 “80 create a set of column headers used when the ListView is in Detail mode to provide headers for each column of information. We have chosen to display the item icon from an ImageList plus the name of the resource, which you must choose, along with the full filename of the source resource.

Lines 89 “92 set up the ImageList , bringing in the image stream and setting up sizes and transparent color and so on.

Lines 98 “100 add the column headers to the list view control. Lines 93 “104 set the properties of the ListView to enable row selection (so you can delete an object from the list), label editing (which lets you name your resource, locations, and sizes for the control), and finally, the KeyDown handler (which only responds to the Delete key).

Lines 110 “128 are the buttons . One adds a resource, the other saves the RESX file.

Lines 155 “219 handle the Add button. This allows you to browse files (lines 154 and 155) for bitmaps, text, or icons. After you find a resource candidate, lines 168 “179 decide whether it's a file we care about and select the correct icon. Finally, lines 212 “217 use the icon selection to create a ListViewItem that has a label (at first "Undefined") and a sub-item that populates the second column of the list control with the filename.

The Save button on lines 221 “284 does a quick check to see if all the resources have been named (lines 226 “233) and then gets a filename for the target file (lines 236 “240). Lines 243 “244 make a new ResXResourceWriter and then pass it into a foreach loop that goes through item by item and creates the resources.

The switch statement (line 249) has three cases. Cases 0 and 2 are handled the same way because, for the XML format, there is no distinction between a bitmap and an icon. Case 1 (lines 254 “276) reads in the text file one line at a time and separates the lines into the name-value pairs used to create each text resource. The name is prefixed with the name you chose for the text file in the listbox. Note that this demonstration only understands text files with the "< name string >=< value string >" syntax. Other files are likely to give errors. After processing is done, lines 286 and 287 write and close the RESX file.

Finally, lines 292 “300 handle the Delete key presses and remove items from the list if you want.

A Note about Bugs

Line 42 and the block of code on lines 184 “208 are a contingency plan that solves a potential problem with an early version of the .NET framework. If you edit the resource name and the program crashes, uncomment the two sections of code in the lines marked "BUGFIXER" and recompile the program. It will work in a slightly different way, and it will not crash.

Notice also how the bugfix code creates a dialog box on-the-fly for you.

NOTE

For applications built with Visual Studio, the complete solution is included as a zip archive on the Sams Web site (http://www.samspublishing.com).


I l @ ve RuBoard


C# and the .NET Framework. The C++ Perspective
C# and the .NET Framework
ISBN: 067232153X
EAN: 2147483647
Year: 2001
Pages: 204

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net