Monday, November 12, 2012

I talked with Jeff and John from AJI Software the other day about developing for the iOS platform. We chatted about learning Xcode and Objective-C, provisioning devices and the app publishing process. We all have a .NET background and made lots of comparisons between the two platforms/ecosystems/fanbois. They even let me throw in a plug for Christian Radio Locator.
Jeff was my first contact with the Kansas City .NET community. It was probably about 10 years ago. He pushed me to talk more (and rescued me from my first talk that bombed) and blog more. One time a group of us took a 16 hour car trip to South Carolina for a code camp and live podcasted the whole thing. Good times.
Listen to the show
Click here to subscribe to more AJI Reports in the future.
Saturday, September 8, 2012

For the last three months or so I've been working on an iPhone (and iPad) app in my spare time. It all started when I took the kids to Minneapolis and had a hard time finding radio stations to listen to on the trip. I looked in the App Store for an app that would use my GPS to show me Christian radio stations nearby, but there wasn't one. So I decided to build my own.
Using public information from the FCC and a few other sources, I built a database in Google docs that contains the frequency for all Christian radio stations, where the tower is located and how far the tower can reach. I also included any streaming audio information and other contact information like Facebook or Twitter that I could find.
Google spreadsheets publish in JSON format (yes, really) and Xcode can automatically deserialize JSON into a properly formatted entity. This is one area that Xcode is far superior to C#. In a just a few lines of code, I can have a list of in-memory strongly typed objects from a web-based JSON feed. To accomplish the same thing natively in .NET would be much more work and wouldn't feel nearly as clean when it was said and done.
The snazzy icon shown above was built by my very talented wife. She hasn't yet provided any feedback on the app's user interface, which is why it is so plain and boring.
I used a navigation view controller and EGO pull to refresh table view to construct the main window. Pulling down to refresh initiates a GPS lookup, which queries the database for radio stations in range (yes, you can pass parameters to Google spreadsheets and get a subset back in JSON). Pulling up on the table extends the range of the search and includes stations that may not be close enough to get clear audio. This feature is not that intuitive and the next version contains an update to that functionality.
Tapping a cell will show a detail view that displays additional information about the station. The user can click to view the station on a map, click to listen to an online stream (if available) or click to see the station's Facebook or Twitter pages.
Swiping back and forth on the table changes the information that is displayed on the right hand side of the table cell. It scrolls through the city where the tower is located, how far the phone is from the tower, the range of the tower and in the next version a signal strength indicator. This was pretty easy to implement once I figured out how to assign the gesture recognizer delegate.
Tapping and holding on a cell will jump the user to the map view screen. Which is pretty cool, but very hard for even a power user to discover. To tackle the issue of discoverability, the next version has a series of instructions displayed at the bottom of the screen to show the user the various shortcuts. Once the user has performed the swipes and long holds, the instructions disappear.
I've learned a lot developing this app. Spending over a decade exclusively in .NET made the learning curve a bit steep, but once I learned the structure and syntax of Objective-C, I've learned to appreciate the power and simplicity of it.
Here are a few screenshots. I would really appreciate any feedback and especially iTunes reviews. Technically it is open source and a smart googler could probably find it. I just haven't promoted it as open source.



Cross posted from timhibbard.com
Thursday, April 14, 2011

