I'm trying to achieve two-way binding between a DataGridView and a BindingList that provides data for the DGV. Some columns do not yet reflect changes in the underlying list and I think it's because I have not provided property setter(s) to notify of property changes. Rather than code the setter for the Rows property the same way I did for the Process property, I'm trying to get more "elegant" and I realize I am stuck....
I stumbled upon a very interesting writeup for a more elegant approach and I'm trying to implement the concepts of it (please see): http://www.gavaghan.org/blog/2007/07/17/use-inotifypropertychanged-with-bindinglist/
Here is the code from Mike's article I want to use (established as Utilities.cs in my CBMI.Common project):
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
namespace CBMI.Common
{
public static class Utilities
{
public static bool Set<T>(object owner, string propName,
ref T oldValue, T newValue, PropertyChangedEventHandler eventHandler)
{
// make sure the property name really exists
if (owner.GetType().GetProperty(propName) == null)
{
throw new ArgumentException("No property named '" + propName + "' on " + owner.GetType().FullName);
}
if (!Equals(oldValue, newValue)) // we only raise an event if the value has changed
{
oldValue = newValue;
if (eventHandler != null)
{
eventHandler(owner, new PropertyChangedEventArgs(propName));
}
}
return true; // Please NOTE: I had to add this statement to avoid compile error:
// "not all code paths return a value".
}
}
}
So, my FIRST QUESTION about this: The author did not have a return statement in his article and I added it which resolved the compiler error. I'm guessing the eventHandler executes and returns and that this was an author omission and this should return true as the method wants a bool return type. Is that correct assumption?
My 2nd QUESTION shows what a C# rookie I am when I try to use this helper method above. I have coded this class into a separate file called InputFileInfo.cs in the same project (and namespace) as the above:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
namespace CBMI.Common
{
public class InputFileInfo : INotifyPropertyChanged
{
private bool processThisFile;
public bool Process
{
get { return processThisFile; }
set
{
processThisFile = value;
this.NotifyPropertyChanged("Process");
}
}
public string FileName { get; set; }
private long rowsReturned;
public long Rows
{
get { return rowsReturned; }
set
{
Utilities.Set(this, "Rows", ref rowsReturned, value, PropertyChanged);
}
}
public string Message { get; set; }
// constructor
public InputFileInfo(string fName)
{
Process = true;
FileName = fName;
Rows = 0;
Message = String.Empty;
}
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged(string name)
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(name));
}
}
}
The setter for the 2nd property in this class is where I try to use Mike's static method:
Utilities.Set(this, "Rows", ref rowsReturned, value, PropertyChanged);
If I remove Utilities.Set and just code it as follows:
Set(this, "Rows", ref rowsReturned, value, PropertyChanged);
..then I get the compiler complaining that "the name 'Set' does not exist in the current context".
I tried adding a using Utilities; directive but that did not fix the problem.
Finally, I do not understand the parameters: ref T oldValue, T newValue
nor the parameter called value where the Set method is invoked.
Can someone please help me over these multiple confusions about this code so I can use these more advanced ideas?
---- EDIT UPDATE ---- Two good answers helped me get this working. The "2nd question" in the original post above remains a bit elusive. Added comments for each requesting a "best practice" on how to package this so I can use the simple invoking syntax as in Mike's original article. That is, I'm seeking to invoke "helper" static methods by the method name only. I want to understand how to invoke like:
set
{
Set(this, "Rows", ref rowsReturned, value, PropertyChanged);
}
instead of having to code as:
set
{
Utilities.Set(this, "Rows", ref rowsReturned, value, PropertyChanged);
}
I got this working by coding Utilities.Set but I guess the question morphs a bit into - "Where do I put static methods and how to call them so I don't have to "qualify" them with the classname?" I would like to understand how to package generally useful "utility" type methods that don't require an instance of an object. In this case, the static method is called Set but I'd like to be able to add other static methods such as:
public static int HelpfulMethodXXXX(string s, int num)
I have a separately compiled DLL (Vstudio project) containing only class file(s). Ultimately, I'd like to think I could use this class in other applications.
Where is the best place to declare these sort of static methods such that they could be invoked as:
int i = HelpfulMethodXXXX("Sample", testNumber);
instead of:
int i = ContainingClassName.HelpfulMethodXXXX("Sample", testNumber);