Showing posts with label Code4Food. Show all posts
Showing posts with label Code4Food. Show all posts

Tuesday, April 27, 2010

Code4Food #6: How to join multiple CSV files with the same structure ?

Hi,

Reading another question on Bytes.com I found this question. So assuming these CSV files have the same structure, I can easily join them.

Now to test it I split this CSV file into 5 files: CsvFile1.csv … CsvFile5.csv

"REVIEW_DATE","AUTHOR","ISBN","DISCOUNTED_PRICE"
"1985/01/21","Douglas Adams",0345391802,5.95
"1990/01/12","Douglas Hofstadter",0465026567,9.95
"1998/07/15","Timothy ""The Parser"" Campbell",0968411304,18.99
"1999/12/03","Richard Friedman",0060630353,5.95
"2001/09/19","Karen Armstrong",0345384563,9.95
"2002/06/23","David Jones",0198504691,9.95
"2002/06/23","Julian Jaynes",0618057072,12.50
"2003/09/30","Scott Adams",0740721909,4.95
"2004/10/04","Benjamin Radcliff",0804818088,4.95
"2004/10/04","Randel Helms",0879755725,4.50

Now I made the program which makes the deal. Nothing to special here, just want to mention you do not need joining multiple times the column headers.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows.Forms;
using System.IO;
using System.Text;

namespace CsvJoiner
{
    static class Program
    {
        public static void Main()
        {
            string[] csvFileNames = Directory.GetFiles(".", "CsvFile*.csv");

            JoinCsvFiles(csvFileNames, "CsvOutput.csv");
        }

        private static void JoinCsvFiles(string[] csvFileNames, string outputDestinationPath)
        {
            StringBuilder sb = new StringBuilder();

            bool columnHeadersRead = false;

            foreach (string csvFileName in csvFileNames)
            {
                TextReader tr = new StreamReader(csvFileName);

                string columnHeaders = tr.ReadLine();

                // Skip appending column headers if already appended
                if (!columnHeadersRead)
                {
                    sb.AppendLine(columnHeaders);
                    columnHeadersRead = true;
                }

                sb.AppendLine(tr.ReadToEnd());  
            }

            File.WriteAllText(outputDestinationPath, sb.ToString());
        }
    }
}
Now I'll show the output. To check out this project
download the sources here
"REVIEW_DATE","AUTHOR","ISBN","DISCOUNTED_PRICE"
"1985/01/21","Douglas Adams",0345391802,5.95
"1990/01/12","Douglas Hofstadter",0465026567,9.95
"1998/07/15","Timothy ""The Parser"" Campbell",0968411304,18.99
"1999/12/03","Richard Friedman",0060630353,5.95
"2001/09/19","Karen Armstrong",0345384563,9.95
"2002/06/23","David Jones",0198504691,9.95
"2002/06/23","Julian Jaynes",0618057072,12.50
"2003/09/30","Scott Adams",0740721909,4.95
"2004/10/04","Benjamin Radcliff",0804818088,4.95
"2004/10/04","Randel Helms",0879755725,4.50

Monday, April 26, 2010

Code4Food #5: How to get specific XML nodes using Linq to XML ?

Hi, another question has been received from Bytes.com.

So the problem was that we needed to get all the tags “Error” from a specific XML without actually caring to much about where exactly in the XML tree is Error tag. And we need to do this using Linq to Xml.

So he got an xml like these:

<Users>
      <User>
           <FirstName>Tom</FirstName>
           <LastName>Won</LastName>
           <Error>Test 2</Error>
       </User>
      <User>
           <FirstName>Jim</FirstName>
           <LastName>Kim</LastName>
           <Error>Test 2</Error>
       </User>
       <Error>Test 3</Error>
</Users>

Now this problem isn't actually a problem at all. All you need is to use Linq to XML objects like XElement, XDocument, XNode, and so on (opposite thing to XmlElement, XmlDocument, and XmlNode). Actually you can do it without directly using Linq, by callings Descendants(XName name) method.

So this is the code that I’ve written to make this done.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows.Forms;
using System.Xml.Linq;

namespace GetErrorTags.Linq2Xml
{
    static class Program
    {
        static void Main()
        {
            // Load the document into root XElement.
            // Remember in Linq you work with XDocument, XElement, XNode and not with XmlDocument, etc.
            XElement rootElement = XElement.Load("ErrorTags.xml");

            // without directly using Linq
            var errorTags = rootElement.Descendants("Error");

            Console.WriteLine("==============Without using Linq=========");

            foreach (XElement tagError in errorTags)
            {
                Console.WriteLine(tagError);
            }

            Console.ReadKey();

            // using Ling directly, we'll select only "Test 2" errors
            var linqErrorTags = rootElement.Descendants("Error").Where(element => element.Value.Equals("Test 2"));

            Console.WriteLine("==============Using Linq=========");

            foreach (XElement tagError in linqErrorTags)
            {
                Console.WriteLine(tagError);
            }

            Console.ReadKey();

        }
    }
}

