OpenFileDialog filename serialization - c#

In writing a program where I need to serialize an AppSettings object which consists of several properties including one that will be used to store a last used filename, I have found that the FileName property is placed into my object (by assignment) but it does not serialize to the xml file. No exceptions are thrown and no data is written.
But conversely, if I programmtically modify the object
tc.TheDataFile = "c:\\Documents And Settings\\SomeUser\\Sample\\a test file.txt";
instead of
tc.TheDataFile = theDialog.FileName;
That will work. Can someone please provide some insight with regard to what I am missing?
Here is a simple version of the program that is directly related to the problem.
The test class which will theoretically hold the AppSettings ---
[Serializable()]
public class TestClass
{
private string m_TheDataFile;
private bool m_UseLastKnownDataFile = true;
public bool UseLastKnownDataFile
{
get
{
return m_UseLastKnownDataFile;
}
set
{
m_UseLastKnownDataFile = value;
}
}
public string TheDataFile
{
get
{
return m_TheDataFile;
}
set
{
m_TheDataFile = value;
}
}
}
public class TestClassHelper
{
public static TestClass Load()
{
XmlSerializer serializer = new XmlSerializer(typeof(TestClass));
TestClass retVal;
TextReader reader = null;
bool fileNotFound = false; ;
try
{
reader = new StreamReader("TestClassConfig.xml");
}
catch (FileNotFoundException)
{
fileNotFound = true;
}
if (fileNotFound)
{
retVal = new TestClass();
}
else
{
retVal = (TestClass)serializer.Deserialize(reader);
reader.Close();
}
return retVal;
}
public static void Save(TestClass settings)
{
XmlSerializer serializer = new XmlSerializer(typeof(TestClass));
TextWriter writer = new StreamWriter("TestClassConfig.xml");
serializer.Serialize(writer, settings);
writer.Close();
}
}
And here is the form which will prompt the user for a filename. In this test, there is a form with one button.
public partial class Form1 : Form
{
TestClass tc = null;
public Form1()
{
InitializeComponent();
tc = TestClassHelper.Load();
}
private void button1_Click(object sender, EventArgs e)
{
OpenFileDialog theDialog = new OpenFileDialog();
string fileName = string.Empty;
theDialog.CheckFileExists = true;
theDialog.CheckPathExists = true;
theDialog.Multiselect = false;
theDialog.FileName = string.Empty;
if (theDialog.ShowDialog() == DialogResult.OK)
{
tc.TheDataFile = theDialog.FileName;
}
else
{
tc.TheDataFile = string.Empty;
}
}
private void Form1_FormClosed(object sender, FormClosedEventArgs e)
{
TestClassHelper.Save(tc);
}
}
Edit To Add:
I'm using Microsoft Visual Studio 2005 Team Edition w/Dot Net 2.0.50727 SP1, with no options to upgrade the development environment.
Solution
I'm not exactly sure why this happens, but the OpenFileDialog control must change the current operating directory of the program. When the object is deserialized to the xml file, it no longer writes where it originally opened. Rather it is created in the new directory.
I corrected the problem by making the XML read and write location more specific.

The problem is that you are setting tc.TheDataFile = fileName; after the if block, but you never assign anything to fileName except when you initialize it to string.Empty. One fix would be:
if (theDialog.ShowDialog() == DialogResult.OK)
{
fileName = theDialog.FileName;
}
// record last used data file
tc.TheDataFile = fileName;
or just
if (theDialog.ShowDialog() == DialogResult.OK)
{
tc.TheDataFile = theDialog.FileName;
}
Note that running your test in the debugger and "watch"ing the variables would have made the problem fairly easy to spot.

Related

UI Not Loading When Using While In Foreach Loop