As I discussed in my last post, we created a TimeSpinner control based on the Extended WPF Toolkit’s ButtonSpinner.
Now, the toolkit has a DateTimeUpDown control that will display a date or time and allow the user to click the spinners for each time part, but I needed a little more. I needed the raw text to be editable and I wanted the spinners to just modify the minutes portion. I also wanted to have special parsing based on the number of characters entered.
4 chars:
Parse as military time.
3 chars:
Parse as modified military time, but only assume waking hours.
So 933 becomes 9:33 AM
345 becomes 3:45 PM
We put the cut-off at 7. Anything before 7 assumes PM anything 7 or after assumes AM.
2 chars:
Assuming shortened military time.
12 = 12:00 PM
15 = 3:00 PM
1 char:
Parses as shortened military time, but assumes waking hours like 3 chars.
1 = 1:00 PM
8 = 8:00 AM
The TimeSpinnerControl exposes one bindable property, Time. So it would be consumed like:
1: <runtime:TimeSpinnerControl Time="{Binding Path=ReturnTime}" 2: x:Name="spinnerReturnTime"/>
So, here is what we did:
TimeSpinnerControl.xaml:
1: <UserControl x:Class="ParaPlan.Controls.TimeSpinnerControl"
2: xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
3: xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
4: xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
5: xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
6: xmlns:wpftoolkit="clr-namespace:Microsoft.Windows.Controls;assembly=WPFToolkit.Extended"
7: mc:Ignorable="d">
8: <wpftoolkit:ButtonSpinner Spin="Time_Spin" IsTabStop="False">
9: <TextBox Name="textTime"
10: MinWidth="60"
11: Margin="0"
12: MouseDoubleClick="textTimeDoubleClick"
13: Keyboard.GotKeyboardFocus="textTimeGotKeyboardFocus"
14: MouseEnter="textTimeMouseEnter"
15: Keyboard.LostKeyboardFocus="textTimeLostKeyboardFocus"/>
16: </wpftoolkit:ButtonSpinner>
17: </UserControl>
TimeSpinnerControl.xaml.cs:
1: using System;
2: using System.Collections.Generic;
3: using System.Linq;
4: using System.Text;
5: using System.Windows;
6: using System.Windows.Controls;
7: using System.Windows.Data;
8: using System.Windows.Documents;
9: using System.Windows.Input;
10: using System.Windows.Media;
11: using System.Windows.Media.Imaging;
12: using System.Windows.Navigation;
13: using System.Windows.Shapes;
14: using ParaPlan.Extensions;
15: using System.Globalization;
16:
17: namespace ParaPlan.Controls
18: { 19: /// <summary>
20: /// Interaction logic for TimeSpinnerControl.xaml
21: /// </summary>
22: public partial class TimeSpinnerControl : UserControl
23: { 24: public TimeSpinnerControl()
25: { 26: InitializeComponent();
27: }
28:
29: #region Time Property
30:
31: /// <summary>
32: /// Time Dependency Property
33: /// </summary>
34: public static readonly DependencyProperty TimeProperty =
35: DependencyProperty.Register("Time", typeof(DateTime), typeof(TimeSpinnerControl), 36: new FrameworkPropertyMetadata(DateTime.MinValue,
37: FrameworkPropertyMetadataOptions.BindsTwoWayByDefault,
38: new PropertyChangedCallback(OnTimeChanged)));
39:
40: /// <summary>
41: /// Gets or sets the Time property.
42: /// </summary>
43: public DateTime Time
44: { 45: get { return (DateTime)GetValue(TimeProperty); } 46: set { SetValue(TimeProperty, value); } 47: }
48:
49: /// <summary>
50: /// Handles changes to the Time property.
51: /// </summary>
52: private static void OnTimeChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
53: { 54: ((TimeSpinnerControl)d).OnTimeChanged(e);
55: }
56:
57: /// <summary>
58: /// Provides derived classes an opportunity to handle changes to the Time property.
59: /// </summary>
60: protected virtual void OnTimeChanged(DependencyPropertyChangedEventArgs e)
61: { 62: DateTime value = (DateTime)e.NewValue;
63: if (value.IsMinValue())
64: { 65: textTime.Text = "";
66: return;
67: }
68: textTime.Text = value.ToShortTimeString();
69: }
70:
71: #endregion
72:
73: #region Event Handlers
74: /// <summary>
75: /// Handles when the user clicks a spinner
76: /// </summary>
77: /// <param name="sender"></param>
78: /// <param name="e"></param>
79: private void Time_Spin(object sender, Microsoft.Windows.Controls.SpinEventArgs e)
80: { 81: if (e.Direction == Microsoft.Windows.Controls.SpinDirection.Increase)
82: { 83: this.Time = this.Time.AddMinutesRoundUp(5);
84: }
85: else
86: { 87: this.Time = this.Time.AddMinutesRoundUp(-5);
88: }
89:
90: }
91:
92: /// <summary>
93: /// Handles when the user double clicks in the textbox
94: /// </summary>
95: /// <param name="sender"></param>
96: /// <param name="e"></param>
97: private void textTimeDoubleClick(object sender, MouseButtonEventArgs e)
98: { 99: this.textTime.SelectAll();
100: }
101:
102: /// <summary>
103: /// Handles when the user tabs in the control
104: /// </summary>
105: /// <param name="sender"></param>
106: /// <param name="e"></param>
107: private void textTimeGotKeyboardFocus(object sender, KeyboardFocusChangedEventArgs e)
108: { 109: this.textTime.SelectAll();
110: }
111:
112: /// <summary>
113: /// Handles when the user enters the control by mouse
114: /// </summary>
115: /// <param name="sender"></param>
116: /// <param name="e"></param>
117: private void textTimeMouseEnter(object sender, MouseEventArgs e)
118: { 119: this.textTime.SelectAll();
120: }
121:
122: /// <summary>
123: /// Handles when the control loses focus. Now we want to parse what
124: /// the user entered
125: /// </summary>
126: /// <param name="sender"></param>
127: /// <param name="e"></param>
128: private void textTimeLostKeyboardFocus(object sender, KeyboardFocusChangedEventArgs e)
129: { 130: this.Time = ParseText(this.textTime.Text);
131: }
132: #endregion
133:
134: private DateTime ParseText(string value)
135: { 136: //empty...move on
137: if (string.IsNullOrWhiteSpace(value))
138: { 139: return DateTime.MinValue;
140: }
141:
142: //parsed as valid date
143: DateTime date = DateTime.MinValue;
144: DateTime.TryParse(value, out date);
145: if (!date.IsMinValue())
146: { 147: return date;
148: }
149:
150: string input = value;
151: int first = int.Parse(value.Substring(0, 1));
152: switch (value.Length)
153: { 154: case 3:
155: input = "0" + value;
156: if (first > 0 && first < 7)
157: { 158: input = (first + 12).ToString() + value.Substring(1, 2);
159: }
160: break;
161: case 2:
162: input = value + "00";
163: break;
164: case 1:
165: input = "0" + value + "00";
166: if (first > 0 && first < 7)
167: { 168: input = (first + 12).ToString() + "00";
169: }
170: break;
171: default:
172: break;
173: }
174: DateTime.TryParseExact(input, "HHmm", null, DateTimeStyles.None, out date);
175: return date;
176: }
177:
178:
179: }
180: }
DateTime Extension Method:
1: /// <summary>
2: /// Adds or subtracts a value to a date time rounding it to
3: /// multiples of the entered value
4: /// </summary>
5: /// <param name="dt">this</param>
6: /// <param name="value">Amount to add or subtract</param>
7: /// <returns>Adjusted DateTime</returns>
8: /// <history>
9: /// [Tim Hibbard] 04/08/2011 Created
10: /// </history>
11: public static DateTime AddMinutesRoundUp(this DateTime dt, int value)
12: { 13: int delta = dt.Minute % value;
14: int subtractDeltaFrom = 0;
15: //since value to add is negative, we want to round down
16: //to nearest delta value
17: if (value < 0)
18: { 19: //but only if delta is more than 0. If delta is 0,
20: //then we are already rounded down
21: if (delta > 0)
22: { 23: subtractDeltaFrom = Math.Abs(value);
24: }
25:
26: }
27: return dt.AddMinutes(subtractDeltaFrom - delta).AddMinutes(value);
28: }
Tuesday, April 12, 2011