And here is the output:

Download source

Thursday, April 22, 2010

Code4Food #4: How to change WinForms Treeview control image size?

Hi,

Today I visited Bytes.com and saw a question about Treeview.

Indeed how would one change ImageSize of a node ? So I had 15 free minutes and this is what I found.

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace TreeView.ImageSize
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
            FillTreeView();
        }

        private void FillTreeView()
        {
            // Load the images in an ImageList.
            ImageList myImageList = new ImageList();
            myImageList.Images.Add(Image.FromFile("63vts4.jpg"));
            myImageList.Images.Add(Image.FromFile("ToDeleteIfNotSold.png"));
            
            // Change the size of the images.
            myImageList.ImageSize = new Size(50, 50);

            // Assign the ImageList to the TreeView.
            trvImages.ImageList = myImageList;
            trvImages.ItemHeight = 50;

            // Set the TreeView control's default image and selected image indexes.
            trvImages.ImageIndex = 0;
            trvImages.SelectedImageIndex = 1;

            // Create the root tree node.
            TreeNode rootNode = new TreeNode("CustomerList");

            TreeNode childNode1 = new TreeNode("Customer1");
            TreeNode childNode2 = new TreeNode("Customer2");

            // Add a main root tree node.
            trvImages.Nodes.Add(rootNode);
            trvImages.Nodes[0].Nodes.Add(childNode1);
            trvImages.Nodes[0].Nodes.Add(childNode2);
        }
    }
}

So the magic line was myImageList.ImageSize = new Size(50, 50); Here is the output and the code to download.

Download source code link

Saturday, December 5, 2009

Code4Food #3: Text Editor in 5 minutes – Part II. FileSystemWatcher class.

By the way I installed a rating widget on my blog. So now you can rate my posts if you like them, or if you dislike them you can put a 1 star rate too.

Hi,

Finally I found time to continue my little experiment with the text editor. Here you can read the previous post on text editor.

Today we’re going to talk about:

So here is the to download it :

ViewFile_0.2 sourcecode

 

SaVE FilE

This part actually was relatively easy to do. It was very similar to reading. Using TextWriter was enough to save the file. I still like looking fancy that’s why I used a SaveFileDialog for saving a file.

I indicated that saving would be possible by default in 2 formats without indicating extension (see saveFileDialog.Filter property), text files and C# class files.

private void btnSaveFile_Click(object sender, EventArgs e)
{
	SaveFileDialog saveFileDialog = new SaveFileDialog();
	saveFileDialog.Filter = "Text Files (*.txt)|*.txt|C# files (*.cs)|*.cs|All files (*.*)|*.*";

	saveFileDialog.SupportMultiDottedExtensions = true;

	DialogResult result = saveFileDialog.ShowDialog();

	if (result == DialogResult.OK)
	{
		_fileName = saveFileDialog.FileName;
		
		if (!string.IsNullOrEmpty(_fileName))
			SaveFileContent();
	}
}

private void SaveFileContent()
{
	lblFileName.Text = Path.GetFileName(_fileName);

	try
	{
		// we'll make only a textual file for instance
		TextWriter tw = File.CreateText(_fileName);

		try
		{
			tw.Write(txtFileContent.Text);
		}
		catch (Exception ex)
		{ MessageBox.Show(ex.Message); }
		finally
		{
			tw.Close();

			StartMonitorization();
		}
	}
	catch (UnauthorizedAccessException ex)
	{ MessageBox.Show("Sorry, you lack sufficient privileges."); }
	catch (Exception ex)
	{ MessageBox.Show(ex.Message); }
}
Notifications Sending when Your file is changed

I didn’t actually planned to implement this but I saw a great opportunity. It was already a class there that could permit me to do this in a very easy way.

So here it is:

FileSystemWatcher class – this class is particularly used to “watch” the changes that occur on a particular map or folder or a group of files (for example: textual files).

The most important things in this class are:

Properties

  • string Filter  -  Gets or sets the filter string used to determine what files are monitored in a directory.
  • string Path  -  Gets or sets the path of the directory to watch.

Both of these properties are indicated in constructor: FileSystemWatcher(String path, String filter)
Initializes a new instance of the FileSystemWatcher class, given the specified directory and type of files to monitor.

  • NotifyFilters NotifyFilter – Here you specify what kind of events do you want to watch:
    • FileName - The name of the file.
    • DirectoryName - The name of the directory.
    • Attributes - The attributes of the file or folder.
    • Size - The size of the file or folder.
    • LastWrite - The date the file or folder last had anything written to it.
    • LastAccess - The date the file or folder was last opened.
    • CreationTime - The time the file or folder was created.
    • Security - The security settings of the file or folder.
  • bool IncludeSubdirectories - Gets or sets a value indicating whether subdirectories within the specified path should be monitored.
  • bool EnableRaisingEvents - Gets or sets a value indicating whether the component is enabled.

