Search This Blog

WPF project about convert XML to text file




I was working on a small WPF project. As some of people already know Pronto, this ERP suite
can not deal with Web service unless integrated with .NET , the P.I.E , but it cost money for license from Pronto.
So I made this WPF program for one of our clients. They will run this on their server 24/7 and once the XML file achieved from their Kiosks to their server, this program will change the XML file to txt file with right data format; then copy the txt file to another fold for process; Or transfer to our pronto server to process. At the end of process, the retailer POS will get the all data.

O.k easy one.

The IDE is VS2010, UI designed with Blend 3. No SQL server used here, user customize saved with ini file, was tried app.config, but it is easy to read, for write , it is not safe even sometimes works, runtime issue. LinQ used for XML date query. typical 3.5 project. MVVM .

The core part is muti-thread, so the famous backgroundWorker would be best choice for this
long time running program.
this.backgroundWorker.DoWork += new System.ComponentModel.DoWorkEventHandler(this.backgroundWorker_DoWork);
this.backgroundWorker.RunWorkerCompleted += new System.ComponentModel.RunWorkerCompletedEventHandler(this.backgroundWorker_RunWorkerCompleted);
this.backgroundWorker.ProgressChanged += new System.ComponentModel.ProgressChangedEventHandler(this.backgroundWorker_ProgressChanged); this.backgroundWorker.WorkerSupportsCancellation = true;
this.backgroundWorker.WorkerReportsProgress = true;


There are a lot of good example on the net about backgroundWorker thread, it is a great and very useful thing. What I did with my project is the Asynchronous one. But one thing these article didn't mentioned about is how to make the the cancel method works. Normally people start coding will still got no responding error after hit the cancel button. The tip is you need return your long time run process thread with a string to your dowork. That will fix the problem.
You won't find this with MSDN, trust me, when you do this part , you will know what I mean.

For long time process, your can use file watcher, but still got some thread not access issue, so what I am use is like this.
namespace ProcessFiles
{
class Program
{
private bool ProgramRunning = true;
private int FilesHandled = 1;

static void Main(string[] args)
{
Program prog = new Program();
prog.ReadDirectoryThread();
}

private void ReadDirectoryThread()
{
while (this.ProgramRunning)
{
DirectoryInfo DirInfo = new DirectoryInfo(Path.GetDirectoryName(Process.GetCurrentProcess().MainModule.FileName) + "\\incoming\\");

foreach (FileInfo FInfo in DirInfo.GetFiles("*.xml"))
{
Thread t = new Thread(new ParameterizedThreadStart(ProcessFile));
t.Start(FInfo.FullName);
while (t.ThreadState != System.Threading.ThreadState.Stopped)
{
//Thread.Sleep(5);
}
}

}
}

void ProcessFile(object FileToProcess)
{
string sFile = FileToProcess.ToString();
bool isProcessed = false;

// File processing
try
{
sFile = "*.xml";
// Process your file here. Convert the XML file to text file
//TransformXML();
// Loading from a file, you can also load from a stream
//XDocument loaded = XDocument.Load(sFile);

//// create a writer and open the file
//TextWriter tw = new StreamWriter("XmltoCSV.txt");

// Query the data and write out a subset of contacts
var contacts = from c in loaded.Descendants("CONTACT")
select new
{
FirstName = (string)c.Element("FIRSTNAME"),
LastName = (string)c.Element("LASTNAME"),
City = (string)c.Element("CITY"),
State = (string)c.Element("STATE"),
Country = (string)c.Element("COUNTRY")
};

foreach (var contact in contacts)
{
string s = contact.FirstName + "," +
contact.LastName + "," +
contact.City + "," +
contact.State + "," +
contact.Country;

// write a line of text to the file
tw.WriteLine(s);
}

// close the stream
tw.Close();

}
catch
{
return;
}

// After the file is processed, we move it
while (!isProcessed)
{
try
{
string ProcessedFilesDir = string.Format("{0}\\processed\\{1}_{2}.txt", Path.GetDirectoryName(Process.GetCurrentProcess().MainModule.FileName), DateTime.Now.ToString("dd_MM_yyyy_HH_mm_ss"), Guid.NewGuid().ToString());
File.Move(sFile, ProcessedFilesDir);
Console.WriteLine(FilesHandled + " - File " + sFile.ToString() + " processed\n");
FilesHandled++;
}
catch
{
isProcessed = false;
}
finally
{
isProcessed = true;
}
}
}
void TransferFile(object FileToTransfer)
{
// write the transfer part here like Secured FTP
}


}
}

As you can see this sample code is a console one, but it is easy change to any Windows form or WPF one, also for the LinQ XML query part you can use XSLT as well, could be another good solution.

For the customize part, easy one, ini file.

public void IniWriteValue(string Section, string Key, string Value, string filepath)
{
WritePrivateProfileString(Section, Key, Value, filepath);
}

public string IniReadValue(string Section, string Key, string filepath)
{
StringBuilder temp = new StringBuilder(255);
int i = GetPrivateProfileString(Section, Key, "", temp,
255, filepath);
return temp.ToString();

}

O.k that's all. Next time I will put the the program on the Google code, that will make sense.
And finally I got some time to updated my blog. That's wonderful.