I am making a program which you can create and load in a flashcard pack using csv files. When a csv file is chosen it opens other UI with the question, answer and image for a flashcard and will keep on looping until all the flashcards in the pack are gone through using a foreach loop.
However the foreach loop would keep on looping without the user pressing the next button. To fix this I did:
while (Continue() == false) { } //this is at the end of the foreach loop
}
}
private bool Continue()
{
if (btn_NextFlashcard_WasClicked) return true;
Application.DoEvents();
Thread.Sleep(250);
Application.DoEvents();
return false;
}
private bool btn_NextFlashcard_WasClicked;
private void btn_NextFlashcard_Click(object sender, EventArgs e)
{
btn_NextFlashcard_WasClicked = true;
}
This fixed the problem of it looping again without the button for the next flashcard being pressed but now it doesn't even open the second UI for me to press the next flashcard button.
How would I fix this? Any help would be greatly appreciated.
Code for foreach loop:
public void ReadFlashcardPack(string file)
{
var records = engine.ReadFile(file);
foreach (var record in records)
{
Console.WriteLine("New foreach loop");
lblQuestion.Text = record.question;
lblAnswer.Text = record.answer;
lblAnswer.Visible = false;
btn_NextFlashcard_WasClicked = false;
//check if there is an image
if (record.image == "FALSE")
{
Image.Hide();
}
else
{
Image.Show();
Image.Image = Properties.Resources.test_image;
}
while (Continue() == false) { }
}
}
The records also come from a class: [DelimitedRecord(",")]
public class FlashcardPack
{
public string question;
public string answer;
public string image;
}
And then a new instance of FileHelpers engine is made private FileHelperEngine<FlashcardPack> engine = new FileHelperEngine<FlashcardPack>(); to read the csv file and every time the foreach loop loops record.question, record.answer and record.image changes depending on what line the loop is on.
One idea that comes to mind is to store the list of records outside of the method, keep track of the next record that should be read, and modify the method to just read the next record.
Then, in your click event, you can just call the method again until all records have been read.
private string filePath = #"f:\private\temp\temp.csv"; // Use your file path here
private List<FlashcardPack> records;
private int nextRecord;
public void ReadNextRecord()
{
if (records == null)
{
records = engine.ReadFile(filePath).ToList();
nextRecord = 0;
}
else if (nextRecord >= records.Count)
{
// Do something when all records have been read
nextRecord = 0;
}
// Get next record and increment our variable
var record = records[nextRecord++];
lblQuestion.Text = record.question;
lblAnswer.Text = record.answer;
lblAnswer.Visible = false;
btn_NextFlashcard_WasClicked = false;
//check if there is an image
if (record.image == "FALSE")
{
Image.Hide();
}
else
{
Image.Show();
Image.Image = Properties.Resources.test_image;
}
}
private void btn_NextFlashcard_Click(object sender, EventArgs e)
{
ReadNextRecord();
}
Here's a working sample that uses the concept above which might help you get your code working, since I can't see your whole project:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private List<Flashcard> flashcards;
private int nextRecord;
// Use a valid path on your system here (the file doesn't need to exist)
private const string FilePath = #"f:\public\temp\temp.csv";
private void LoadFlashcards()
{
flashcards = Engine.ReadFile(FilePath);
nextRecord = 0;
}
public void DisplayNextFlashcard()
{
if (flashcards == null)
{
LoadFlashcards();
}
else if (nextRecord >= flashcards.Count)
{
// Do something when all records have been read
nextRecord = 0;
}
var flashcard = flashcards[nextRecord++];
lblQuestion.Text = flashcard.Question;
lblAnswer.Visible = false;
lblAnswer.Text = flashcard.Answer;
Image.Visible = flashcard.Image;
Image.Image = Properties.Resources.FlashcardImage;
}
private void btn_NextFlashcard_Click(object sender, EventArgs e)
{
DisplayNextFlashcard();
}
}
class Flashcard
{
public string Question { get; set; }
public string Answer { get; set; }
public bool Image { get; set; }
public static Flashcard Parse(string csvLine)
{
if (csvLine == null) throw new ArgumentNullException(nameof(csvLine));
var parts = csvLine.Split(',').Select(item => item.Trim()).ToList();
if (parts.Count != 3) throw new FormatException(
"csvLine does not contain 3 comma-separated items.");
return new Flashcard
{
Question = parts[0],
Answer = parts[1],
Image = !parts[2].Equals("FALSE", StringComparison.OrdinalIgnoreCase)
};
}
}
class Engine
{
public static List<Flashcard> ReadFile(string filePath)
{
if (filePath == null) throw new ArgumentNullException(nameof(filePath));
if (!File.Exists(filePath)) CreateFile(filePath);
return File.ReadAllLines(filePath).Select(Flashcard.Parse).ToList();
}
private static void CreateFile(string filePath)
{
File.CreateText(filePath).Close();
File.WriteAllText(filePath,
"What is more useful when it is broken?, An egg, TRUE\n" +
"What belongs to you but other people use it more?, Your name, FALSE\n" +
"I have three eyes all in a row. When the red one opens " +
"no one can go. What am I?, A traffic light, TRUE");
}
}