Events

  • Created  -  Occurs when a file or directory in the specified Path is created.
  • Changed  -  Occurs when a file or directory in the specified Path is changed.
  • Renamed  -  Occurs when a file or directory in the specified Path is renamed.
  • Deleted  -  Occurs when a file or directory in the specified Path is deleted.
  • Error -  Occurs when the internal buffer overflows.

For more information consult MSDN on FileSystemWatcher.

So here is the code I implemented for support of notifications.

First I implemented StartMonitorization method where i initialized my FileSystemWatcher, and wired the events to it. I also specified the name of the file to monitor (it is always the file i load or save), and set the events I want to catch. This was done by setting NotifyFilter = NotifyFilters.FileName | NotifyFilters.LastWrite. This means that I would like to catch the events then the filename is changed or when the file is saved. Then i set EnableRaisingEvents = true for my _fileMonitor. If this property is set to false, events are not generated.

Then I implemented the event handlers. First of all I got to say that I made a single handler for Created and Changed event, and another two for Deleted and Renamed events.

The workflow was easy: when an event occurs I display a message box and ask if user wants to reload the file in case of Created, Renamed, Changed events, or remove the file from text editor if i get the Deleted event. If user answers OK, then I execute the needed method.

 

Problems I’ve met

  1. Now the first problem I saw was that my methods were not executed because I try to modify the UI thread from watcher thread. That is not working that way. We need to use BeginInvoke method and to create a delegate in UI thread, and to pass him the names of the methods to execute. The difference is that this delegate is on UI thread, and he is allowed to execute the methods from the same thread. So I created LoadContentCallback delegate.
  2. Second problem that I had was that the events were generated twice. To solve this problem I created 3 boolean fields to match the events. When the event is generated I set this boolean to true. Second time I set it to false, without actually executing the logic. With the Deleted event I had no problems because i dispose the _fileMonitor once user deletes file from text editor.
  3. Changed event handler handled 2 events Created and Changed, so I was wondering how am I gonna determine which event is actually handled. But the arguments of the event FileSystemEventArgs helped me because there is a property WatcherChangeTypes e.ChangeType which indicate what kind of change was made. From here it was easy because I knew what boolean to reset.
  4. To determine the new file name when Renamed event occurs was super easy thanks to RenamedEventArgs class which contains the following info, that did helped me:
    • FullPath - Gets the new fully qualifed path of the affected file or directory.
    • Name  -  Gets the new name of the affected file or directory.
    • OldName  -  Gets the old name of the affected file or directory.
    • OldFullPath - Gets the previous fully qualified path of the affected file or directory.

 

private FileSystemWatcher _fileMonitor;

private bool _wasChanged;
private bool _wasRenamed;
private bool _wasCreated;

public delegate void LoadContentCallback();

private void StartMonitorization()
{
	_fileMonitor = new FileSystemWatcher(Path.GetDirectoryName(_fileName), Path.GetFileName(_fileName))
		{
			NotifyFilter = NotifyFilters.FileName | NotifyFilters.LastWrite,
			IncludeSubdirectories = false
		};

	_fileMonitor.Changed += FileMonitor_OnChanged;
	_fileMonitor.Created += FileMonitor_OnChanged;
	_fileMonitor.Deleted += FileMonitor_OnDeleted;
	_fileMonitor.Renamed += FileMonitor_OnRenamed;

	_fileMonitor.EnableRaisingEvents = true;
}

private void FileMonitor_OnRenamed(object sender, RenamedEventArgs e)
{
	if (!_wasRenamed)
	{
		DialogResult result = MessageBox.Show("The file " + e.OldName + " was renamed. \r\n" +
											"Do you want to load the new file ?", "File was renamed", MessageBoxButtons.OKCancel);

		_wasRenamed = true;

		if (result == DialogResult.OK)
		{
			_fileName = e.FullPath;
			this.BeginInvoke(new LoadContentCallback(LoadFileContent));
		}
	}
	else
	{
		_wasRenamed = false;
	}
}

private void FileMonitor_OnDeleted(object sender, FileSystemEventArgs e)
{
	DialogResult result = MessageBox.Show("The file " + e.Name + " was deleted. \r\n" + "Do you want to remove it from text editor ?", "File was deleted",
MessageBoxButtons.YesNo);

	if (result == DialogResult.Yes)
	{
		_fileMonitor.Dispose();

		this.BeginInvoke(new LoadContentCallback(ResetUiContent));
	}

}