Our software will automatically generate pick up and drop off times based on distance of trip, how many other people are on the bus, how long it takes to drop them off, etc. We display these times in our custom TimeSpinner control based on WPF Extended Toolkit’s button spinner.
Since the computer is generating the time, they are often not human-friendly. 6:00 AM is a lot easier to remember than 6:03 AM. So we give the users the option to modify these times. Using the spinners, they can adjust the time 5 minutes up or 5 minutes down. However, 6:08 is still difficult to remember, so what we really need is to be able to round up (or down) to the nearest 5 minutes, then adjust in 5 minute increments after that.
So 6:03 AM to 6:05 AM to 6:10 AM to 6:15 AM and likewise, round down from 6:03 AM to 6:00 AM to 5:55 AM to 5:50 AM.
We used an extension method to accomplish this. Note that it accepts increments other than 5 minutes, that’s just what we use.
1: /// <summary>
2: /// Adds or subtracts a value to a date time rounding it to
3: /// multiples of the entered value
4: /// </summary>
5: /// <param name="dt">this</param>
6: /// <param name="value">Amount to add or subtract</param>
7: /// <returns>Adjusted DateTime</returns>
8: public static DateTime AddMinutesRoundUp(this DateTime dt, int value)
9: {
10: int delta = dt.Minute % value;
11: int subtractDeltaFrom = 0;
12: //if value to add is negative, we want to round down
13: //to nearest delta value
14: if (value < 0)
15: {
16: //but only if delta is more than 0. If delta is 0,
17: //then we are already rounded down
18: if (delta > 0)
19: {
20: subtractDeltaFrom = Math.Abs(value);
21: }
22:
23: }
24: return dt.AddMinutes(subtractDeltaFrom - delta).AddMinutes(value);
25: }
Friday, April 8, 2011

