Sample: SearchQuery (Windows Forms)
Binding Oriented Programming (BOP) is something that I’ve been championing to a number of Readify colleagues. In my original post, I gave an example of how the BOP approach could be applied in a Windows Presentation Foundation application. Then in a post about the SecurityManager, I showed an example that used Windows Forms and followed it up with another one using ASP.NET. Tonight I’d like to show another example using Windows Forms.
This came from looking at an application that Omar had built. He showed me a fancy search form, which allowed you to type in the first and last name for someone and it would bring back some results asynchronously using a BackgroundWorker.
Shaking my head slowly, I remarked: “That’s not Binding Oriented”.
“But there’s no object to bind to!”, he answered.
“Why not?” was my reply. Let’s approach this same form from a Binding Oriented Programmer’s perspective.
The Goal
We’re going to build a window that looks like this:
Here are some requirements to guide us:
- Filling in the first and last name and clicking “Search” should bring back a list of people with those names.
- Clicking “Cancel” while the search is in progress should stop the search.
- Typing in either
TextBoxwhilst a search is in progress should cancel the search. - The search should be conducted asynchronously.
- A progress bar should be visible whilst a search is in progress.
We are going to create 10 of these forms, each of which return different results and take different parameters.
Before you read on, have a think about the amount of code that would required in your code-behind for the Form: You would need to subscribe to the TextChanged events to cancel the search; you’d need to handle both button clicks; you’d need to write all of the code around the BackgroundWorker component to create it, fetch the data and load it; and you’d need to write code to show and hide the progress bar. And all of that code would be intermixed with having to handle other UI-centric things.
The Binding Oriented Approach
I would begin by defining an object to represent the search query. Let’s create a base class that we can use over and over again, called SearchQuery<T>:
public abstract class SearchQuery<T> : INotifyPropertyChanged {
private BindingList<T> _searchResults;
private BackgroundWorker _backgroundWorker;
private bool _isSearching;
public SearchQuery() {
_searchResults = new BindingList<T>();
}
public event PropertyChangedEventHandler PropertyChanged;
public bool IsSearching {
get { return _isSearching; }
set {
_isSearching = value;
this.OnPropertyChanged(new PropertyChangedEventArgs(”IsSearching”));
}
}
public BindingList<T> SearchResults {
get { return _searchResults; }
}
protected bool CancellationPending {
get {
if (_backgroundWorker == null) {
return false;
} else {
return _backgroundWorker.CancellationPending;
}
}
}
protected abstract IEnumerable<T> SearchOnBackgroundThread();
public void Execute() {
if (_backgroundWorker != null && _backgroundWorker.IsBusy) {
Cancel();
}
_backgroundWorker = new BackgroundWorker();
_backgroundWorker.WorkerSupportsCancellation = true;
_backgroundWorker.DoWork += BackgroundWorker_DoWork;
_backgroundWorker.RunWorkerCompleted += BackgroundWorker_RunWorkerCompleted;
_backgroundWorker.RunWorkerAsync();
this.IsSearching = true;
}
public void Cancel() {
if (_backgroundWorker != null && _backgroundWorker.IsBusy) {
_backgroundWorker.CancelAsync();
}
}
private void BackgroundWorker_DoWork(object sender, DoWorkEventArgs e) {
IEnumerable<T> results = SearchOnBackgroundThread();
if (!_backgroundWorker.CancellationPending) {
e.Result = results;
}
}
private void BackgroundWorker_RunWorkerCompleted(object sender,
RunWorkerCompletedEventArgs e) {
if (!e.Cancelled) {
this.IsSearching = false;
if (e.Result != null && e.Result is IEnumerable) {
_searchResults.Clear();
foreach (T item in (IEnumerable)e.Result) {
_searchResults.Add(item);
}
}
}
}
protected virtual void OnPropertyChanged(PropertyChangedEventArgs e) {
if (this.PropertyChanged != null) {
this.PropertyChanged(this, e);
}
}
}
Now I’ll just create a simple derived class to handle my Customer search:
internal sealed class CustomerSearchQuery : SearchQuery<Customer> {
private string _firstName;
private string _lastName;
public CustomerSearchQuery() {
}
public string FirstName {
get { return _firstName; }
set {
_firstName = value;
this.OnPropertyChanged(new PropertyChangedEventArgs(”FirstName”));
Cancel();
}
}
public string LastName {
get { return _lastName; }
set {
_lastName = value;
this.OnPropertyChanged(new PropertyChangedEventArgs(”LastName”));
Cancel();
}
}
protected override IEnumerable<Customer> SearchOnBackgroundThread() {
List<Customer> results = new List<Customer>();
for (int i = 0; i < 100; i++) {
// Create some test data
if (base.CancellationPending) {
break;
}
Customer p = new Customer();
p.FirstName = _firstName + ” ” + i.ToString();
p.LastName = _lastName + ” ” + i.ToString();
results.Add(p);
Thread.Sleep(10);
}
return results;
}
}
Now all I have to do is bind up my user interface:
- Add a
BindingSourceto the screen, and bind it up to aCustomerSearchQueryobject. - Bind the
Textproperties of bothTextBoxesto theFirstNameandLastNameproperties on theCustomerSearchQueryBindingSource. - Set the
UpdateSourceModeof the two bindings above to beOnPropertyChangedinstead ofOnValidating. - Add a
ProgressBarcontrol, and bind theVisibleproperty to theIsSearchingproperty of theCustomerSearchQueryBindingSource. - Bind the
DataSourceof theDataGridViewwhich will contain the results to theCustomerSearchQueryBindingSource, and bind theDataMemberproperty to theSearchResultsproperty (this is the step many people get wrong). - Add two event handlers to the Search and Cancel buttons, to trigger the search.
All told, our code-behind looks like this:
public partial class Form1 : Form {
public Form1() {
InitializeComponent();
}
private void Form_Loaded(object sender, EventArgs e) {
_customerSearchQueryBindingSource.DataSource = new CustomerSearchQuery();
}
private void SearchButton_Clicked(object sender, EventArgs e) {
((CustomerSearchQuery)_customerSearchQueryBindingSource.DataSource).Execute();
}
private void CancelButton_Clicked(object sender, EventArgs e) {
((CustomerSearchQuery)_customerSearchQueryBindingSource.DataSource).Cancel();
}
}
And there you have it: one search form, one simple encapsulated object to represent the search, and one base class to make all of the hard work generic.
The Summary
Why do I prefer this approach?
- The
CustomerSearchQueryandSearchQuery<T>objects are completely testable via unit tests. - The code is separated. The logic about how to search for stuff on a background thread is encapsulated in one class, the logic about how to fetch (or in our case, create)
Customersand to represent the fields of the search are in another class, and our UI code is left uncluttered. - The
CustomerSearchQueryobject is reusable, though you may never reuse it. More importantly, theSearchQuery<T>object is reusable, and we certainly plan to reuse it. Wasn’t reusability one of the reasons we learnt .NET in the first place?
More importantly, I think this approach makes the requirements very plainly understood. Let’s look at the requirements again:
1. Filling in the first and last name and clicking “Search” should bring back a list of people with those names.
When you set the values of the FirstName and LastName properties and call Execute(), it brings back those results. The UI is just bound to it.
2. Clicking “Cancel” while the search is in progress should stop the search.
That’s obvious from the one line of code in the CancelButton_Clicked event handler.
3. Typing in either TextBox whilst a search is in progress should cancel the search.
As the text boxes are bound to the FirstName and LastName properties, it’s plainly clear in the property setters that setting either of those two properties will cancel the search. It’s a lot easier to tell than if we were to write some event handlers that handle TextChanged events, get a reference to the current BackgroundWorker, and then call Cancel on it unless IsBusy is false, and then toggle the visibility of the progress bar.
4. The search should be conducted asynchronously.
While this is an important request it’s not something the UI should be concerned about, so it’s not in UI code. Since all searches should be asynchronous, we’ve captured this nicely in the SearchQuery<T> class.
5. A progress bar should be visible whilst a search is in progress.
Notice what this requirement is saying? The requirement doesn’t say “The progress bar should be made visible when a search is begun, hidden when it is cancelled or when there is an error or when someone types, and hidden by default”. It says “Visible whilst a search is in progress“. That sentence implies synchronization - between the visibility of the ProgressBar, and the current state of the search. Our IsSearching property encapsulates the “search is in progress” part, and data binding captures the synchronization. This is much more obvious than a bunch of event handlers and property setters hidden in code-behind.
This example highlights that Binding Oriented Programming is not limited just to plain old business objects; almost any piece of logic that is written in code-behind and that has some form of state management can be represented, and encapsulated, through a bindable object.
So, which do you prefer? If you asked a developer to write something to meet those requirements (remembering we were asked to make this for 10 different forms), would you prefer the Binding Oriented approach or the normal code-behind oriented approach? From a maintenance perspective, which approach would you rather have to look after?
Filed under: Binding