private void FileMonitor_OnChanged(object sender, FileSystemEventArgs e)
{
	if ((!_wasCreated && e.ChangeType == WatcherChangeTypes.Created) ||
		(!_wasChanged && e.ChangeType == WatcherChangeTypes.Changed))
	{
		DialogResult result = MessageBox.Show("The content of the file " + e.Name + " was changed. \r\n" + "Do you want to reload it ?", "File was changed",
MessageBoxButtons.OKCancel);

		if (e.ChangeType == WatcherChangeTypes.Changed)
		{
			_wasChanged = true;
		}
		else
		{
			_wasCreated = true;
		}

		if (result == DialogResult.OK)
		{
			this.BeginInvoke(new LoadContentCallback(LoadFileContent));
		}
	}
	else
	{
		if (e.ChangeType == WatcherChangeTypes.Changed && _wasChanged)
		{
			_wasChanged = false;
		}
		else if (e.ChangeType == WatcherChangeTypes.Created && _wasCreated)
		{
			_wasCreated = false;
		}
	}
}

private void ResetUiContent()
{
	txtFileContent.Text = string.Empty;
	lblFileName.Text = string.Empty;
	_fileName = string.Empty;
}
PUTTING Keyboard shortcuts on your buttons

This is I think really the easiest part. First you wire up your form with KeyDown event, make a event handler (in my case it was ViewFile_KeyDown handler). Then you need to set your form KeyPreview property on true, because otherwise it would not be able to catch keyboard events.

Than you just indicate what kind of combination will execute your action. For example I wanted my app to react at       Ctrl + S as a save action shortcut. In event handler I just indicate that I want it to react on Control + S for saving and Control + O for loading/opening the file.

this.KeyDown += new System.Windows.Forms.KeyEventHandler(this.ViewFile_KeyDown);
this.KeyPreview = true;

private void ViewFile_KeyDown(object sender, KeyEventArgs e)
{
	if (e.Modifiers == Keys.Control)
	{
		switch (e.KeyCode)
		{
			case Keys.S:
				btnSaveFile_Click(btnSaveFile, null);
				break;
			case Keys.O:
				btnLoadFile_Click(btnSaveFile, null);
				break;
		}
	}
}
New Features coming…

Now I think about new features that could be done on top of what already exists:

I also think about migrating this app on WPF to provide better visual experience. I think I will do it in the next 2 releases.

The Entire Sourcecode

Here you can see entire sourcecode file in collapsed way.

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text;
using System.Windows.Forms;

// Author : Poperecinii Timur
namespace ViewFile
{
    public partial class ViewFile : Form
    {
        private string _fileName;
        private FileSystemWatcher _fileMonitor;

        private bool _wasChanged;
        private bool _wasRenamed;
        private bool _wasCreated;

        public delegate void LoadContentCallback();

        public ViewFile()
        {
            InitObjects();

            InitializeComponent();
        }

        private void InitObjects()
        {
            _fileName = string.Empty;
        }

        private void btnLoadFile_Click(object sender, EventArgs e)
        {
            OpenFileDialog ofd = new OpenFileDialog();

            ofd.CheckFileExists = true;
            ofd.Multiselect = false;

            DialogResult result = ofd.ShowDialog();

            if (result == DialogResult.OK)
            {
                _fileName = ofd.FileName;

                if (_fileName != string.Empty)
                    LoadFileContent();
            }
        }

        private void LoadFileContent()
        {
            lblFileName.Text = Path.GetFileName(_fileName);

            try
            {
                TextReader tr = new StreamReader(_fileName);
                try
                { txtFileContent.Text = tr.ReadToEnd(); }
                catch (Exception ex)
                { MessageBox.Show(ex.Message); }
                finally
                {
                    tr.Close();

                    StartMonitorization();
                }
            }
            catch (FileNotFoundException ex)
            { MessageBox.Show("Sorry, the file does not exist."); }
            catch (UnauthorizedAccessException ex)
            { MessageBox.Show("Sorry, you lack sufficient privileges."); }
            catch (Exception ex)
            { MessageBox.Show(ex.Message); }
        }

        private void StartMonitorization()
        {
            _fileMonitor = new FileSystemWatcher(Path.GetDirectoryName(_fileName), Path.GetFileName(_fileName))
                               {
                                   NotifyFilter = NotifyFilters.FileName | NotifyFilters.LastWrite,
                                   IncludeSubdirectories = false
                               };

            _fileMonitor.Changed += FileMonitor_OnChanged;
            _fileMonitor.Created += FileMonitor_OnChanged;
            _fileMonitor.Deleted += FileMonitor_OnDeleted;
            _fileMonitor.Renamed += FileMonitor_OnRenamed;

            _fileMonitor.EnableRaisingEvents = true;
        }