Sometimes it handy to force the user’s attention to a specific screen. We can do this with a dialog, but sometimes the user doesn’t know that window is on top. To draw the user’s eye to the window, I like to place a backdrop between the rest of the application and the dialog window. I use the following code to make that happen.
1: public bool? ShowDialogWithBackdrop(Window win)
2: {
3: //create backgroup
4: Window backgroundWindow = new Window();
5: backgroundWindow.Top = 0;
6: backgroundWindow.Left = 0;
7: backgroundWindow.Height = SystemParameters.WorkArea.Height;
8: backgroundWindow.Width = SystemParameters.WorkArea.Width;
9: backgroundWindow.AllowsTransparency = true;
10: backgroundWindow.Background = Brushes.Transparent;
11: backgroundWindow.WindowStyle = WindowStyle.None;
12: backgroundWindow.ShowInTaskbar = false;
13: Rectangle rect = new Rectangle() { Fill = Brushes.Silver, Opacity = 0.5 };
14: backgroundWindow.Content = rect;
15: backgroundWindow.Show();
16: //set the owner so if the user clicks on the backdrop,
17: //the window will flash
18: win.Owner = backgroundWindow;
19: bool? rv = win.ShowDialog();
20: //dialog has returned. Close backdrop.
21: backgroundWindow.Close();
22: return rv;
23: }
Monday, June 21, 2010
The most common use for Preprocessor Directives is to intelligently group your code using the #region … #endregion tag (sidenote: Ctrl + M, M is a great keyboard shortcut to expand and contract your regions). Preprocessor Directives can also be used to tell the compiler which code should or should not be compiled based on the configuration environment. Wrapping code in an #if DEBUG … #endif block will only execute if the environment is in debug mode.
This proved to be a handy way to debug a situation this morning in a multi-threaded scenario where breakpoints and Console.WriteLine were not giving me enough information. I added a new tab with initial visibility as collapsed, set it to visible in an #if DEBUG … #endif block, and wrote events to it also in a debug block.
For situations where you want code to execute only in a production environment, use #if !DEBUG … #endif.
View MSDN’s page on Preprocessor Directives for more information.
Sunday, June 20, 2010
On Jan 16, 2011, we are expecting a new addition to our family. Ben is going to learn words like “share” and “don’t put that in the baby’s nose”. We expect he’ll do great!