That was a great read
Great stuff, I didn’t realise that the winforms stuff was as powerful as the wpf data binding, we need more winforms dev’s to know about this.
Thanks
Daniel
Data Binding
Excellent article! I’ve been reading your different posts on Binding Oriented Programming and it is definitely making me change the way I think about programming. I also really enjoyed your screencasts on Binding and wondered if you will have any time in the near future to work on some more. I realize that these take quite a bit of time to get done and since you are into Rails I wondered if you had seen PeepCode http://peepcode.com/ I don’t know about others, but I definitely found your content good enough to charge for.
[…] SearchQuery - Windows Forms example […]
[…] Stovell has one of the best examples I’ve seen on how to-do Binding Oriented Programming (BOP). I’ll be honest, I’ve not seen many, in fact I’ve been keeping my eyes open […]
A real eye-opener, thanks! I’ve never programmed this way, because I’m a .NET programmer. But I’m learning WPF so this is a valuable lesson.
[…] SearchQuery example […]
[…] Rocky Lhotka’s books introduced me to the idea of Binding Oriented Programming. He never used the term (if I remember correctly something I read so many years ago), but he made a very eloquent & persuasive case for the practice. This is an idea I’ve taught to several people at work in recent years. That’s worked fairly well, but I suspect it will be even easier if I can point at some useful definitions & examples online. So thank you, Paul Stovell, for giving a name to Binding Oriented Programming. […]
Paul,
What would be a clean way of hooking up the progress bar?
Thank you,
Stephen
Very cool. I saw this demonstrated at Tech.Ed 2008 here in NZ, and the presenter referenced your examples.
Can this work with a database datasource as well?