How can I write a using block in another way?

I have a class with different methods from a Windows Form. In my test code, I used this to create a new OpenXML Document:
using (WordprocessingDocument package = WordprocessingDocument.Create(docName, WordprocessingDocumentType.Document))
But this seems not working on multiple methods. How can I fix it? It won't work without the using, so after a bit of research I found out that this class was IDisposable.
But I have 2 needs right now:
1) If the file exists, the document has to open instead of creating a new one.
2) The docName, which contains the path to the file that he's going to save, has to be reachable end used in the block as seen above.
Is there a way to do this?
This is my code right now:
using System;
using System.IO;
using System.Windows.Forms;
using DocumentFormat.OpenXml;
using DocumentFormat.OpenXml.Packaging;
using DocumentFormat.OpenXml.Wordprocessing;
namespace WordExample
{
public partial class Word : Form
{
private string _docName = Environment.GetFolderPath(Environment.SpecialFolder.Desktop) + #"\xxx2.docx";
private WordprocessingDocument _package;
private Document _doc;
private Body _body;
public Word()
{
InitializeComponent();
/*if (File.Exists(_docName))
{
_package = WordprocessingDocument.Open(_docName, false);
_doc = _package.MainDocumentPart.Document;
_body = _doc.Body;
}
else
{
_package = WordprocessingDocument.Create(_docName, WordprocessingDocumentType.Document);
_package.AddMainDocumentPart();
_doc = _package.MainDocumentPart.Document;
_body = new Body();
}*/
_package = WordprocessingDocument.Create(_docName, WordprocessingDocumentType.Document);
_package.AddMainDocumentPart();
_doc = new Document();
_body = new Body();
}
private void Word_Load(object sender, EventArgs e)
{
}
private void btnAddParagraph_Click(object sender, EventArgs e)
{
/*Paragraph p = new Paragraph();
Text t = new Text(txtTekstParagraaf.Text);
Run r = new Run();
RunProperties rPr = new RunProperties();
if (chkBold.Checked)
{
Bold b = new Bold();
rPr.Append(b);
}
if (chkItalic.Checked)
{
Italic b = new Italic();
rPr.Append(b);
}
if (chkUnderline.Checked)
{
Underline b = new Underline();
rPr.Append(b);
}
//RunProperties
//r.PrependChild<RunProperties>(rPr);
r.PrependChild(rPr);
r.AppendChild(t);
p.AppendChild(r);
_body.AppendChild(p);*/
Save();
}
private void Save()
{
_doc.AppendChild(_body);
_package.MainDocumentPart.Document = _doc;
// Save changes to the main document part.
_package.MainDocumentPart.Document.Save();
}
}
}
But this code generates an error when trying to open the created document afterwards AND when I try to open an document instead of creating one.
You can try using trenary operator here:
using (WordprocessingDocument package = File.Exists(docName) ?
WordprocessingDocument.Create(docName, WordprocessingDocumentType.Document) :
WordprocessingDocument.Open(docName, WordprocessingDocumentType.Document)) {
...
}
If the file exists, the document has to open instead of creating a new one.
So why don't you use an if statement?
if(File.Exists(docName))
{
using(var package = ..) // open file
{
...
}
}
else
{
using(var package = ..) // create file
{
...
}
}
You are not forced to instantiate variable directly in using statement. You can move creation to separate method:
private WordprocessingDocument GetPackage(string docName)
{
var docType = WordprocessingDocumentType.Document;
if (File.Exists(docName))
return WordprocessingDocument.Open(docName, docType);
return WordprocessingDocument.Create(docName, docType);
}
Now your code will look like:
using(var package = GetPackage(docName))
{
// ...
}
UPDATE: If you want to reuse disposable dependency in all methods of class (as you stated in comments) you should implement IDisposale by class which holds disposable dependency, and dispose that dependency when you are disposing class:
public class Foo : IDisposable
{
private readonly WordprocessingDocument _package;
public Foo()
{
_package = GetPackage(docName); // implemented as above
}
public void Method1()
{
// use _package without `using` block
}
public void Method2()
{
// use _package without `using` block
}
public void Dispose()
{
if (_package != null)
_package.Dispose();
}
}
Then wrap instance of Foo into using block:
using(var foo = new Foo()) // _package created here
{
foo.Method1(); // same _package instance used by both methods
foo.Method2();
} // _package will be disposed here