        private void FileMonitor_OnRenamed(object sender, RenamedEventArgs e)
        {
            if (!_wasRenamed)
            {
                DialogResult result = MessageBox.Show("The file " + e.OldName + " was renamed. \r\n" +
                                                    "Do you want to load the new file ?", "File was renamed", MessageBoxButtons.OKCancel);

                _wasRenamed = true;

                if (result == DialogResult.OK)
                {
                    _fileName = e.FullPath;
                    this.BeginInvoke(new LoadContentCallback(LoadFileContent));
                }
            }
            else
            {
                _wasRenamed = false;
            }

        }

        private void FileMonitor_OnDeleted(object sender, FileSystemEventArgs e)
        {
            DialogResult result = MessageBox.Show("The file " + e.Name + " was deleted. \r\n" +
                                                  "Do you want to remove it from text editor ?", "File was deleted",
                                                  MessageBoxButtons.YesNo);

            if (result == DialogResult.Yes)
            {
                _fileMonitor.Dispose();

                this.BeginInvoke(new LoadContentCallback(ResetUiContent));
            }

        }

        private void FileMonitor_OnChanged(object sender, FileSystemEventArgs e)
        {
            if ((!_wasCreated && e.ChangeType == WatcherChangeTypes.Created) ||
                (!_wasChanged && e.ChangeType == WatcherChangeTypes.Changed))
            {
                DialogResult result = MessageBox.Show("The content of the file " + e.Name + " was changed. \r\n" +
                                                      "Do you want to reload it ?", "File was changed",
                                                      MessageBoxButtons.OKCancel);

                if (e.ChangeType == WatcherChangeTypes.Changed)
                {
                    _wasChanged = true;
                }
                else
                {
                    _wasCreated = true;
                }

                if (result == DialogResult.OK)
                {
                    this.BeginInvoke(new LoadContentCallback(LoadFileContent));
                }
            }
            else
            {
                if (e.ChangeType == WatcherChangeTypes.Changed && _wasChanged)
                {
                    _wasChanged = false;
                }
                else if (e.ChangeType == WatcherChangeTypes.Created && _wasCreated)
                {
                    _wasCreated = false;
                }
            }
        }

        private void ResetUiContent()
        {
            txtFileContent.Text = string.Empty;
            lblFileName.Text = string.Empty;
            _fileName = string.Empty;
        }



        private void btnSaveFile_Click(object sender, EventArgs e)
        {
            SaveFileDialog saveFileDialog = new SaveFileDialog();
            saveFileDialog.Filter = "Text Files (*.txt)|*.txt|C# files (*.cs)|*.cs|All files (*.*)|*.*";

            saveFileDialog.SupportMultiDottedExtensions = true;

            DialogResult result = saveFileDialog.ShowDialog();

            if (result == DialogResult.OK)
            {
                _fileName = saveFileDialog.FileName;
                
                if (!string.IsNullOrEmpty(_fileName))
                    SaveFileContent();
            }
        }

        private void SaveFileContent()
        {
            lblFileName.Text = Path.GetFileName(_fileName);

            try
            {
                // we'll make only a textual file for instance
                TextWriter tw = File.CreateText(_fileName);

                try
                {
                    tw.Write(txtFileContent.Text);
                }
                catch (Exception ex)
                { MessageBox.Show(ex.Message); }
                finally
                {
                    tw.Close();

                    StartMonitorization();
                }
            }
            catch (UnauthorizedAccessException ex)
            { MessageBox.Show("Sorry, you lack sufficient privileges."); }
            catch (Exception ex)
            { MessageBox.Show(ex.Message); }
        }

        private void ViewFile_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.Modifiers == Keys.Control)
            {
                switch (e.KeyCode)
                {
                    case Keys.S:
                        btnSaveFile_Click(btnSaveFile, null);
                        break;
                    case Keys.O:
                        btnLoadFile_Click(btnSaveFile, null);
                        break;
                }
            }
        }
    }
}

Monday, October 5, 2009

Code4Food #2: Create a Text Editor in 5 minutes. C# - magic

Hi, guys!
It is October and it's the time for another Code4Food episode.

Today I'm gonna show you some magic. We'll make a text editor in C#.


Here is the sourcecode for Downloading:
ViewFile sourcecode


Note: This part will contain only loading certain file in a textbox.

1st minute.

a) Create a new WinForms app in Visual Studio (File -> New -> Project -> Windows Forms Application) and change the name of the project to ViewFile.


b) Delete the form Form1.cs from the solution.



c) Add a new form to the project and name it ViewFile


2nd minute

