I have a system which manages Vehicles and Staff, when you click on their name based on a date you should be able to see the times that they are available on that day.
Your best bet is to create a custom control inheriting from a similar control, for your example something along the lines of a picture-box may be beneficial. For a (slightly outdated C++) walkthough of custom controls see: http://msdn.microsoft.com/en-us/library/ms364048(v=vs.80).aspx
As far as custom-drawing setup goes: http://msdn.microsoft.com/en-us/library/windows/desktop/bb761817(v=vs.85).aspx
As a generalization, the idea is as follows: Capture the WM_PAINT event, and in that event render a pre-drawn image to the control (this is most often done by creating a paint surface, then copying that into the render-able pain-area of the control) this method avoids any 'flicker'.
The drawing commands are mostly simple, 'drawline(xy_start, xy_end).
Finally, for handling the time of day, if you take the (rendersurface.height / (24*60)) you will have a converstion from time to pixels. eg:
double convert_Size = (rendersurface.height / (24*60)); //height / Hours_in_day * Minites
int time = (hour * 60) + minite_past_hour;
Pixels_from_top = time * convert_Size;
Pixels_from_top is now the pixel-y coordinate of that time during the day.
Evaluate the time you will spend to develop your control, multiply this by your cost/hour, add some bug you will (for sure) produce, and compare this to some existant, well tested solutions:
http://www.telerik.com/products/winforms/scheduler.aspx
http://www.devexpress.com/Products/NET/Controls/WinForms/Scheduler/
I suggest you to buy your control (or some).
Posting this answer because the OP requested it:
This is how you do that in WPF:
<Window x:Class="MiscSamples.TimeBookings"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:MiscSamples"
Title="TimeBookings" Height="300" Width="300">
<Window.Resources>
<local:TimeRangeToVerticalMarginConverter x:Key="VerticalMarginConverter"/>
<local:TimeRangeHeightConverter x:Key="HeightConverter"/>
</Window.Resources>
<ScrollViewer>
<Grid>
<ItemsControl ItemsSource="{Binding Available}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Border BorderBrush="Black" BorderThickness="1" Height="60">
<TextBlock Text="{Binding StringFormat='hh tt'}"
HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Border>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
<ItemsControl ItemsSource="{Binding Bookings}">
<ItemsControl.ItemContainerStyle>
<Style TargetType="ContentPresenter">
<Setter Property="Margin" Value="{Binding Converter={StaticResource VerticalMarginConverter}}"/>
<Setter Property="Height" Value="{Binding Converter={StaticResource HeightConverter}}"/>
<Setter Property="VerticalAlignment" Value="Top"/>
</Style>
</ItemsControl.ItemContainerStyle>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Border Background="#601050FF" BorderBrush="LightSkyBlue" BorderThickness="1"
x:Name="Border">
<Viewbox Stretch="Uniform">
<TextBlock Text="Booked" FontWeight="Bold" VerticalAlignment="Center" HorizontalAlignment="Center" FontSize="16">
<TextBlock.LayoutTransform>
<RotateTransform Angle="-45"/>
</TextBlock.LayoutTransform>
</TextBlock>
</Viewbox>
<Border.ToolTip>
<ToolTip>
<StackPanel>
<TextBlock>
<Run Text="From" FontWeight="Bold"/>
<Run Text="{Binding StartString, Mode=OneWay}"/>
</TextBlock>
<TextBlock>
<Run Text="To" FontWeight="Bold"/>
<Run Text="{Binding EndString,Mode=OneWay}"/>
</TextBlock>
</StackPanel>
</ToolTip>
</Border.ToolTip>
</Border>
</DataTemplate>
</ItemsControl.ItemTemplate>
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<Grid/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
</Grid>
</ScrollViewer>
Code Behind:
public partial class TimeBookings : Window
{
public TimeBookings()
{
InitializeComponent();
DataContext = new TimeBookingsViewModel();
}
}
ViewModel:
public class TimeBookingsViewModel
{
public ObservableCollection<DateTime> Available { get; set; }
public ObservableCollection<TimeRange> Bookings { get; set; }
public TimeBookingsViewModel()
{
Available = new ObservableCollection<DateTime>(Enumerable.Range(8, 11).Select(x => new DateTime(2013, 1, 1).AddHours(x)));
Bookings = new ObservableCollection<TimeRange>();
Bookings.Add(new TimeRange(8, 0, 9, 50) {Base = TimeSpan.FromHours(8)});
Bookings.Add(new TimeRange(10, 0, 11, 00) { Base = TimeSpan.FromHours(8) });
Bookings.Add(new TimeRange(12, 00, 13, 30) { Base = TimeSpan.FromHours(8) });
}
}
Data Item:
public class TimeRange
{
public TimeSpan Base { get; set; }
public TimeSpan Start { get; set; }
public TimeSpan End { get; set; }
public string StartString { get { return new DateTime(Start.Ticks).ToString("hh:mm tt"); } }
public string EndString { get { return new DateTime(End.Ticks).ToString("hh:mm tt"); } }
public TimeRange(int starthour, int startminute, int endhour, int endminute)
{
Start = new TimeSpan(0, starthour, startminute, 0);
End = new TimeSpan(0, endhour, endminute, 0);
}
}
And a few helpers (Converters and such):
public class TimeRangeToVerticalMarginConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (!(value is TimeRange))
return null;
var range = (TimeRange) value;
return new Thickness(2, range.Start.TotalMinutes - range.Base.TotalMinutes, 2, 0);
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
public class TimeRangeHeightConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (!(value is TimeRange))
return null;
var range = value as TimeRange;
return range.End.Subtract(range.Start).TotalMinutes;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
ToolTip
. You can really do what you want in WPF.Bottom Line:
Forget winforms, it's too limited, it doesn't have (real) databinding, it requires a lot of code to do less, it does not support any level of customization, and it forces you to create shitty Windows 95 like UIs.
WPF Rocks: Just copy and paste my code in a File -> New Project -> WPF Application
and see the results for yourself.