Thursday, June 17, 2010
There is a sales technique where the strategy is to get the customer to say “No deal” as soon as possible. The idea being that by establishing terms that your customer is not comfortable with with, the sooner you can figure out what they will be willing to agree to. The same principal can be applied to code design. Instead of nested if…then statements, a code block should quickly eliminate the cases it is not equipped to handle and just focus on what it is meant to handle.
This is code that will quickly become unmaintainable as requirements change:
private void SaveClient(Client c)
{
if (c != null)
{
if (c.BirthDate != DateTime.MinValue)
{
foreach (Sale s in c.Sales)
{
if (s.IsProcessed)
{
SaveSaleToDatabase(s);
}
}
SaveClientToDatabase(c);
}
}
}
If an additional requirement comes along that requires the Client to have Manager approval or for a Sale to be under $20K, this code will get messy and unreadable.
A better way to meet the same requirements would be:
private void SaveClient(Client c)
{
if (c == null)
{
return;
}
if (c.BirthDate == DateTime.MinValue)
{
return;
}
foreach (Sale s in c.Sales)
{
if (!s.IsProcessed)
{
continue;
}
SaveSaleToDatabase(s);
}
SaveClientToDatabase(c);
}
This technique moves on quickly when it finds something it doesn’t like. This makes it much easier to add a Manager approval constraint. We would just insert the new requirement before the action takes place.
Tuesday, June 8, 2010
A lot of reports work on data from last month. It is a nice touch to have these dates pre-populated for your users. Using extension methods, the code can look cleaner too.
Extension Methods:
public static class DateHelper
{
public static DateTime FirstOfTheMonth(this DateTime dt)
{
return new DateTime(dt.Year, dt.Month, 1);
}
public static DateTime LastOfTheMonth(this DateTime dt)
{
return dt.FirstOfTheMonth().AddMonths(1).AddDays(-1);
}
}
Consuming Code:
void Prepopulate()
{
startDateBox.CurrentlySelectedDate = DateTime.Now.AddMonths(-1).FirstOfTheMonth();
endDateBox.CurrentlySelectedDate = DateTime.Now.AddMonths(-1).LastOfTheMonth();
}
Monday, June 7, 2010
I would like to blog more about the problems I encounter on a daily basis. I find that taking 10 minutes or so to write a simple solution to my problems helps me retain that information.
I always forget the specific syntax to declaring variables in T-SQL.
declare @startdate datetime;
declare @enddate datetime;
set @startdate = '04/01/2010';
set @enddate = '04/30/2010';
select count(id) from triphistory where tripdate between @startdate and @enddate
Saturday, March 20, 2010
We recently added OAuth to MentionNotifier so that users can quickly view and edit their subscriptions without needed an additional login. This is enabled by default for new users, but existing users will need to do the following steps to associate their subscriptions with OAuth:
1) Go to http://software.engraph.com/ManageMentionNotifier
2) Click “Sign in with Twitter”
3) Verify that your twittername and email are correct
4) Click "Associate with OAuth"
This will also allow you to reply to notification emails and MentionNotifier will tweet on your behalf. This is made possible by @sidePop written by @ferventcoder
Note that the reply by email is new and buggy, so make sure that what was tweeted is correct and as expected.
If you run into any issues, sent me a reply to @timhibbard.
You can also join the MentionNotifier fan page on facebook, or follow @MentionNotifier on twitter.
Friday, January 22, 2010
If you want to specify that a virtual server starts up automatically when the host server starts up:
1) On host server, browse to “C:\Users\Public\Documents”
2) Right click “Shared Virtual Machines”, select Properties
3) Browse to security tab, add yourself as having full control over this folder
4) Repeat steps 2-3 for “Shared Virtual Networks”
5) In Virtual Server web interface, shut down the virtual machine you wish to auto-start
6) Navigate to Edit Configuration –> General Properties
7) Check “Run virtual machine under the following user account”
8) Enter the credentials from step 3
9) Select desired startup action and delay, then start virtual machine.
Now when your host machine reboots, your virtual machines will start up automatically. Step 4 is very important as my wasted morning can attest to.
Wednesday, December 30, 2009
EnGraph is looking for an ASP.NET developer to join our team. We are a small company in Lenexa, KS that creates .NET applications for Paratransit agencies.
A good candidate would be very comfortable with ASP.NET, Forms Authentication and JavaScript. A huge bonus would be knowledge of IIS, Google Maps API, AJAXPro, ActiveReports, WPF and SQL.
We are accepting resumes immediately and look to hire as soon as January 18th. We would consider contract or full-time and we would require office attendance.
Please send your resume to timhibbard@engraph.com
Friday, October 2, 2009
Last weekend I ran the Shoreline Shuffle trail 5K. It was my first trail race and also my first first place finish. As a bonus, I also broke 20 minutes, which I didn’t think was possible for me on a trail run. I’ve posted a full race report (with way too many pics) on my running blog.
Wednesday, September 23, 2009
TwitApps was a great tool, it would email you when somebody @mentioned you on twitter. But, alas, they are shutting down and leaving what I think is a huge hole.
So I built my own service that does the exact same thing.
To use the service, visit MentionNotifier, and subscribe to your @mentions. To get notified of updates, follow @MentionNotifier or @timhibbard on twitter.
Here are some of the FAQ’s:
Q: What is this?
A: It is a service to notify you by email when somebody has mentioned you in a tweet.
Q: Who do the emails come from?
A: MentionNotifier@gmail.com
Q: How quickly will I be notified of a new tweet?
A: Currently, it checks every minute.
Q: How does it work?
A: It uses the search API of twitter to check for your twitter username.
Q: Isn't that just a glorified RSS reader?
A: Yes.
Q: Will it work with hashtags?
A: Yes. Put in the search string you want to be notified on (#KUbball) and the email address to send new tweets to.
Q: Will I receive multiple emails if I get multiple mentions?
A: It will group the mentions into a single email each checking cycle.
Q: Will it work if I get a mention from somebody that protects their tweets?
A: No, because protected tweets are not part of the public timeline.
Friday, July 31, 2009
I use Gmail for my personal email, and as an archive for my EnGraph email, but haven’t been able to use it as my main email client as it appends a “On Behalf of” to messages sent from Gmail using a non-gmail address.
Google has recently released an update to Gmail allowing you to use an SMTP server of your choosing, which removes the “On Behalf Of”.
Now I can email my clients from Gmail and they don’t know the difference!
Friday, July 17, 2009
Pre-approval letter in hand, let the house shopping begin!10:10 AM Apr 28th
Apparently it's impossible to look at a house without the realtor begging to be your buyer's agent. Back off people!1:36 PM Apr 30th
Finally going live with software that I've been working on for 2+ years!3:59 PM Apr 30th
First install and we run into a proxy brick wall...smooth4:43 PM Apr 30th
Done with an exhausting day of house hunting. Found a lot that we liked. One that we LOVED, in shawnee of all places.6:40 PM May 2nd
We still aren't sure if we could actually leave lawrence though. So much coolness in this town.6:41 PM May 2nd
Found another very cool house in shawnee. Love this area, didn't even really knew it existed before this weekend.3:01 PM May 3rd
My fav website these days: http://land.jocogov.org/ - amazing how some people are asking 2-3% above appraised value. Crack smokers8:59 AM May 6th
We just had a realtor tell us she wouldn't accept our pre-approval letter from BofA. Umm, seriously?5:47 PM May 6th
Officially submitted an offer on the shawnee house. Many knots in stomach.1:31 PM May 9th
Ugh...their counter offer sucks and they probably aren't going to like our counter offer...preparing ourselves to walk away from this one9:12 PM May 9th
Counter counter offer submitted. This is starting to get fun. Bring it on!12:13 AM May 10th
Still in negotiations, only battling over closing and possession dates now. Everything else is ironed out.4:32 PM May 10th
Our counter offer was rejected over...get this...$172 of rent we asked for because they wanted to live in the home for 4 days past closing7:55 AM May 12th
@ericjgruber That's how we feel. If this was such a big deal, what else would they have been stupid about during the rest of the process8:09 AM May 12th
Couldn't have said it better myself - @chibb's take on our offer being rejected - http://bit.ly/6m1Wt8:12 AM May 12th
http://twitpic.com/51v8d - The camry is rocking the gowagon.com sticker. Thanks guys. Unrelated: Sorry @chibb :)2:49 PM May 12th
Ben and @chibb landed safely in Chicago and Ben was a champ during the flight!10:09 AM May 14th
I don't know if "trained" is the word I'm looking for, but my wife is out of town and I still put the toilet seat down10:12 PM May 14th
Ugh...I've been up all night with the Buffalo Wild Wings Flu. No trail run for me this morning.6:58 AM May 16th
I slept 13 hours and feel a lot better. Still a little light headed and queasy and down about 8 lbs from avg weight. Never eating BWW again.7:27 AM May 17th
Excited that @chibb and Ben come home today. Trying to get the house cleaned up before I go pick them up from the airport8:08 AM May 17th
Choking down oatmeal with no milk. Apparently I have the bug where you feel fine on Sunday, but kicks you in the junk on monday.2:57 PM May 18th
Great bday dinner with @chibb, Ben, @kylejarcher, Allie and Sophs - http://bkite.com/07W4y7:20 PM May 28th
Ben is growing up. Got rid of the infant car seat today and installed the @Britax1:46 PM May 30th
Just placed an offer on a great place in Lenexa8:21 PM May 30th
Our offer was accepted!!10:42 AM May 31st
My favorite part of our new house - Pic: http://bkite.com/084g211:41 AM Jun 1st
Buying a warranty actually paid off for me. Got a new TomTom 930 today cause 910 that I bought 3 years ago has been crapping out.2:31 PM Jun 6th
We hit a few snags today during the inspection and getting insurance. Hopefully all will be resolved quickly.8:37 PM Jun 8th
Heading to a WPF conference in Chicago via Pella, IA and Madison. Ben's first really big road trip. #fb7:12 AM Jun 11th
Round 2 of negotiations (post-inspection) are done!8:14 AM Jun 11th
Getting ready to check in for my classes. Gonna be a great day of WPF learning. - http://bkite.com/08qvX7:58 AM Jun 12th
Awesome trail run tonight with the crew from TrailHawks - they were gentle popping my trail cherry :) - http://bit.ly/6ifZo10:25 PM Jun 17th
Heading to KC with @chibb to P&L to spend a night boozin' celebrating my 30th, father's day, buying a house and getting a babysitter :)2:10 PM Jun 19th
Video of Ben crawling around and standing himself up for the first time - http://bit.ly/t9eiU9:59 PM Jun 21st
@fxdgear we have too much crap!9:40 PM Jun 24th
Closing on Lenexa house in 12 hours! #fb11:19 PM Jun 25th
Homeowners!11:09 AM Jun 26th
Thanks everybody. @chibb and I are thrilled. And also a bit exposed, didn't realize that there wasn't any blinds :)12:23 PM Jun 26th
Everything is off the truck and into the house. Many thanks to my dad for helping and Chels mom for watching Ben #fb10:43 PM Jun 28th
First ever #bike commute. 2.91 miles in 11 minutes and 2 seconds. Pretty easy ride. A few hills, but nothing major.2:01 PM Jun 29th
@mintchaos The place is an absolute disaster of boxes. I couldn't find any clothes so I came work in gym clothes :)3:40 PM Jun 29th
Backed up pipes! Poop in the basement! Yay for home ownership!! - http://bkite.com/097G01:18 PM Jul 1st
We are moved in enough that we can park one car in the garage! - http://bkite.com/09c4i12:08 PM Jul 3rd
Enjoying a beautiful night with @chibb on our new deck. -http://bkite.com/09fMg9:16 PM Jul 4th
I ran a 5:46 mile this morning. My fastest ever since high school -http://bit.ly/16tKNT9:02 AM Jul 10th
I promise to be a better blogger :)
Monday, March 23, 2009
This is a great tool for those circumstances where ordinary sarcasm isn’t quite enough to get the point across.
http://lmgtfy.com
In action: http://tinyurl.com/d2yyxl
Friday, February 27, 2009
Since my Dell D610 is three years old, I decided it was time for a new lappy. I finally decided on a E6400 from Dell.
Finally a machine that can actually run Vista. Here is my score:
So far I love it. I can have VS 2008 plus a couple virtual machines open and it doesn’t even blink.
Technorati Tags:
Dell,
E6400
Friday, February 20, 2009
I asked my first question on stackoverflow today. I want to make sure I’m unsubscribing from PropertyChanged events properly. Please head over and put in your two cents.
Monday, January 5, 2009
In ParaPlan 4.0, we use twitter to maintain a change log. I wanted to display this information to our users, so I wrote a little class that calls the RSS feed and uses LINQ to parse the data. All I need is the message and the date, so that is all it pulls out.
Here is the class:
public class Twitter
{
public string Message { get; set; }
public DateTime PubDate { get; set; }
public static List<Twitter> Parse(string User)
{
var rv = new List<Twitter>();
var url = "http://twitter.com/statuses/user_timeline/" + User + ".rss";
var element = XElement.Load(url);
foreach (var node in element.Element("channel").Elements("item"))
{
var twit = new Twitter();
var message = node.Element("description").Value;
//remove username information
twit.Message = message.Replace(User + ": ", string.Empty);
twit.PubDate = DateTime.Parse(node.Element("pubDate").Value);
rv.Add(twit);
}
return rv;
}
}
Our calling code looks like this:
var changes = new List<string>();
var fromTwitter = Twitter.Parse("ParaPlan");
fromTwitter.ForEach(t =>
changes.Add(t.PubDate.ToString("MM/dd/yy") + " - " + t.Message));
var list = new ListBox();
list.ItemsSource = changes;
Friday, January 2, 2009
On 12-20-2008, my wife Chelsea, gave birth to our beautiful baby boy Benjamin. It’s been a crazy exciting and busy couple of weeks so far. I’ve tried to respond to all the many people that have congratulated us on twitter and facebook, but if I forgot, thank you so much. All of your kind words and well wishes have been very appreciated!!
Many more pictures here.
Technorati Tags:
Benjamin
Tuesday, December 9, 2008
This code example will show how to hide a listbox from the user when it doesn’t have any items.
It involves binding the Visibility of the listbox to the Items.Count of the listbox. We run the Items.Count through a converter that will return a Visibility.Visible object if the Item.Count is not zero.
Here is the converter class:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Data;
using System.Windows;
namespace HideAListBox
{
public class ZeroCollapsedNonZeroVisible : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
var rv = Visibility.Visible;
var val = 0;
int.TryParse(value.ToString(), out val);
if (val == 0)
{
rv = Visibility.Collapsed;
}
return rv;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}
}
Here is the window code:
<Window x:Class="HideAListBox.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:converter="clr-namespace:HideAListBox"
Title="Window1" Height="300" Width="300">
<Window.Resources>
<converter:ZeroCollapsedNonZeroVisible x:Key="hideListBox"/>
</Window.Resources>
<DockPanel LastChildFill="True">
<Button Content="Add Item" Click="addItemClick" DockPanel.Dock="Top"/>
<Button Content="Clear Items" Click="clearItemsClick" DockPanel.Dock="Top"/>
<ListBox Margin="3" BorderBrush="Blue" Name="myListBox"
Visibility="{Binding ElementName=myListBox,
Path=Items.Count,
Converter={StaticResource hideListBox}}"/>
</DockPanel>
</Window>
The entire project can be downloaded here.
Tuesday, November 25, 2008
I try to use keyboard shortcuts as much as possible. Here are some that are handy when unit testing with Visual Studio:
Ctrl + R, A – Run all tests
Ctrl + R, T – Run tests in context (based on if cursor is in function, class, or namespace)
Ctrl + R, F – Runs all tests that are checked in Test Results – very handy because that window is impossible to navigate without a mouse
Ctrl + R, Ctrl + A – Run all tests in debug mode
Ctrl + R, Ctrl + T – Run all tests in context in debug mode
Ctrl + R, Ctrl + F – Run all checked tests in debug mode
Friday, November 21, 2008
The newest version of Google Sync adds a great new feature of syncing contacts. Now your Gmail contacts will stay up to date with your Blackberry contacts and vice versa.
Very nice!
Download page here.