a) Open the ViewFile form in Designer mode. Add a textbox to this form and name it txtFileContent. Change it's 'Multiline' property to true, and 'ScrollBars' to 'Both'.


b) Change it's size to fit the form. After this change the 'Anchor' property to 'Top, Bottom, Left, Right'.


c) Add a button to the form and name it btnLoadFile and change it's 'Text' property to 'Load File'.
d) Add a button to the form and name it btnSaveFile and change it's 'Text' property to 'Save File'.

e) Add a label where we'll show the file name. Name it lblFileName and change it's 'Text' property to 'File Name'

f) In Program.cs change the following line so that your application runs the ViewFile form.
Application.Run(new ViewFile());

At this point you can run the User Interface of our app.


3rd minute

a) Create a private field _fileName where we'll store the name of the file we want to open. Create than a method where we'll initialize all the fields in our app and name it InitObjects. Initialize there _fileName to string.Empty. Also we'll make the filename label empty for now, because we don't have a file opened.

b) Double click the 'Load File' button and in the event generated by Visual Studio create an instance of OpenFileDialog. Set the properties of this instance: 'CheckFileExists' (verifies if the file exists) - true, 'Multiselect' (the ability to select multiple files in the dialog at once) - false. And call the method ShowDialog.

c) When the file is selected we'll show in the label only the name of the file which is stored in 'SafeFileName' property of the OpenFileDialog instance. Also save the full path to the file in _fileName field, and it is equal to 'FileName' property of the instance of the dialog.

Now our code should look like this:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace ViewFile
{
public partial class ViewFile : Form
{
private string _fileName;

public ViewFile()
{
InitializeComponent();
InitObjects();
}

private void InitObjects()
{
lblFileName.Text = string.Empty;
_fileName = string.Empty;
}

private void btnLoadFile_Click(object sender, EventArgs e)
{
OpenFileDialog ofd = new OpenFileDialog();

ofd.CheckFileExists = true;
ofd.Multiselect = false;

ofd.ShowDialog();

_fileName = ofd.FileName;
lblFileName.Text = ofd.SafeFileName;
}
}
}


4th minute

Now what we need to do is read the file and show its content in our textbox.
We'll use the StreamReader class, specifically its method ReadToEnd() and nested try-catch blocks to catch all the potential exceptions while we are trying to open a file.

So the final version of our app logic is this:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace ViewFile
{
public partial class ViewFile : Form
{
private string _fileName;

public ViewFile()
{
InitializeComponent();
InitObjects();
}

private void InitObjects()
{
lblFileName.Text = string.Empty;
_fileName = string.Empty;
}

private void btnLoadFile_Click(object sender, EventArgs e)
{
OpenFileDialog ofd = new OpenFileDialog();

ofd.CheckFileExists = true;
ofd.Multiselect = false;

ofd.ShowDialog();

_fileName = ofd.FileName;
lblFileName.Text = ofd.SafeFileName;

if (_fileName != string.Empty)
LoadFileContent(_fileName);
}

private void LoadFileContent(string chosenFileName)
{
try
{
TextReader tr = new StreamReader(chosenFileName);
try
{ txtFileContent.Text = tr.ReadToEnd(); }
catch (Exception ex)
{ MessageBox.Show(ex.Message); }
finally
{ tr.Close(); }
}
catch (System.IO.FileNotFoundException ex)
{ MessageBox.Show("Sorry, the file does not exist."); }
catch (System.UnauthorizedAccessException ex)
{ MessageBox.Show("Sorry, you lack sufficient privileges."); }
catch (Exception ex)
{ MessageBox.Show(ex.Message); }
}
}
}

5th minute


For now we can really open any file but I wanted to make it look like a source code file. And disable some things we don't actually use.



a) We'll make the button 'Save File' disabled. Because we don't actually use it.

b) We'll change the 'Font' property of the txtFileContent to 'Courier New; 9pt'









Wednesday, September 2, 2009

Code4Food #1: Frank Car Assistant application.

Hi! There are a lot of situations when you as a programmer need to code just for 5 bucks. Of course you don't have to put your soul in these kind of programs, if you don't want to, but remember if you will make a nice piece of code, which will satisfy all client's requirements, you will definitely be able to buy some caviar as a bonus to your butter and bread. Ladies and gents, Code4Food series is starting. Yesterday I was talking to my online friend Frank. He already studied Java programming language so I thought I should presented him C# language, writing down some simple examples. I'm gonna try to present you the same thing using the same examples. Here is the sourcecode for Downloading: FrankTestConsoleApp sourcecode FrankCarAssistant sourcecode

"Hello World"

