A recurring requirement in every day programming is determining whether a value exists with a certain range. Since it is exam time (for most students at present), I resolved to write a quick application demonstrating this requirement based around examination marks.
This quick demo is written in WPF, but should work in Silverlight or Windows Phone 7 with no alteration. The Range class though, can be used throughout .NET in general.
To start with, create a new WPF application in visual Studio and call it ExamApp. Add a new folder to the project called Range and in this declare a new interface called IRange with the following members
using System;
namespace ExamApp.Range
{
public interface IRange<T> where T : IComparable<T>
{
T Start { get; }
T End { get; }
bool InRange(T valueToFind);
}
}
Create a new class in the same folder called Range which implements the interface above
using System;
namespace ExamApp.Range
{
public class Range<T> : IRange<T> where T : IComparable<T>
{
private readonly T start;
private readonly T end;
public Range(T start, T end)
{
if (start.CompareTo(end) <= 0)
{
this.start = start;
this.end = end;
}
else
{
this.start = end;
this.end = start;
}
}
public T Start
{
get { return this.start; }
}
public T End
{
get { return this.end; }
}
public bool InRange(T valueToFind)
{
return valueToFind.CompareTo(Start) >= 0 && valueToFind.CompareTo(End) <= 0;
}
}
}
Add a new Folder to the project called Examinations and in this add a new class called Percentage. This Percentage class inherits off Range, and here you can create whatever logical range class you may desire for your own applications
using System;
using ExamApp.Range;
namespace ExamApp.Examinations
{
public class Percentage<T> : Range<T> where T : IComparable<T>
{
public Percentage(T start, T end) : base(start, end)
{
}
}
}
Add a new enumeration called Grade thus
namespace ExamApp.Examinations
{
public enum Grade
{
None = 0,
A = 1,
B = 2,
C = 3,
D = 4,
E = 5,
} ;
}
Add a new interface called ITest with the following members.
namespace ExamApp.Examinations
{
interface ITest
{
int ArtAndDesignMark { get; set; }
int ScienceMark { get; set; }
int MathsMark { get; set; }
}
}
Add a new folder called Converters to the project, and add the following
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Windows.Data;
using System.Windows.Markup;
using ExamApp.Examinations;
namespace ExamApp.Converters
{
public class MarkToGradeConverter : MarkupExtension, IValueConverter
{
private static MarkToGradeConverter instance;
private static readonly Dictionary<Percentage<int>, Grade> Marks;
static MarkToGradeConverter()
{
Marks = new Dictionary<Percentage<int>, Grade>
{
{new Percentage<int>(80, 100), Grade.A},
{new Percentage<int>(75, 79), Grade.B},
{new Percentage<int>(60, 74), Grade.C},
{new Percentage<int>(55, 59), Grade.D},
{new Percentage<int>(0, 54), Grade.E},
};
}
public override object ProvideValue(IServiceProvider serviceProvider)
{
return instance ?? (instance = new MarkToGradeConverter());
}
#region Implementation of IValueConverter
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
return GetGrade((int)value).ToString();
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
public static Grade GetGrade(int mark)
{
Percentage<int> key = Marks.Keys.FirstOrDefault(r => r.InRange(mark));
if (key != null)
{
Grade grade;
if (Marks.TryGetValue(key, out grade))
{
return grade;
}
}
return Grade.None;
}
#endregion
}
}
As you can see most of the logic is executed here. Add a new class to the project called Student with the following properties. Also note that this implements the ITest interface that was declared earlier
using ExamApp.Examinations;
namespace ExamApp
{
public class Student : ITest
{
public Student(string firstName, string surname, int artAndDesignMark, int scienceMark, int mathsMark)
{
this.FirstName = firstName;
this.Surname = surname;
this.ArtAndDesignMark = artAndDesignMark;
this.ScienceMark = scienceMark;
this.MathsMark = mathsMark;
}
public Student()
{
}
public string FirstName { get; set; }
public string Surname { get; set; }
#region Implementation of ITest
public int ArtAndDesignMark { get; set; }
public int ScienceMark { get; set; }
public int MathsMark { get; set; }
#endregion
}
}
We need a collection of students to show in a list so create the following class that inherits off ObservableCollection<T>
using System.Collections.ObjectModel;
namespace ExamApp
{
public class Students : ObservableCollection<Student>
{
public Students()
{
Add(new Student
{
FirstName = "John",
Surname = "Lennon",
ArtAndDesignMark = 81,
ScienceMark = 59,
MathsMark = 77
});
Add(new Student
{
FirstName = "Paul",
Surname = "McCartney",
ArtAndDesignMark = 88,
ScienceMark = 40,
MathsMark = 66
});
Add(new Student
{
FirstName = "Ringo",
Surname = "Starr",
ArtAndDesignMark = 88,
ScienceMark = 31,
MathsMark = 96
});
Add(new Student
{
FirstName = "George",
Surname = "Harrison",
ArtAndDesignMark = 100,
ScienceMark = 99,
MathsMark = 99
});
}
}
}
Now the data structures are complete, add the following .xaml markup
<Window x:Class="ExamApp.MainWindow"
xmlns:Converters="clr-namespace:ExamApp.Converters"
Title="MainWindow"
Width="525"
Height="350">
<Window.Resources>
<Converters:MarkToGradeConverter x:Key="MarkToGradeConverter" />
</Window.Resources>
<ListView x:Name="studentsListBox">
<ListView.View>
<GridView>
<GridViewColumn Width="120"
DisplayMemberBinding="{Binding Path=FirstName}"
Header="Name" />
<GridViewColumn Width="120"
DisplayMemberBinding="{Binding Path=Surname}"
Header="Surname" />
<GridViewColumn Width="40"
DisplayMemberBinding="{Binding Path=ArtAndDesignMark,
Converter={StaticResource MarkToGradeConverter}}"
Header="Art" />
<GridViewColumn Width="60"
DisplayMemberBinding="{Binding Path=ScienceMark,
Converter={StaticResource MarkToGradeConverter}}"
Header="Science" />
<GridViewColumn Width="50"
DisplayMemberBinding="{Binding Path=MathsMark,
Converter={StaticResource MarkToGradeConverter}}"
Header="Maths" />
</GridView>
</ListView.View>
</ListView>
</Window>
Add the following code to the constructor of the main window
using System.Windows;
namespace ExamApp
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
this.studentsListBox.ItemsSource = new Students();
}
}
}
You should have the following

As you can see it is quite a simple and pretty reusable way to use ranges in your application.
The source code for this simple example is available here