Erratic redirecting standard/error output from ncftpput.exe

I'm trying to get the output stream from ncftpput.exe and be able to manipulate the stream asynchronously. ncftpput.exe doesn't print it's stream line by line, instead it just keeps updating the same line with new information (this might be relevant). It works intermittantly - sometimes I'll get the information back, sometimes I don't.
Essentially, is there a way I can get a stream that refreshes it's line frequently to be redirected in a more secure and regular manner?
Here is what I've got so far (I've annotated it, getting rid of irrelvant extraneous information, but this is the essence):
class Program
{
static int main()
{
internal Process m_Tool { get; set; }
internal ProcessStartInfo m_StartInfo { get; set; }
internal static string m_StandardData { get; set; }
internal static string m_ErrorData { get; set; }
m_Tool = new Process();
m_StartInfo = new ProcessStartInfo();
m_StartInfo.FileName = #"C:\utils\ncftpput.exe";
m_StartInfo.UseShellExecute = false;
m_StartInfo.RedirectStandardOutput = true;
m_StartInfo.RedirectStandardError = true;
m_StandardData = "";
m_ErrorData = "";
m_StartInfo.Arguments = /* Various starting args */
m_Tool.StartInfo = m_StartInfo;
m_Tool.Start();
string standardLine;
string errorLine;
try
{
m_Tool.OutputDataReceived += ProcessStandardDataHandler;
m_Tool.ErrorDataReceived += ProcessErrorDataHandler;
m_Tool.BeginErrorReadLine();
m_Tool.BeginOutputReadLine();
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}
while (!m_Tool.HasExited)
{
System.Threading.Thread.Sleep(5000);
standardLine = m_StandardData;
errorLine = m_ErrorData;
}
}
private static void ProcessErrorDataHandler(object sendingProcess, DataReceivedEventArgs outLine)
{
if (!String.IsNullOrEmpty(outLine.Data))
{
// Add the text to the collected output.
m_ErrorData = outLine.Data.ToString();
m_DataReceived = true;
}
}
private static void ProcessStandardDataHandler(object sendingProcess, DataReceivedEventArgs outLine)
{
if (!String.IsNullOrEmpty(outLine.Data))
{
// Add the text to the collected output.
m_StandardData = outLine.Data.ToString();
}
}
}
Thanks in advance!!
In the end I discovered that because of how ncftpput.exe printed to the console, it was going to be impossible to get sufficient information from the redirected output. So I just decided to write my own FTP application and use that! It's a simpler application than ncftpput.exe but it does what I need it to do. I used the standard .NET library, nothing special.