So first program is like always HelloWorld 1. File -> New -> Project 2. Choose Project types -> Visual C# -> Windows -> In templates choose Console Application 3. Choose a name for your project. In my case I chosen the name FrankTestConsoleApp. In Program.cs file we will have the following thing:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace FrankTestConsoleApp
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("Hello World!!!");

            Console.ReadKey();
        }
    }
}
Another thing that I was showing was some loops from C#. We first create an array of strings and than we call each string using different loops.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace FrankTestConsoleApp
{
    class Program
    {
        static void Main(string[] args)
        {
            string[] names = { "Frank", "Timur", "Jessica", "Helen" };

            Console.WriteLine("=======FOR loop=========");

            for (int i = 0; i < names.Length; i++)
            {
                Console.WriteLine("Hello {0}!", names[i]);
            }

            Console.WriteLine("=======FOREACH loop=========");

            foreach (string name in names)
            {
                Console.WriteLine("Hello {0}!", name);
            }

            Console.WriteLine("=======WHILE loop=========");

            int index = 0;

            while (index < names.Length)
            {
                Console.WriteLine("Hello {0}!", names[index]);
                index++;
            }

            Console.ReadKey();
        }
    }
}
So the result is the same for each loop.

Car class

The next thing we did was creating a Class Library Project CarsModel. 1. File -> New -> Project 2. Choose Project types -> Visual C# -> Windows -> In templates choose Class Library When you create a Class Library project it means that all the classes which will be in this project will be built into a single .DLL file. A DLL file can contain multiple namespaces. In this project we created a class Car which contains 2 properties: int WheelNumber and a string Name, and a method PrintInfo, and 2 constructors. A property is a public accessor to a private field of the class. This is an analog for Java's get and set methods. For example: we have a private field _wheelsNumber which can be accessed by other classes using the WheelNumber property. A property can have 2 parts get and set. When you have in your property the get part it means that the other class can read the value of your private field. The set part of the property allows to set a value for the private field of the class. In fact when you read a property (ex.: int numberOfCars = car.WheelNumber) everything inside the get part is executed (in our case it's get { return _wheelsNumber; }). When you write a value into a property (ex.: car.WheelNumber = 3) everything inside the set part is executed. You can have properties with only get or only set part. It means that you can only read or write into this property. The PrintInfo method was only used for printing to our console the Car data (name and wheels number). By creating this method into the Car class we made it possible to call this method from the class instance (ex.: car.PrintInfo()). This way of programming is called to delegate to an object a method, usually it is used when you refactor your old code and you see that a method only uses the instance of a class, for example X. It is than logically to move this method into the class X itself, than you can simple call x.RefactoredMethod() In this class we also have 2 constuctors with and without parameters. The constructor with parameters initializes the properties of this class. The default constructor (without parameters) initializes the properties with its default values (for int it is 0, and for string it's string.Empty).
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace CarsModel
{
    public class Car
    {
        private int _wheelsNumber = 0;

        public int WheelNumber
        {
            get { return _wheelsNumber; }
            set { _wheelsNumber = value; }
        }

        private string _name = string.Empty;

        public string Name
        {
            get { return _name; }
            set { _name = value; }
        }

        public Car()
        {

        }

        public Car(int wheelz, string carName)
        {
            this.WheelNumber = wheelz;
            this.Name = carName;
        }

        public void PrintInfo()
        {
            Console.WriteLine(this.Name);
            Console.WriteLine(this.WheelNumber);
            Console.WriteLine("=================");
        }
    }
}

Frank Car Assistant Console Application

Than we build the project and added its DLL file to the references of the FranksTestConsoleApp, and made a little console application which I'm gonna try to explain.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using CarsModel;

namespace FrankTestConsoleApp
{
    class Program
    {
        static void Main(string[] args)
        {
            List<Car> listCar = new List<Car>();

            Car franksCar = new Car(2, "Honda Civic");
            Car timurCar = new Car(1, "4x4");

            listCar.Add(franksCar);
            listCar.Add(timurCar);
            listCar.Add(new Car(14, "Jessica"));

            bool iWantToLeave = false;

            while (!iWantToLeave)
            {
                Console.WriteLine(Environment.NewLine);

                PrintHelp();

                Console.WriteLine(Environment.NewLine);

                int numberEntered = int.Parse(Console.ReadLine());

                switch (numberEntered)
                {
                    case 2: RemoveCarFromList(listCar);
                        break;
                    case 3: listCar.Add(AddNewCar());
                        break;
                    case 4: iWantToLeave = true;
                        break;
                    default: ShowMeTheCars(listCar);
                        break;
                }
            }

            Console.WriteLine("Bye");

            Console.ReadKey();
        }

        /// 
        /// Prints the current list of cars.
        /// 
        /// The lists of cars.
        private static void ShowMeTheCars(List<Car> listCar)
        {
            Console.WriteLine(Environment.NewLine);

            foreach (Car carName in listCar)
            {
                carName.PrintInfo();
            }
        }

