I am trying to save the MDI state when closing the application and load it when opening. Like FireFox, it opens all the web pages last time when you close the application. I've noticed that UltraTabbedMdiManager have methods like SaveAsXml and LoadFromXml.What is contained in the saved XML file?
What do I need to do if I want to open the last visited pages like FireFox? Thanks.Mike
The XML file will contain all properties and values which are publicly exposed in the tabbed mdi manager. It is intended to save customizations the user might have made, through both the default UI, as well as any additional UI you have added to your application to give the user control over certain aspects of the tabbed mdi manager. One of the reasons to save and load this file would be to maintain the tab groups into which the user has organized the mdi child forms. However, loading the XML file will not open the forms which were previously opened. You must keep track of which forms were open when the XML file was saved and re-open them before loading the XML file.
>You must keep track of which forms were open when the XML file was saved and re-open them before loading the XML file.
So i guess i should save the open forms into a separate file, instead of messing this XML file.
In fact, all I want to save for each form is the file name to initialize it. Is it possible to tag objects (e.g., the list of file names in this case) to the UltraTabbedMdiManager? Is it worth doing that?
>to maintain the tab groups into which the user has organized the mdi child formsThe only think i can think of is to switch between normal MDI and tabbed MDI. Anything else user acn do to organize child forms?Thanks!
I must apologize: I was thinking about how the dock manager loads the layout and I assumed the tabbed mdi manager worked the same way, so I am sorry for giving bad advice. I have checked with someone more familiar with this component, and there are properties and events built in specifically for what you are trying to do. Handle the StoreTab event on the tabbed mdi manager. When a tab is going to be serialized to the XML file, this event will be fired for each tab. In your case, when you handle this event, set the PersistedInfo of the tab for which the event is being fired to the file name associated with the tab. For deserialization, handle the RestoreTab event. This event will be fired for each tab which was serialized. In the handler, you can get the PersistedInfo for the tab and create a Form (or use an existing Form) to use for the tab. Set the Form on the Form property of the event arguments.
Another question: Our application uses different managers (Toolbar, Dock, and MDI), is it possible to save the setting in a single file instead of multiple ones.What is the industrial standard to do that?
Thanks.
Its possible, but it would need to be done manually. You could create an XML file where you store each configuration stream as a base 64 value in the file. Here is one way you could accomplish this for a toolbars manager and dock manager:
private void Form1_Load( object sender, EventArgs e ){ if ( File.Exists( "config.xml" ) == false ) return;
using ( XmlTextReader reader = new XmlTextReader( "config.xml" ) ) { reader.ReadStartElement( "Config" );
using ( MemoryStream stream = new MemoryStream( this.ReadBase64( reader ) ) ) this.ultraToolbarsManager1.LoadFromBinary( stream );
using ( MemoryStream stream = new MemoryStream( this.ReadBase64( reader ) ) ) this.ultraToolbarsManager1.LoadFromBinary( stream ); }}
private void Form1_FormClosed( object sender, FormClosedEventArgs e ){ using ( XmlTextWriter writer = new XmlTextWriter( "config.xml", Encoding.Default ) ) { writer.WriteStartElement( "Config" ); writer.WriteStartElement( "ToolbarsConfig" );
using ( MemoryStream stream = new MemoryStream() ) { this.ultraToolbarsManager1.SaveAsBinary( stream, true );
byte[ buffer = stream.GetBuffer(); writer.WriteBase64( buffer, 0, buffer.Length ); }
writer.WriteEndElement();
writer.WriteStartElement( "DockConfig" );
using ( MemoryStream stream = new MemoryStream() ) { this.ultraDockManager1.SaveAsBinary( stream );
writer.WriteEndElement(); writer.WriteEndElement(); }}
private byte[ ReadBase64( XmlTextReader reader ){ List<byte> finalBuffer = new List<byte>(); byte[ buffer = new byte[ 1000 ];
while ( true ) { int bytesRead = reader.ReadBase64( buffer, 0, buffer.Length );
if ( bytesRead < buffer.Length ) { byte[ retValue = new byte[ finalBuffer.Count + bytesRead ];
Buffer.BlockCopy( finalBuffer.ToArray(), 0, retValue, 0, finalBuffer.Count ); Buffer.BlockCopy( buffer, 0, retValue, finalBuffer.Count, bytesRead );
return retValue; } else { finalBuffer.AddRange( buffer ); } }}
Mike Dour"] private void Form1_Load( object sender, EventArgs e ){ if ( File.Exists( "config.xml" ) == false ) return; using ( XmlTextReader reader = new XmlTextReader( "config.xml" ) ) { reader.ReadStartElement( "Config" ); using ( MemoryStream stream = new MemoryStream( this.ReadBase64( reader ) ) ) this.ultraToolbarsManager1.LoadFromBinary( stream ); using ( MemoryStream stream = new MemoryStream( this.ReadBase64( reader ) ) ) this.ultraToolbarsManager1.LoadFromBinary( stream ); }}
Mike, In the above code snippet I think you meant to do something with ToolbarConfig and DockConfig since write it out at Form closure.
Mike Dour"] writer.WriteStartElement( "DockConfig" );
If you do not mind, can you add that code to snippet to help me understand how you use the stream to read individual settings
Second questoin, I want to let users to save as many settings as they like. That way they can have multiple looks and layouts pre-defined and they can change it to any of them very quickly. When they load such a setting file, I would like each control to process its own settings by firing an event. What should I be sending as part of the event to the individual control so that the control can pick it up from there? Should I make the control get the XML stream, the complete binary or something else?
Thanks!
vrn said:Mike, In the above code snippet I think you meant to do something with ToolbarConfig and DockConfig since write it out at Form closure.
My code snippet used an XmlTextReader, which just reads the nodes in order, so it did not need to specify the config file it was looking for. I could have put asserts before loading each stream to make sure the current node had the expected names before loading them.
vrn said:Second questoin, I want to let users to save as many settings as they like. That way they can have multiple looks and layouts pre-defined and they can change it to any of them very quickly. When they load such a setting file, I would like each control to process its own settings by firing an event. What should I be sending as part of the event to the individual control so that the control can pick it up from there? Should I make the control get the XML stream, the complete binary or something else?
I would send the stream loaded from the file in the event args. Then the control can just pass that to its appropriate LoadFrom... method.
vrn said:I am guessing because ReadBase64 is reading the next node and decoding it, the order of loading the controls is important? So it should be read in the same sequence that I saved it?
Yes, that is correct.
vrn said:Do you have suggestion on how I can make the loading sequence independent of the saving sequence? This can prove useful for my design where I am trying to make each component completely independent of the other. So each component should be able to figure out its own setting from the larger XML file.
Instead of using an XmlTextReader, you can try to implement something using an XmlDocument. Then each control can iterate the child nodes of the document and find the node with their stream name and just read in that node. Alternatively, you could keep the same approach and read in all streams and populate them into a Dictionary<string,Stream>, where the key is the stream name. Then when each control goes to load, they just access the dictionary with the name they are looking for.
Mike Dour"] My code snippet used an XmlTextReader, which just reads the nodes in order, so it did not need to specify the config file it was looking for. I could have put asserts before loading each stream to make sure the current node had the expected names before loading them.
Mike your code worked like a charm!
- I am guessing because ReadBase64 is reading the next node and decoding it, the order of loading the controls is important? So it should be read in the same sequence that I saved it?
- Do you have suggestion on how I can make the loading sequence independent of the saving sequence? This can prove useful for my design where I am trying to make each component completely independent of the other. So each component should be able to figure out its own setting from the larger XML file.