| Neil Bamber's profileFriendMap - Made in Expr...BlogLists | Help |
|
|
8/5/2006 Publish.The Publish functionality in Visual C# Express worked a treat; everything is working nicely on all the different computers I’ve tested it on (thanks to Justin, Arron and Gavin). The final package compresses nicely into a RAR at about 500k, I’d put it up for download but I’m not sure if that would violate any rules. The project should be downloadable after it’s submitted anyway.
Using the publish functionality in the Visual C# Express was a breeze. The only problems I had stemmed from my idiocy where I had a hard coded database connection string. Of course I found that out after I had waited for the .NET 2.0 and SQL Server Express to install the 333 MHz Celeron test machine I was trying it on. :)
To publish your project go to the Project menu, and choose ProjectName Properties, where ProjectName is your project name. Click the Publish link on the left and then select where you want to publish the project to, I put it in a temp directory on my hard drive. Click the Options button and then enter the appropriate information about your project, name, language, etc. Once you’ve entered that information uncheck the Automatically increment revision with each publish option. That way when you mess up the first ten times it’s still at 1.0.
Then click the Publish Wizard button to go through a few more options and then your application should be published. The great thing about the Publish functionality is that it checks if the user has .NET 2.0 and SQL Express Server and if it doesn’t fetches and installs them for the user. The installer also adds the program to the Add/Remove programs list in Windows. This makes things so much simpler from my point of view.
The only problem (aside from my silly connection string issue) was the help file not being included in my published application. I fixed this by changing the properties of the help file in my project. I set Copy To Output Directory to Always and changed the Build Action to content. The next time I published the application the help file was included as expected. One other minor issue I had was the installer having problems installing over a previous version but that isn’t exactly rare.
I’d like to use the Auto Update functionality, it looks really simple to implement and for on going projects I imagine it would be hugely useful to developers. To check out the functionality click the Updates button just above the Options button on the Publish page.
Good luck to all contestants that end up submitting their project, I hope you’ve all enjoyed the competition as much as I have. It’s given me a nice timeline to work through and I feel a nice fuzzy feeling deep down inside that all work in the project has been completed by me, no inclusion of anyone else code or work. For now I’m going out to celebrate :) 8/3/2006 Circles.Last night I sat down and wrote the help file for my application. I wrote the topics in word and then used HTML Help to compile them into the CHM format. HTML Help was a little bit temperamental and didn’t compile a few times due to the paths of the html files. Everything seemed to be fine if you didn’t save and load the project again though so I just did it all at once. I couldn’t figure out how to create sections in the help file but since there aren’t too many pages I didn’t fuss over it. The file loads and displays nicely from within my application and even though HTML Help is a bit archaic I’m glad I went the CHM route.
Writing the help file was (as everyone would expect) boring however it made me use my application and helped me discover a few more bugs, so in that regard it was a worth while process. Now I just need to work on fixing the newly discovered bugs before the project is due.
One bug I did fix today was my line drawing problem when relationships were more than one person deep. I’d thought about this problem for a while but never reached a work able solution, I originally thought of storing the “parent” circle as a property but that idea was shot when I came to implement it due to the way I draw friends using recursion. So the parent would be updated anytime there were children, which would leave me with the same problem.
So after looking at the code and thinking about how I could do it I came up with the idea of moving X number of circles backward, where X is the number of children a parent has. This was pretty easy to do, if the parent circle was on the same line as the child circle (X – (size * childCount)), but when the child circle was on the next line it got a little more complicated. I spent a lot longer (45 minutes) figuring the problem out and implementing it than I would have liked (15 minutes) seeing as the solution ended up being pretty simple. Calculate the number of pixels behind X we are, determine how many circles can fit in that amount of pixels (the number of circles on the new line we need to move back), then determine the new X position by maxCirclesPerLine – previousLineCircles * circleSize.
I expect most of the remaining bugs and features to be fixed or added by tomorrow night and then I’ll spend Saturday figuring out how to distribute my program so people can actually use it. 7/31/2006 Lines.
Linked above is the work I accomplished today, I added code to determine and draw the strength of a relationship link. This formula takes into account the friend rating, the years the friend has been known, the importance and rating of the last event and the days since the last event. I then multiplied that figure (it’s always between 0 and 1) by 7 and there you go, weighted lines. Why 7? Because that’s what looked the best on the map. :)
Another cool .NET feature I learned about today (and appreciate even more after having been doing a rather date math heavy PHP app at work recently.) is the TimeSpan class used in conjunction with the DateTime.Subtract() method. The TimeSpan class in my application is used to get the number of days since the last event and today. However you can also get information such as hours, seconds, milliseconds etcetera.
Something that was a little harder than I though it would be was creating a context menu for my Friends DataGridView. I assumed that I’d be able to access the RowIndex through a menu item click, however I couldn’t. I also figured that the row I had clicked on would become selected. I had a look through the DataGridView events (is there an object with properties and events than a DGV?) and found the RowContextMenuStripNeeded event, by firing this event I’m able to get the RowIndex, I store the RowIndex in the ContextMenu’s tag for easy access. I also select the DataGridView row in this method with the line, dgvFriends.Rows[e.RowIndex].Selected = true;
Tomorrow I hope to work on the circle weighting (and possibly colouring, I’m not sure if I’ll implement that yet.) and add a ContextMenu for the events DataGridView. Other than using it as a shortcut to load friends and events I’m not sure what else I can put in the ContextMenus. It feels wrong only having one option to choose from in a ContextMenu. 7/30/2006 Another Lazy Sunday.I think it’s safe to say that Sundays are not my best developing days. I didn’t get a whole lot done today and only spent about four hours on my application. I started the day with good intentions but then it went down hill from there. On the upside Ninety Nine Nights for the 360 looks fun and I finished Cloning Clyde.
Application wise I worked out a few more bugs and shined up a few areas of the application. One problem I was having that I mentioned last week (I think) was my contacts owner drawn ListBox not drawing anything. I spent ages one day last week trying to figure out why the DrawItem and MeasureItem events were not firing. I looked through my code, multiple times over, I checked that the events were actually set up (unlike last time this happened), they were and I checked the designer code and everything seemed fine. I wanted to get this fixed today so I sat down and had a look again and ended up finding out the problem. For some reason this line had been removed from the designer code, this.Controls.Add(this.lstContacts);. So the ListBox was never added, except the control displayed as a ListBox on the form in the designer and when the application ran. In the end I was happy it was fixed but still annoyed it took so long to fix.
Oh well. Today I ended up fixing all but one of the bugs on my list. Tomorrow should be more productive and I’ll try and get that bug fixed. Depending on how quickly I’m able to fix it I may also start adding a few more small features just to make things a little more hectic. 7/29/2006 Bug Fixing.After a fair bit of “research” last night I sat down this morning to begin working though my TODO and BUG list, grabbing at the low hanging fruit first. I’ve fixed 25 bugs today so far, but they are all of the relatively easy ones and a few of the more medium difficulty ones. Regardless of how hard the bugs have been to fix the time I’ve spent today is well reflected in the applications quality.
One of the areas of my application I wanted to fix today was the ComboBoxes. I’ve used ComboBoxes fairly extensively through out my application and they were generally filled with entries from the database. This was all well and good except that users could still put their own entry in and that would cause problems. This problem was something that I thought would be easy to fix and I never got around to finding out how to make a ComboBox read only. Well, for a change, I was right and making a ComboBox read only is as easy as setting it’s DropDownStyle property to DropDownList.
In fixing these bugs I’ve come across an issue with the ToolStrip smart tag, when I remove buttons from a ToolStrip using the Edit Items… link that are between other buttons, the spacing of the buttons stays the same in the designer, as if the deleted buttons were still there. However when the application runs the buttons are aligned properly. The buttons stay the same even after rebuilding the project.
In other news that developers may be interested in Microsoft has announced Sandcastle, a documentation compiler http://blogs.msdn.com/sandcastle/. While I wouldn’t find a use for it on a small project such as this (especially as there is little to no documentation) on a larger project it would be great. It’s also great to see Microsoft releasing more free tools for developers.
I’m pleased I decide against implementing a the FriendMap control as a planar graph. It would have caused me a significant amount of stress trying to get it working in such a short period of time and would have prevented me from fixing existing issues, although it would have looked a lot nicer than the current implementation. Tomorrow I plan on climbing the tree a bit and taking a swing at the medium and high hanging fruit. That’s usually sweeter right? 7/27/2006 Escaping SQL.I’ve been terribly busy with a few real life things since I got back so I’ve not had much time to do any work on my application. I’m slowly progressing bit by bit though. For the little time I programmed today I fixed some bugs and added some code to escape the SQL queries the user can add input to.
Escaping SQL in .NET is apparently done automatically when using ADO.NET correctly by using the following code.
SqlCommand command = new SqlCommand("SELECT * from people where name = " + txtFilter.Text, dbConn)But I’m not using ADO.NET correctly so that’s crazy talk. The way I’m doing it is escaping the user input using the Regex.Replace() function, as so.
private string EscapeText(string text) { return Regex.Replace(text, "'", @"''"); }
Again, I really need to learn ADO.NET properly. :)
Tomorrow will be another busy day where I won’t have any time to work on my program. I’ll have to spend the majority of this weekend fixing bugs and getting my application ready for submission. It’s getting close. 7/23/2006 Holiday!I fixed my problem yesterday of the DataSet not being updated, well more worked around it. After trying everything I could think I eventually gave up and tried working around it. In the end I selected what I wanted from the table, then set the properties of the combo box to display what I selected. I’ll paste the code below to show you what I mean.
private void FillEventCategory() { DatabaseInfo dbInfo = new DatabaseInfo(); SqlCommandBuilder sqlCb; string query = "select event_category_id, name from event_category"; SqlDataAdapter dataAdapter = new SqlDataAdapter(query, dbInfo.ConnectionString); sqlCb = new SqlCommandBuilder(dataAdapter);
DataSet dataSet = new DataSet(); dataAdapter.Fill(dataSet); DataTable dataTable = dataSet.Tables[0];
cmbEventCategory.DataSource = dataTable; cmbEventCategory.DisplayMember = "name"; cmbEventCategory.ValueMember = "event_category_id"; }
This code is called from the forms OnLoad event and as you can see selects fields from the event category table and sets the DataSource of the combo box to the results, and then sets the DisplayMember and ValueMember properties. I know this isn’t the correct way but it’s the way that ended up working for me. I’m looking forward to getting the ADO.NET Programming book from Manning Publications so I can see what the correct way use ADO.NET is.
With that I’m off for two days to read up on graph theory and how I can use it in my application. I think I’ve updated my blog every day this month so hopefully no one will miss me :P 7/22/2006 Saturday!I got very little done today; I caught up with a friend after being behind him on the freeway coming home this morning. Lunch turned into mixing which then turned into dinner and then playing xbox for a while, oh well, I’m on holiday. I did get a little bit of coding done but not too much, I fixed a plainly obvious bug that was displaying the category id rather than the text.
One of the other bugs I wanted to fix today wasn’t fixed, my noob ADO.NET code came to bite me in the ass as I thought it would. When adding events or friends the categories and such are selected from the data sets. Since my code updates the database directly the data set stays the same. I’ve tried a few different things (DataSet.Table.Rows.Add(newRow), updating the dataset from the database) but couldn’t get it working; I’ll have to look into it a bit more closely in the few hours I’ve got tomorrow. 7/21/2006 Uh oh.Unfortunately drawing the lines in a neat way isn’t as easy as I was hoping it would be, I’ve had a look around and deduced that my problem is related to Graph Theory. Graph Theory is the drawing of points and the lines from those points, in my FriendMap application each friend is a point, and the link between them can be represented by line. In my applications case I want an undirected, planar graph. An algorithm that produces no intersections is better than one that does produce intersecting lines, however not all graphs can be drawn in such a way. Wikipedia has more information about Graph Theory here. Looks like I’ll be taking some light reading along on my two day holiday.
Of course simply reading about Graph Theory isn’t going to solve my problem. I’ve already thought about ways I can display the map in a neater fashion and after I’ve read up a little more I’ll try and implement it. What I’m imagining is the owner point being moved into the centre of map and links being drawn from there. The same principle would be followed for friends who are linked to other friends. So if I’m friends with Friend A and Friend A knows Friends B, C, and D. The owner point (me) would be in the centre of the screen, linked to Friend A would be centre of Friends B, C and D. What I’m a little unclear on at the moment is how to store where people are located or even if I need too after they’ve been drawn. As I said, I’ll do more reading while I’m away.
I’ll try spending a few days after I get back implementing a cleaner graph and if I can’t do that I’ll have to submit with the graph I have now. Since I won’t be implementing the new graph tomorrow I’ll spend the day going through the application and fixing bugs. There are a fair few small bugs that I’ve left behind in the pursuit of getting my application close to finished. 7/20/2006 Cloning Neil.
I didn’t get too much done today due to a longer day at work and using an hour of my development time playing the new Xbox Live Arcade game Cloning Clyde (I could certainly use some clones.). I accomplished what I set out to do though which is good, the drawing of the lines didn’t take as long as I thought it would.
Linked above is the result of tonight’s work. Relating to yesterdays post I figured out why the MessageBox informing the user the map had run out of space was being continually displayed. It was something pretty silly and due to my inexperience with Windows.Forms. Drawing the MessageBox over the control invalidated the panel, causing the panel to be redrawn, redrawing the panel in the same size results in the same message being displayed, which invalidates the panel. Hooray for infinite loops! I didn’t realise the panel was being redrawn when the MessageBox was displayed. To solve the issue I simply wrote the error on the Panel using the DrawString method, the error is red so it stands out.
Once I had that problem fixed it was time to start drawing the links between friends. This ended up being easier than I thought it would be and just involves using the function DrawLine from the Graphics class to, surprisingly, draw a line. Lines are drawn between two points, the starting circle and the destination circle (I used Point objects to set where the lines are drawn but there are a few overloads for DrawLine).
As you can see the map looks very messy with lines intersecting circles and other lines. I’m not too sure at the moment how I’m going to tidy it up. I’ll look into it more tonight and tomorrow and post my findings. The map at the moment isn’t displaying relationship strength or any other information I want it too. I’ll leave that until last, I’d rather have it display cleanly first.
There won’t be any programming done tomorrow (well, at least on this project) since I’ll be heading out for a change. If I’ve figured out how to implement a cleaner graph I will start work on that Saturday and hopefully muse about any problems I’m having and how they can be fixed while I’m away. 7/19/2006 Friends Drawn.
Here is tonight’s screen shot, as you can see the map is now drawing some of the other friends. This was pretty simple do with how I set up the draw text and circle code. The DrawFriends() method selects all friends that are parents in their relationships, or don’t have any relationships. Each person is then drawn on the map and after they drawn the code checks if they have any children and if they do the child friend is drawn, which then checks if that child has any friends, this is done using recursion and allows an infinite amount of relationships, in case you wanted to track a few hundred generations of family?
Another major development from last night’s screenshot is the circles and text looking 100% better. I was talking to a friend this morning and he gave me some tips on how to make it look better. By using the following two lines.
g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias; g.TextRenderingHint = System.Drawing.Text.TextRenderingHint.AntiAlias;
This applies Anti Aliasing to the drawn shapes and lines and the drawn text. Anti Aliasing makes the drawn text and circles look smoother by removing the ‘jaggies’ or sharp edges. How does it do it? Magic. Pure unadulterated magic. Wikipedia may be more correct than I am though, so if you want to know I’d suggest you go here.
I’d also like to retract something I said yesterday, you can make a rectangle with out using integers. RectangleF is the object you use for that. I should pressed the down key a few more times :)
So now that friends are being drawn on the map what next? I need to fix a small but annoying problem I’m having with the drawing of the control. If there are too many friends to display the map continues trying to draw them and giving the user the too popular message, over and over again. I’ve tried setting variables so it isn’t displayed any more and I’ve tried only displaying it once the map has finished drawing, but it’s coming up multiple times for reason. I’ve spent a disproportionate amount of time on a problem that should be simple. Once I’ve nailed that down I’ll start adding links between the circles, I think this part of the application will be the most troublesome. If I can get this part finished before I go away I’ll be very happy. 7/18/2006 Too Popular!
Linked above is the latest screenshot of my application, similar to yesterdays except the text positioning has been fixed up (though it’s still a little buggy) and there are multiple circles with my name in it, why? I’m really popular with my self as the message box says.
What the screenshot is really demonstrating is code to determine when the map can not draw any fit any more circles in it. Usually these would be friend circles but I’ve not got that far yet and just created an event to draw the owner circle multiple times. I didn’t get much besides this done today, I spent far too long doing my head in thinking about I can check if a circle is intersecting another circle. Which annoyed me because the answer was really simple; I’m not sure why I didn’t come up with it sooner.
The DrawEllipse() method can take a rectangle to draw the ellipse in. For me it’s a lot easier to work out if a square is over lapping another square, especially when the squares are in a rectangular container, so this is the solution I used. At the moment a circle is 20% of the original panel width, the space between circles is the circle width / 2. After each circle is drawn the coordinates for the next circle are updated, if the previous circle is at X, Y the next circle has to be at (X + circle size + ½ circle size), Y unless that X coordinate (plus a circle) is greater than the panel width. In that case the coordinates need to be X, (Y + circle size + ½ circle size). This fell into place when I realised circles could be represented by squares.
One thing I found a little annoying was that when creating a rectangle it couldn’t take float values for the size. So there is a bit of casting and rounding going on to get integers out of floats. So when I say ½ circle size I really mean Math.Round(circle size / 2, 0);.
Today was pretty successful, even though I didn’t accomplish what I set out to achieve (drawing friends on the map). I’ll attempt to get friends drawn on the map tomorrow if time is on my side. Speaking of time I’ll be taking some out Sunday and Monday, I’m having a mini holiday to the south west of Western Australia which will be extremely relaxing, so no blog entries on those days. :) 7/17/2006 Application Screenshot.
It’s all coming together; well at least the screen shot makes it appear that way. I didn’t get much time after work today to get much done. Though I did some design on paper to work out exactly what I needed to create and how that should be done. I’m still a little unclear on a few things, but I’ll get there in the end. One other part of the design of the control I did today was creating the formulae (formulas? www.dictionary.com says both are acceptable.) for ranking friends and events, they (especially the friends formula) could use some fine tuning, and who knows I might change it entirely before I actually implement it :)
The actual implementation of the friend map control is similar to the code I posted yesterday. Except here I have the panel’s paint method calling other methods to draw the individual parts. Drawing friends and links between people is going to be a fairly involved process and putting it all in the panel’s paint method would be messy to say the least.
Tomorrow I plan on cleaning up the code so the text in the initial circle is drawn in the middle and fixing a few other things (at the moment my name is hard coded, I’ll change that to dynamic tomorrow). Once I’m happy with that I’ll begin adding code for drawing the circles of other friends. I’m thinking of selecting all friends from the friends table that don’t have links, or are parents in their links and then one by one draw each friend on the map, and if they have links draw their links. I’m not quite sure how I’ll make the map look pretty with out having circles or links between friends over lapping each other and I’m sure I’ll run into quite a few issues I’m not yet aware about. So we’ll see where I’m at tomorrow. 7/16/2006 GDI+ Amateur
Linked above is a screenshot of what I accomplished last night, not overly productive, to be fair though it’s really my first time trying to draw something using System.Drawing class. The main reason I go little done was because I didn’t know what I was doing for the most part and why my picture wasn’t drawing. So after trying by my self to get the code working I turned to Google and apparently the mistakes I was making are really common for first timers.
I was trying to draw in a PictureBox by creating a graphics object from it, Graphics g = pboxImage.CreateGraphics();. While this allows the program to draw on the picture box when changes are made they aren’t saved because the changes are made above the PictureBox rather than actually on the PictureBox’s image. In my case I was trying to draw this way before the form loaded, and then when it was loaded it refreshed and my changes were lost.
This was all made clear to me after reading an excellent FAQ by Bob Powell at http://www.bobpowell.net/faqmain.htm the very first question deals with the issue I was having, if only I had searched earlier :). In the first question Bob discusses why the PictureBox isn’t a fit solution and goes on to suggest alternatives. I chose to store my graphic in a panel since I want a container for it. Another advantage over the PictureBox is that panels are scrollable by default, meaning I don’t have to do any extra work to make it scroll like I would with a PictureBox.
The code for the above application is very simple; I’ll paste the main part of it below.
private void panel1_Paint(object sender, PaintEventArgs e) { Graphics g = e.Graphics;
g.FillRectangle(Brushes.White, 0, 0, panel1.Width, panel1.Height);
Pen blackPen = new Pen(Color.Black); g.DrawEllipse(blackPen, 35, 5, 200, 200);
SolidBrush textBrush = new SolidBrush(Color.Black); g.DrawString("Neil Bamber", new Font("Verdana", 20), textBrush, 50, 85);
textBrush.Dispose(); blackPen.Dispose(); g.Dispose(); }
The panel1_Paint() method is called whenever the panel needs to be redrawn, so if a user minimises and maximises the application or moves a window over the application and then moves it away, the panel needs to be redrawn. This is why drawing on top of the picture box with a “stolen” graphics object does not work. The next line creates a Graphics object for us to use. The Graphics class contains all sorts of methods for drawing most things you can think of, In this example I’m drawing rectangles, circles and text (though drawing text isn’t new to my application, I’ve used the DrawString() function plenty of times in my owner drawn ListBoxes).
The FillRectangle() function fills the panel with a white rectangle that starts in the upper left corner, and is the height and width of the panel. The next line creates a Pen object for the DrawEllipse() method to use. The DrawEllipse() method draws a circle using the created Pen, at 35 pixels across from the left of the application and 5 pixels down from the top, with a width and height of 200. The next line creates a SolidBrush object for use in the DrawString() method. The difference between a SolidBrush and a Pen object is that Pens are used to draw lines and curves where as a SolidBrush is used to fill graphics such as the circle drawn by the Pen. The DrawString() method draws the text (in my case Neil Bamber, in the Verdana) font on the Panel. It doesn’t get much more Hello World than this :).
The next 3 lines dispose of the objects created during the method. It’s always proper practice to dispose of the objects you’ve created when you won’t need them anymore. Disposing of an object frees the resources it uses up so another object can use them. Freeing the resources used by objects that are no longer needed improves application performance because your application won’t be using as much memory. Of course the C# Garbage Collector will eventually free them, but managing your own memory where you can is better than not.
I think this post shows how little I know about GDI+ and how much work I’ll have to do get the control finished in time. Today I’ll be away from the computer although that may be a good thing because it will give me time to think about the best way to create the control, and the formula for ranking friends. 7/15/2006 Found.
Linked above is the promised screen shot of my search form in action. As you can see searching for my friend Arron (I don’t know why his parents spelled his name wrong either) returns his friend entry, a friend note, two events, and three event notes. I coded the rest of the functionality today, after last night’s blog post I thought I’d take a shower to wake me up so I could soldier on, but not after I just laid down for a minute. Oops I fell asleep; at least my dry jeans got an extra 8 hours of wear.
There are still a few niggling bugs with the search form though I wanted it finished a few days ago so they will remain unless I have time at the end of the competition to clean them up. I’m hoping to have a few days to add polish to my application, at the moment it’s a little rough in places, though I think that’s to be expected in all the competition applications given the timeframe and feature sets that are being delivered.
I’m going to take a bit of a break for the rest of today, read a little (Currently reading Musashi by Eiji Yoshikawa, it’s not a tech book so I’ve not added it to my reading list on the side) and play 360 a little, I’ve had a busy week. I’ll begin work on the much talked about FriendMap control tonight and post screenshots and thoughts of and on my progress tomorrow. 7/14/2006 Searching.
Above is a picture of the search form in action. At the moment the search only looks at friends and only at dates so it’s not too useful. I’ll write the rest of the form in what’s left of tonight and tomorrow morning; I just wanted to get an entry up while I’m still able to write coherently. Ignore the relevancy score it’s hard coded for the moment :)
Over the last few days I’ve been thinking about how to fetch the search data from the database, in the majority of searches I’ve written previously I knew what data the user wanted and consequently where in the database it was likely to be, or allowed them to select a field from the database they wanted to search and then enter their terms. Searching allows a user choose what they want to search, limit the results to a particular date range and (or) enter a string to limit the results further. This is a little different than writing select * from table where $fieldName like ‘%$search%’ like I’m used to.
So over the past few days I’ve been thinking about the best way to perform the search. Do I restrict the text box, as well as two DateTimePickers, to a certain field? This isn’t an optimum solution because a user may not be able to find what they want, how do I know if a user wants to search by First Known or Birthday. Do I write a multitude of queries to query all possible fields something could be in? That could work because it would return the appropriate results, but it would be time consuming (not to mention boring) to write and fairly inefficient. In the end I decided on writing three queries that limit results based on the birthday, first known, and event date fields and then further checking the results against the search criteria. I’ll explain further.
After a user clicks the search button, there are checks to see what they are searching for, in the screenshots case, friends. The application selects all records that match the date criteria for both birthday and first known. The results are put into a DataTable and then duplicates removed. The DataTable is then processed and any records that match the criteria are added to an ArrayList of Result objects. The Result ArrayList is then drawn in the ListBox and the user sees (hopefully) what they wanted to see.
I’ll post another screen shot of the search tomorrow showing different result types and hopefully different relevancy scores. I'll also go back through this entry and fix any mistakes I've made due to falling asleep :) 7/12/2006 Misc.Unfortunately no major code additions today, the search form is still where it was yesterday, and with another event on the calendar for tomorrow night It’ll be Friday before I can work on it properly again. Over the next two days I’ll talk about a few topics regarding Visual C# 2005 Express Edition and SQL Server 2005 Express Edition from a usage point of view. Today I’ll mention problems I’ve come across recently and tomorrow I’ll move on to features that I really like and I think could be improved.
One issue I have with SQL Server 2005 was made apparent when I was changing the query that fills the friend list DataGridView on the main form. When I was first fleshing out the application I just put a query in that would display friends, their rating, and the last seen date. I didn’t limit the results to the most recent last seen date because I just wanted to get something running. I recently fixed this so it did in fact limit the results to the most recent, last seen date. Below is the query.
select people.person_id, people.name, people.rating, max(events.date) as date from events, owner_people, people, event_attendees where event_attendees.event_id = events.event_id and owner_people.person_id = event_attendees.person_id and owner_people.person_id = people.person_id and owner_people.owner_id = @mapOwnerID group by people.person_id, people.name, people.rating
At first though this didn’t work, when I ran the query I was getting the error that I couldn’t group by people.name (and therefore not select it) because it was a text, ntext, or image field. Not being able to group by a text field seemed pretty strange, but I figured I’d find a way around it and I did. I changed the people.name field type to varchar(max) since it wasn’t listed in the error list and sounded like it allowed the user to enter a lot of characters (I don’t really like limiting user input, some one may have a really long name :)). Once I did that it worked, but I was intrigued by just how big varchar(max) is. After googling I found that varchar(max) has the same 2gb limit as the text type, if it’s pretty much the same data type with the same size limitations and content, why can’t I group by text as well as varchar(max)? I might be missing something and if I am I’d love for some one to leave a comment informing me. :)
The second and final part of this post relates to Visual C# 2005 and is, unfortunately, a little vaguer than the first part. I’d guess that this is related to the copying and pasting of ToolStrip controls since that’s when it seems to happen. I’ve been rushing to get forms completed and a lot of the ToolStrips in my application are of the same format (either Save/New or Delete buttons) and I’ve taken to copying and pasting the controls into group boxes. The ToolStrips copy and paste fine, and work as they should, however at some point the Visible property gets to False for some reason. If I figure out the exact steps to duplicate the issue I’ll post them, but that’s the best I’ve got at the moment. It’s not too major, just a minor annoyance.
I’ll take a minor annoyance for a nearly fully featured IDE though. :)
7/11/2006 Low Hanging Fruit.Today I spent a lot of time cleaning up and finishing the remaining forms. On the events form I added the functionality for adding and removing event attendees (up until now I’d just been entering them straight into the database, naughty). On the options form I added the ability to add and remove interests. One concept I’m not sure I’ll have time to implement is linking event types to interests, the benefit of doing this would allow for a more accurate event ranking between owners and friends. For example if Bob is interested in DJing and Rob is not, obviously an event that involves the DJing interest would mean more to Bob than Rob.
On the manage friends form I added the functionality to add and remove interests as well the functionality to add and remove links between people. When a person is linked they will be drawn on the map connected to that friend, rather than connected to you. This should allow for a neater, less complicated map. Say for example you are friends with Bob; he would be connected to you. You’ve seen Bob at a few events with his girlfriend Robina, you add her to the map and then link Bob to her. When the map control draws itself you would be connected to Robina through Bob.
No screenshots today because the work I’ve done is all very similar to the screenshots I’ve already posted. One issue I decided on today was the continued use of owner drawn ListBoxes. In some sections of the form (for example the friend and owner interests tab) it would have made more sense to use a DataGridView. The main benefit of using a DataGridView controls would be sorting. That is, a user could click the interest column and sort alphabetically, or click the rating column and sort numerically. The disadvantage of using a DataGridView is that it would look out of place since most other forms would be using owner drawn ListBoxes. I felt the consistency was worth the lack of sorting functionality since usually the boxes only contain three or four entries. If there were no deadlines I’d add the sorting functionality to all owner drawn ListBoxes and there would be no disadvantage anywhere. Unfortunately there is a deadline.
Speaking of sorting I still haven’t figured out an appropriate and time effective way to search and sort the resulting items (which is why I completed the forms today). Assigning a percentage relevancy score may have been a little over my head for the timeframe. I think I’ll be settling for a description rather than a percentage relevancy, for example Very Relevant, Relevant, Less Relevant and Possibly Not Relevant. These ratings will be initially determined by looking at where search term was found, so the search term in the event title is a lot more relevant than the search term in an event note. Then the results will be further separated by counting the occurrence of the search term within the result, so if the term occurs more often then it is more relevant. Even this may be too hard to implement in the given timeframe, but I’ll try giving it a shot and see how far I get. 7/10/2006 Search Form.
Linked above is the search form as seen in the Visual C# form designer. I’m not too happy with the design of the form; it’s functional though I feel something isn’t quite right with it. If any one can see anything that should be added to it, feel free to comment. The form is quite simple to comprehend at a glance, the DateTimePickers will allow the user to limit the search results before/after/between the selected dates and the ListBox below will display the search results.
Search results will be in the form of Friend/Event (%relevancy) – Name or something very similar. I’m trying to decide at the moment how to implement the search code, the easiest yet least cost effective way (performance wise) would be to query the two tables separately and then sort those results by relevancy. I’ll think about it over the next day and see if I can think of a better way to do it that would take a similar amount of time. I’d like to have the search form finished by tomorrow.
At the moment there is very little code there since I had to spend a while fixing a problem with my contacts display control. I had added all the code, but it wasn’t displaying anything. The query was returning rows but I couldn’t figure why no items were being added to the ListBox. I spent a good 30 minutes looking through the control code trying to figure out what was wrong. Then I realised I had forgot to assign the functions to events. I’m still kicking my self for that one.
In other news I added controls for Links and Interests tabs on the Manage Friends form. Depending on how quickly the search form is finished I may get those complete tomorrow as well. Two more days until my deadline for getting all the forms finished, I’m not sure if I can make it but I’ll be working hard over the next two nights to get there.
Perhaps this competition should have provided us with Microsoft Project so we can manage time more effectively. In side projects such as this I’ve never had hard and fast deadlines to work to. It’s helped a lot to motivate me and it’s taught me that you probably should have goals and deadlines that you work towards in your own projects, just so you do actually work on them. 7/8/2006 NotesControl Custom Control.The work I accomplished today was an extension of my Owner Drawn ListBox from yesterday. I needed to duplicate the functionality of the notes ListBox for the events form and (gasp) I thought about just copying and pasting the code. I knew that was entirely the wrong thing to do but I didn’t want to create a custom control and spend all night figuring out why it wasn’t working.
In the end though I opted for the correct way of coding the ListBox and put it in a control. Aside from a few simple changes to the code (so it would support multiple tables) I think I spent more time considering whether or not to implement the ListBox as a custom control than I spent actually implementing it, so I’m glad I did take the high road.
To create a custom ListBox control, navigate to the solution explorer tab and right click your project name and choose User Control. Enter a name for the control, I entered notesControl, and you’ll be shown a grey window. Drag a ListBox on to the form and set its properties similar to yesterdays ListBox. Once that is complete change the form to inherit from System.Windows.Forms.ListBox and add the necessary properties and code and Rob’s your father’s brother, you have your own custom control.
To use the control drop it on to a form from the Components section of the Toolbox and change your code to call the appropriate methods when the notesControl needs populating or items deleting from it. I replaced about 200 lines of code with 10 on my Manage Friends form, making the code a lot more readable.
The main issue I had was changing the code so it would support the friends and events notes tables, which have different field names (I’m not sure what I was thinking…). On the plus side though it means I have a very reusable ListBox for displaying notes that contain a date, title and an actual note. To achieve this I just gave the custom control properties such as TableName, NoteIDFieldName and then changed the query string to “select ” + NoteIDFieldName + “ from “ + TableName;.
The only real problem I had when creating the custom control was Visual Studio giving me an error about the control not having a constructor. The form did have a constructor but it was in the form of notesControl(string tableName, string etc, etc…). I tried just created a blank constructor and then it allowed me to place it on the form.
So all in all creating the control was quite an easy task and I’m happy I created it rather than copying and pasting code. I’ll create two more custom ListBox controls to display the address and contact information for a friend. I could put those directly on the form as I originally did with the notesControl, since they won’t be used twice, but I may need to use them in another project so it’s better to do it the correct way. |
|
|