        /// 
        /// Prints the help.
        /// 
        private static void PrintHelp()
        {
            Console.WriteLine("This is the Frank car system assistant");
            Console.WriteLine("PRESS");
            Console.WriteLine("1 - To see the list of the cars");
            Console.WriteLine("2 - To remove a car from the list");
            Console.WriteLine("3 - To add a car to the list of the cars");
            Console.WriteLine("4 - To say 'Bye'");
        }

        /// 
        /// Adds the new car.
        /// 
        /// The new car object
        private static Car AddNewCar()
        {
            Console.WriteLine("Enter the name of the car: ");
            string name = Console.ReadLine();
            Console.WriteLine("Enter the number of wheels: ");
            int number = int.Parse(Console.ReadLine());

            return new Car(number, name);
        }

        /// 
        /// Removes the car from list.
        /// 
        /// The list of cars.
        private static void RemoveCarFromList(List<Car> listCar)
        {
            string nameOfTheCar = Console.ReadLine();

            Car searchedCar = listCar.Find(delegate(Car car) { return car.Name == nameOfTheCar; });

            if (searchedCar == null)
            {
                Console.WriteLine("ERROR! We don't have this car, really, don't try to find it.");
                return;
            }

            listCar.Remove(searchedCar);
        }

    }
}
So first I'm gonna explain what this application is doing. So it can print you the help menu and depending on the part you select, it can show the list of cars available with it's characteristics, add a new car or remove a car with a certain name. The PrintHelp method only prints some bunch of strings. In the beggining of our Main method what we do is initialize a List of our object Car from CarsModel namespace, and we add some custom cars in it.
List<Car> listCar = new List<Car>();

Car franksCar = new Car(2, "Honda Civic");
Car timurCar = new Car(1, "4x4");

listCar.Add(franksCar);
listCar.Add(timurCar);
listCar.Add(new Car(14, "Jessica"));
In the AddNewCar method we create a new car by entering its name and the number of the wheels for this particular car and than return this car. ShowMeTheCars method calls for each Car object from a list of cars (listCar) its method PrintInfo(). The most interesting method is RemoveCarFromList method. What I am doing there is trying to show the power of List objects in C#. Firstly we have a Find method in List object which permits us to find an object from the list which satisfy a specified condition. Car searchedCar = listCar.Find(delegate(Car car) { return car.Name == nameOfTheCar; }); In this example the condition is that the name of the car which we indicated (nameOfTheCar) should coincide with the car's name from the list (car.Name). And for formulating it we create a delegate with the list's object as an argument which should return a boolean value (true or false), according to specified condition. Than in Main method we create a boolean field iWantToLeave = false, and we will loop, while we'll want to leave. Firstly we'll call PrintHelp method, than we'll parse the introduced number, and will pass this number in a switch statement, and treat each case apart. Notice that we'll have a default case, when any other number than specified in case statements will be introduced. If the user choose the exit option I just set the field iWantToLeave = true and the while condition isn't already passed and we close the app.

Frank Car Assistant App

Now we need to translate the application logic from a console app to a windows forms app.
1. File -> New -> Project 2. Choose Project types -> Visual C# -> Windows -> In templates choose Windows Forms Application
First we draw our form. And add into references of this project the CarsModel.dll file.
Now for the Add Car and Remove Car buttons we use the same code as for our console application.
The interesting part comes to populating our listbox and refreshing it.
For populating listbox we added this code:
BindingSource bSource = new BindingSource();
...
private void Form1_Load(object sender, EventArgs e)
{
   InitListOfCars(listCar);

   bSource.DataSource = listCar;

   lstCars.DataSource = bSource;
   lstCars.DisplayMember = "Name";
}
This means we have a binding source and we put it it (as its Datasource) the list of our cars. Now we put this binding source as Datasource of the listbox. In listbox.DisplayMember we choose the property of our object which will be shown in listbox, in our case it is name that we want to show. We decided that we need to fill in the textboxes with the data of selected car. This is made by this code:
private void lstCars_SelectedIndexChanged(object sender, EventArgs e)
{
   txtCarName.Text = (lstCars.SelectedItem as Car).Name;
   txtNumberOfWheels.Text = (lstCars.SelectedItem as Car).WheelNumber.ToString();
}
And we most difficult part was to find out how to update listbox data when we add or remove a Car object. The solution s this line: bSource.ResetBindings(true); the program generates automatically a Reload event when the flag is equal to true, and the datasource for bindingSource is reloaded.
So that have been the longest post of mine so far, but we've done a lot of stuff this time. Hope you liked it! Next time we'll be thinking about possible improvements and bugs in Frank Car Assistant application, and will try to fix them.