Skip to content

Commit

Permalink
Merge pull request #61 from M-Zuber/Development
Browse files Browse the repository at this point in the history
Make Detail Viewers sortable
  • Loading branch information
M-Zuber committed Jan 27, 2015
2 parents 2a7e20b + 65b0bef commit 5e55238
Show file tree
Hide file tree
Showing 6 changed files with 230 additions and 36 deletions.
10 changes: 8 additions & 2 deletions LocalTypes/ExpenseCategory.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
namespace LocalTypes
using System;
namespace LocalTypes
{
public class ExpenseCategory : BaseCategory
public class ExpenseCategory : BaseCategory, IComparable<ExpenseCategory>
{
#region C'Tor

Expand Down Expand Up @@ -35,5 +36,10 @@ public override int GetHashCode()
#endregion

#endregion

public int CompareTo(ExpenseCategory other)
{
return this.Name.CompareTo(other.Name);
}
}
}
10 changes: 8 additions & 2 deletions LocalTypes/IncomeCategory.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
namespace LocalTypes
using System;
namespace LocalTypes
{
public class IncomeCategory : BaseCategory
public class IncomeCategory : BaseCategory, IComparable<IncomeCategory>
{
#region C'Tor

Expand Down Expand Up @@ -35,5 +36,10 @@ public override int GetHashCode()
#endregion

#endregion

public int CompareTo(IncomeCategory other)
{
return this.Name.CompareTo(other.Name);
}
}
}
10 changes: 8 additions & 2 deletions LocalTypes/PaymentMethod.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
namespace LocalTypes
using System;
namespace LocalTypes
{
public class PaymentMethod : BaseCategory
public class PaymentMethod : BaseCategory, IComparable<PaymentMethod>
{
#region C'Tor

Expand Down Expand Up @@ -35,5 +36,10 @@ public override int GetHashCode()
#endregion

#endregion

public int CompareTo(PaymentMethod other)
{
return this.Name.CompareTo(other.Name);
}
}
}
68 changes: 38 additions & 30 deletions UI/DataViewUI.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
using FrameWork;
using LocalTypes;
using System.Globalization;
using System.ComponentModel;

