I am currently trying to figure out how to save the content from a RichTextbox into a stream(currently using FileStream) and do this alongside a bunch of other data. Then of course I want to be able to load from this file.
I was currently trying to use something along the following lines.
FileStream stream = new FileStream(); //this is actually correctly defined.
ASCIIEncoding encoding = new ASCIIEncoding();
//write Title
byte[] array = encoding.GetBytes(Title);
stream.WriteByte(Convert.ToByte(array.Length));
stream.Write(array, 0, array.Length);
//save textRange
textRange.Save(stream, System.Windows.DataFormats.Rtf);
//write Subtitle
byte[] array = encoding.GetBytes(Subtitle);
stream.WriteByte(Convert.ToByte(array.Length));
stream.Write(array, 0, array.Length);
//ect...and something very similar for Loading a file.
This is basically what I am trying to do. I am actually saving 2 TextRanges and a bunch more Properties. So my problem is that TextRange.Load() reads to the end of the file...making it impossible for me to use that considering I have 2 TextRanges I need to save/load.
So here I am trying to come up with another way to be able to save/load the content of a RichTextBox with other data. I dont have to use a Stream. I am pretty much open to any feasible solutions. Thanks in advance!
~Jasson
You could load/save to a MemoryStream to solve your issue with reading to the end of the file. It could look like this:
- Load your file into memory
- Load the section of that file that is the contents of the richtextbox into a MemoryStream
- Load the richtextbox contents from that MemoryStream
Or are you wanting to know how you'd create and parse a file to contain different sections for the title, and the contents, and any other fields ?
I figured I should post my current solution. It seems to work perfectly fine. Thank you Chris and Ants to the hints on how to go about doing this.
/// <summary>
/// Reads a TextRange (DataFormats.Rtf) from the stream.
/// </summary>
/// <param name="stream">The stream to be read from.</param>
/// <returns>The TextRange (DataFormats.Rtf) that was read from the stream.</returns>
public static TextRange ReadTextRange(FileStream stream)
{
long startPos = stream.Position;
int length = -1;
int count = 0;
int previousByte = 0;
int currentByte = 0;
//set previousByte to give the current one something to compare to
previousByte = stream.ReadByte();
//parse the file counting the { and } to find the end of the rtf portion of the file.
while (count > 0 || length < 1)
{
length++;
stream.Position = startPos + length;
currentByte = stream.ReadByte();
if (previousByte != 92) // not '\' so check to see if '{' or '}' is currentByte
{
if (currentByte == 123) // '{' increase count
count++;
else if (currentByte == 125) // '}' decrease count
count--;
}
previousByte = currentByte;
}
//save finish position to move to later
long finishPos = stream.Position;
//reset stream position to start at beginning of rtf
stream.Position = startPos;
//read the rtf portion of the file into a byte[]
byte[] content = new byte[length];
stream.Read(content, 0, length);
//put the byte[] into a memory stream
MemoryStream memStream = new MemoryStream(content);
FlowDocument doc = new FlowDocument();
TextRange range = new TextRange(doc.ContentStart, doc.ContentEnd);
//have the TextRange read from the memorystream
range.Load(memStream, System.Windows.DataFormats.Rtf);
memStream.Close();
//set the position to after the rtf portion of the file
stream.Position = finishPos;
return range;
}
This ReadTextRange Method is in a StreamHelper class I defined for helping read from a FileStream. So all of this is to load a TextRange that is saved to the FileStream like this...
//save query (TextRange)
Query.Save(stream, System.Windows.DataFormats.Rtf);
I hope that someone finds this useful if/when they come to a similar problem! :D
EDIT:
I used a profiler and found that this code was not very efficient so I have changed this code to be much more efficient in a few ways.
Instead of using the TextRange and use a byte[] which holds the contents of MemoryStream memStream. This cuts out range.Load which consumes a lot of CPU.
I took out the line stream.Position = startPos + length because I realized it was useless after the first run and also took up a decent amount of CPU. I placed stream.Position--; after the line previousByte = stream.ReadByte();
Also I realized I was being a bad coder and wasn't following MVC by having TextRange, UI element, inside of my data class. Now it has a byte[], which is MUCH better.
EDIT AGAIN:
After a few minutes of having the byte[] instead of the TextRange I realized I had the size of the byte[] so I didn't need to parse it. So instead I save write the byte[] size and then the byte[]. This makes it extremely fast and can read a very large file nearly instantly.