Extension method must be defined in a non-generic static class

I'm getting the above error. I saw other similar posts on this error but I don't seem to find where the problem is. I changed my class type to static and the error resists. This is the entire code to my main form class:
I Edited my class. This is how it looks like now and the error has changed to:Missing partial modifier on declaration of type 'PhoneFind.frmMain'; another partial declaration of this type exists.
namespace PhoneFind
{
public partial class frmMain : Form
{
// the path to the temporary file to store the webresponse
String path = "c:\\Temp\\webresponse.txt";
public frmMain()
{
InitializeComponent();
comboSelectSearchEngine.SelectedIndex = 0;
ofdPhones.Filter = "txt files (*.txt)|*.txt";
listbxMessages.Items.Clear();
addItemToListBox(listbxMessages, "Welcome to ActionBase Phone Find!");
addItemToListBox(listbxMessages, "Select the file containing the numbers.");
radioNumbers.Checked = true;
}
private void frmMain_Load(object sender, EventArgs e)
{
}
private void btnLoadFile_Click(object sender, EventArgs e)
{
if (ofdPhones.ShowDialog() == System.Windows.Forms.DialogResult.OK)
{
txtFile.Text = ofdPhones.FileName;
// Read the file line by line and add the numbers to the numbers listbox.
listbxNumbers.Items.Clear();
String line;
int numbersCounter = 0;
System.IO.StreamReader file = new System.IO.StreamReader(ofdPhones.FileName);
while ((line = file.ReadLine()) != null)
{
listbxNumbers.Items.Add(line.Trim());
numbersCounter++;
}
addItemToListBox(listbxMessages, ofdPhones.FileName + " loaded.");
addItemToListBox(listbxMessages, numbersCounter + " records found in the file.");
}
}
// add item to the listbox and move scroll to the end of the listbox for the latest messages to be visibile to the viewer
private void addItemToListBox(ListBox listbox, String item)
{
listbox.Items.Add(item);
listbox.SelectedIndex = (listbox.Items.Count - 1);
}
private void radioNumbers_CheckedChanged(object sender, EventArgs e)
{
if (!radioNumbers.Checked)
{
grpbxNumbers.Text = "Names and Addresses";
}
else
{
grpbxNumbers.Text = "Numbers";
}
}
private void btnRun_Click(object sender, EventArgs e)
{
if (listbxNumbers.Items.Count == 0)
{
MessageBox.Show("No records have been loaded." + "\n" + "Use the browse button to load records.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
else if (!CheckForInternetConnection())
{
MessageBox.Show("No internet connection.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
else
{
String response;
switch (comboSelectSearchEngine.SelectedIndex)
{
case 0: // Hitta.se
foreach (String item in listbxNumbers.Items)
{
WebRequestObj request = new WebRequestObj(item, "hitta");
response = request.sendRequest();
if (response.Equals("Error"))
{
addItemToListBox(listbxMessages, "Error sending '" + item + "' to the server.");
}
else
{
//create a temporary file to work on the response
StreamWriter sw;
if (!File.Exists(path)) {
sw = File.CreateText(path);
}
try
{
File.WriteAllText(path, String.Empty); // clear the content of the file
sw = File.AppendText(path);
sw.WriteLine(response);
sw.Flush();
sw.Close();
String s = findResultType(path);
MessageBox.Show(s);
}
catch (IOException ioe)
{
MessageBox.Show(ioe.Message,"Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
}
break;
}
}
}
public bool CheckForInternetConnection()
{
try
{
using (var client = new System.Net.WebClient())
using (var stream = client.OpenRead("http://www.google.com"))
{
return true;
}
}
catch
{
return false;
}
}
/*
* findResultType
* gets the web response and finds out if the matching result of the search termis one of the following:
* 1. one person (oneperson)
* 2. one company (onecompany)
* 3. more than one person, no company (manypersonnocompany)
* 4. no person, more than one company (nopersonmanycompany)
* 5. more than one person, more than one company (manypersonmanycompany)
* 6. no person, no company (nopersonnocompany)
*/
public String findResultType(String reponsepath)
{
HtmlAgilityPack.HtmlDocument doc = new HtmlAgilityPack.HtmlDocument();
doc.Load(reponsepath);
List<String> itemList = new List<String>();
IEnumerable<String> v = null;
var item = doc.DocumentNode.SelectNodes("//body[#id='person']");
if (item != null)
{
v = item.Select(p => p.InnerText);
itemList = v.ToList();
if (itemList.Count == 1)
return "oneperson";
}
else
{
item = doc.DocumentNode.SelectNodes("//body[#id='company']");
if (item != null)
{
v = item.Select(p => p.InnerText);
itemList = v.ToList();
if (itemList.Count == 1)
return "onecompany";
}
}
//for (int i = 0; i < itemList.Count; i++)
//{
// MessageBox.Show(itemList[i]);
// //console.writeline(itemlist[i]);
//}
//console.writeline(itemlist.count + " results found.");
return "";
}
}
}
This is your first problem:
public static class frmMain : Form
You can't derive a static class from another class. A static class always implicitly derives from Object. You also can't have non-static members in static classes.
So basically, you can't put your extension method in your frmMain class (which should be renamed to follow .NET naming conventions and to be somewhat more descriptive at the same time). Why did you want to put the extension method in that class anyway?
I can't even see an extension method in the code you've posted - did you remove it? Is it in some other class you haven't posted?
Fundamentally, I think you need to take a step back. It sounds like you've reacted to the compiler error message without really understanding it fully. Read up on extension methods, read up on what static classes are, until you really understand why you don't want your form class to be static, and why you do want to make the class that contains your extension method static.
A static class cannot have public constructors. Moreover, static forms are pointless, as you need an instance of them to show.
If you have an extension method (I don't see any...), you have to move it into a separate static class which you cannot create instances of:
static class MyExtensions
{
public static void Extend(this Object o) {}
}
You should always put your extension methods in a separate static class.
You can't fix the problem by simply marking a class as static. That changes the entire meaning of the class. Instead, create a new class for just extension methods.
For example:
public static class Extensions
{
public void SomeExtension(this object arg)
{
...
}
}

Read and write data into notepad using serialization

I have a problem with reading and writing data into file notepad using serialization
Basically that's about login and sign up
I'll give my code here
This is the part for sign up form :
public partial class formSignUp : Form
{
List<data> game = new List<data>();
data dt = new data();
public formSignUp()
{
InitializeComponent();
}
private void write()
{
try
{
using (Stream stream = File.OpenWrite("game.txt"))
{
BinaryFormatter bin = new BinaryFormatter();
bin.Serialize(stream, dt);
}
}
catch (IOException)
{
}
}
private void butRegister_Click(object sender, EventArgs e)
{
write();
dt = new data(tbUName.Text, tbPass1.Text);
game.Add(dt);
}
}
and then this is the class data code :
[Serializable()]
class data
{
private string username;
private string password;
public string Username
{
get { return username; }
set { username = value; }
}
public string Password
{
get { return password; }
set { password = value; }
}
public data(string username, string password)
{
this.username = username;
this.password = password;
}
public data()
{
}
}
i put the file notepad inside folder "bin" with name "game.txt"
the problem is, everytime i call "write()" the character which is written into file "game.txt" is so strange character. so far i got like :
ÿÿÿÿ <Login, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
Login.data usernamepassword
Anybody can help me?
Thanks a lot in advance
Regards
That's because you're using a BinaryFormatter, it outputs binary data. You should use one of the textual formatters. There's SoapFormatter and the DataContractJsonSerialized, although it may not be suitible for you.

Categories

Resources