namespace MyHome2013
{
Expand All @@ -15,6 +16,15 @@ namespace MyHome2013
/// </summary>
public partial class DataViewUI : Form
{
static Tuple<string, ListSortDirection>[] baseSorting = new[]
{
Tuple.Create("ID", ListSortDirection.Ascending),
Tuple.Create("Date", ListSortDirection.Ascending)
};

SortableBindingList<Expense> expenseData = new SortableBindingList<Expense>(baseSorting);
SortableBindingList<Income> incomeData = new SortableBindingList<Income>(baseSorting);

#region Properties

/// <summary>
Expand All @@ -38,7 +48,7 @@ public DataViewUI()
{
InitializeComponent();
}

#endregion

#region Control Event Methods
Expand All @@ -52,12 +62,18 @@ private void DataViewUI_Load(object sender, EventArgs e)
{
// Automatically forces the window to be open to its max size
this.WindowState = FormWindowState.Maximized;

// Binds the cache data to the form
this.DataBinding();

this.dgOut.DataSource = expenseData;
this.dgOut.Columns["ID"].Visible = false;
this.dgOut.Columns["Date"].DefaultCellStyle.Format = CultureInfo.CurrentUICulture.DateTimeFormat.ShortDatePattern;

this.dgIn.DataSource = incomeData;
this.dgIn.Columns["ID"].Visible = false;
this.dgIn.Columns["Date"].DefaultCellStyle.Format = CultureInfo.CurrentUICulture.DateTimeFormat.ShortDatePattern;

// Due to only the month being displayed on the control, the day is set to '1',
// so when going from a month with more days to a month with less an exception won't be thrown
// Note: this triggers ValueChanged event
this.dtPick.Value = new DateTime(this.dtPick.Value.Year, this.dtPick.Value.Month, 1);

// Sets up the event for re-entering the form
Expand All @@ -81,16 +97,15 @@ private void dtPick_ValueChanged(object sender, EventArgs e)
/// <param name="e">standard MouseEvent object</param>
private void dgOut_MouseDoubleClick(object sender, MouseEventArgs e)
{
if (this.dgOut.CurrentCell != null)
{
using (ExpenseViewer viewAndEditExpense =
new ExpenseViewer((Expense)this.dgOut.CurrentCell.OwningRow.DataBoundItem))
{
viewAndEditExpense.ShowDialog();
}
var grid = sender as DataGridView;
if (grid.CurrentCell == null) return;

this.DataBinding();
using (var form = new ExpenseViewer(grid.CurrentCell.OwningRow.DataBoundItem as Expense))
{
form.ShowDialog();
}

this.DataBinding();
}

/// <summary>
Expand All @@ -100,18 +115,18 @@ private void dgOut_MouseDoubleClick(object sender, MouseEventArgs e)
/// <param name="e">standard MouseEvent object</param>
private void dgIn_MouseDoubleClick(object sender, MouseEventArgs e)
{
if (this.dgIn.CurrentCell != null)
{
using (IncomeViewer viewAndEditIncome =
new IncomeViewer((Income)this.dgIn.CurrentCell.OwningRow.DataBoundItem))
{
viewAndEditIncome.ShowDialog();
}
var grid = sender as DataGridView;
if (grid.CurrentCell == null) return;

this.DataBinding();
using (var form = new IncomeViewer(grid.CurrentCell.OwningRow.DataBoundItem as Income))
{
form.ShowDialog();
}

this.DataBinding();
}


/// <summary>
/// Refreshes the data in the form every time it gains focus
/// -This is to deal with multiple views into the same month being open
Expand Down Expand Up @@ -175,16 +190,9 @@ private void DataBinding()
private void MonthlyDataBinding()
{
// Updates the data in the expense and income chart views
this.dgOut.DataSource =
ExpenseHandler.LoadOfMonth(dtPick.Value);
this.dgOut.Columns["ID"].Visible = false;
this.dgOut.Columns["Date"].DefaultCellStyle.Format = CultureInfo.CurrentUICulture.DateTimeFormat.ShortDatePattern;

this.dgIn.DataSource =
IncomeHandler.LoadOfMonth(dtPick.Value);
this.dgIn.Columns["ID"].Visible = false;
this.dgIn.Columns["Date"].DefaultCellStyle.Format = CultureInfo.CurrentUICulture.DateTimeFormat.ShortDatePattern;
}
expenseData.Load(ExpenseHandler.LoadOfMonth(dtPick.Value));
incomeData.Load(IncomeHandler.LoadOfMonth(dtPick.Value));
}

#endregion
}
Expand Down
1 change: 1 addition & 0 deletions UI/MyHome2013.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,7 @@
<Compile Include="RecurringIncomeInput.Designer.cs">
<DependentUpon>RecurringIncomeInput.cs</DependentUpon>
</Compile>
<Compile Include="SortableBindingList.cs" />
<Compile Include="ViewCategoriesUI.cs">
<SubType>Form</SubType>
</Compile>
Expand Down
167 changes: 167 additions & 0 deletions UI/SortableBindingList.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,167 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;

namespace MyHome2013
{
class SortableBindingList<T> : BindingList<T>
{
CustomComparer comparer;

protected override bool SupportsSortingCore
{
get { return true; }
}

bool isSorted = false;
protected override bool IsSortedCore
{
get { return isSorted; }
}

PropertyDescriptor propertyDescriptor;
protected override PropertyDescriptor SortPropertyCore
{
get { return propertyDescriptor; }
}

private ListSortDirection listSortDirection;
protected override ListSortDirection SortDirectionCore
{
get { return listSortDirection; }
}



public SortableBindingList() : this(new Tuple<string, ListSortDirection>[0], new List<T>()) { }
public SortableBindingList(IEnumerable<Tuple<string, ListSortDirection>> props) : this(props, new List<T>()) { }
public SortableBindingList(IEnumerable<Tuple<string, ListSortDirection>> props, List<T> list)
: base(list)
{
// Build Comparer chain
var t = TypeDescriptor.GetProperties(typeof(T));

foreach (var prop in props)
{
var p = t.Find(prop.Item1, false);
if (p == null)
throw new ArgumentException("The property \"" + prop.Item1 + "\" was not found on " + typeof(T).FullName + ".", "prop");

isSorted = true;
this.propertyDescriptor = p;
this.listSortDirection = prop.Item2;
this.comparer = new CustomComparer(this.comparer, p, prop.Item2);
}

// Wrap in final Comparer for user sorting
this.comparer = new CustomComparer(this.comparer);

var items = this.Items as List<T>;
items.Sort(this.comparer);
}

public void Load(IEnumerable<T> collection)
{
var data = this.Items as List<T>;
data.Clear();
data.AddRange(collection);
data.Sort(this.comparer);
this.OnListChanged(new ListChangedEventArgs(ListChangedType.Reset, -1));
}

protected override void ApplySortCore(PropertyDescriptor prop, ListSortDirection direction)
{
var items = this.Items as List<T>;

this.comparer.SetSort(prop, direction);
items.Sort(this.comparer);

this.propertyDescriptor = prop;
this.listSortDirection = direction;
this.isSorted = true;
this.OnListChanged(new ListChangedEventArgs(ListChangedType.Reset, -1));
}

protected override int FindCore(PropertyDescriptor prop, object key)
{
for (int i = 0, count = this.Count; i < count; i++)
{
if (prop.GetValue(this[i]).Equals(key))
{
return i;
}
}
return -1;
}



private class CustomComparer : IComparer<T>
{
static readonly Dictionary<PropertyDescriptor, IComparer> comparerCache = new Dictionary<PropertyDescriptor, IComparer>();

readonly CustomComparer baseComparer;
IComparer comparer;
public ListSortDirection Direction { get; set; }
public PropertyDescriptor Property { get; private set; }

public CustomComparer(PropertyDescriptor prop, ListSortDirection direction) : this(null, prop, direction) { }
public CustomComparer(CustomComparer baseComparer) : this(baseComparer, null, ListSortDirection.Ascending) { }
public CustomComparer(CustomComparer baseComparer, PropertyDescriptor prop, ListSortDirection direction)
{
this.baseComparer = baseComparer;
this.Direction = direction;
this.Property = prop;
this.comparer = GetComparer(prop);
}

public void SetSort(PropertyDescriptor prop, ListSortDirection direction)
{
this.Direction = direction;

if (baseComparer != null && prop == baseComparer.Property)
{
baseComparer.Direction = direction;
prop = null;
}

Property = prop;
comparer = GetComparer(prop);
}

public int Compare(T x, T y)
{
if (comparer != null)
{
var result = comparer.Compare(Property.GetValue(x), Property.GetValue(y));
if (Direction == ListSortDirection.Descending)
result = -result;

if (result != 0)
return result;
}

if (baseComparer != null)
return baseComparer.Compare(x, y);

return 0;
}

IComparer GetComparer(PropertyDescriptor prop)
{
if (prop == null) return null;
if (comparerCache.ContainsKey(prop)) return comparerCache[prop];

var propComparer = typeof(Comparer<>).MakeGenericType(prop.PropertyType);
var result = propComparer.InvokeMember("Default", BindingFlags.Static | BindingFlags.GetProperty | BindingFlags.Public, null, null, null) as IComparer;
comparerCache.Add(prop, result);
return result;
}
}
}
}

0 comments on commit 5e55238

Please sign in to comment.