Bill Blogs in C# -- DataBinding

Bill Blogs in C# -- DataBinding

Created: 2/11/2011 12:24:33 PM

Update:  Jonathan Wanagel from the CodePlex team contacted me with a better download URL scheme.  See below.

The title says the big news:  I added elevate to the NuGet gallery.

ElevateInNuGet

Thanks to Phil Haack for helping me get started by writing a great post that makes it easy.

When we loaded the package, we chose to host the package on the elevate download page. That is the only part of the process that’s a bit tricky.  When you download the package from CodePlex, you have to accept the license. The link on the download page does not point to the download. 

The link on your download page looks like this:

http://elevate.codeplex.com/releases/view/31732#DownloadId=206119 (actual download link for the elevate NuPkg)

That isn’t what you need to register in the NuGet gallery.  Instead, you need the link to the binary release.  That’s this link:

http://download.codeplex.com/Project/Download/FileDownload.aspx?ProjectName=elevate&DownloadId=206119&FileTime=129415679423400000&Build=17501 (actual Elevate direct download link for the NuPkg.)

If you are uploading your own NuGet package, and the file is hosted on CodePlex, you need to perform a bit of a dance:

  1. Go to your download page on CodePlex.
  2. Examine the download link for your .nupkg file.  For instance, elevate’s is: http://elevate.codeplex.com/releases/view/31732#DownloadId=206119.
  3. Replace the ‘#’ character with a ‘?’. Elevate’s download link is now: http://elevate.codeplex.com/releases/view/31732?DownloadId=206119
  4. Use that link for your NuGet package. 

As for the current release of Elevate, you’ll notice that we currently have the 0.1 alpha release in the NuGet gallery.  Chris is working on a new release, and as soon as that release is ready, we’ll update the version in NuGet.

Created: 2/10/2011 2:54:55 PM

This is one of those small tips that took me way too long to find, and I figure if I needed to search that long to find the right answer, I might be able to help others by posting it here.

One practice I usually use for WPF and Silverlight applications is to create a 1:1 correspondence between my Views (Windows, User Controls, and so one) and my ViewModel classes. I find that practice makes it easier to ensure that I’ve tested the behavior of the different visual elements in the program.

In general, that works great. Each view has its own DataContext, and that DataContext points to a ViewModel that holds the properties for that view. But, there’s one place where that falls down: having a parent view control the visibility of the child control.

As an example, one windows has two child controls that occupy the same location. The associated view model assures that exactly of the two child controls is visible at one time:

          <
          c:FirstControl
        
          Grid.ColumnSpan="3"
          Visibility
          ="{Binding FirstControlVisible}"
          />
        
          <
          c:SecondControl
        
          Grid.ColumnSpan="3"
          Visibility
          ="{Binding SecondControlVisible}"
          />
        

So far, so good.  This ran great in prototypes, but once I created the specific ViewModel classes for FirstControl and SecondControl, it stopped working. No matter what I did, both controls were visible. I ran it through the debugger, and I was getting errors saying that the DataContext did not have the correct property.

Hmm. I knew my ViewModel had the right property (it worked before, all tests were still green), so what was going on? Well, the problem was that the binding was using the DataContext for each user control, not for the parent window.

I now had a different ViewModel for each View. That means each view has a different object for its DataContext. In order to get the parent DataContext, you have to specify the source in the binding.  It looks like the following:

          <
          c:FirstControl
        
          Grid.ColumnSpan="3"
          Visibility
          ="{Binding Path=DataContext.FirstControlVisible,    RelativeSource={RelativeSource AncestorType=Window}}"
          />
        
          <
          c:SecondControl
        
          Grid.ColumnSpan="3"
          Visibility
          ="{Binding Path=DataContext.SecondControlVisible,RelativeSource={RelativeSource AncestorType=Window}}"
          />
        

Note the extra information on the binding to specify the parent.

You may be thinking why you don’t need this more often. My UI was working in early prototypes before I flushed out more functionality. WPF has some binding features that helps you out. If a View’s DataContext is null, the binding infrastructure will use the parent DataContext. Before I built the child ViewModels, everything worked.

I don’t recommend binding to properties in another DataContext as a regular practice, but for the visibility of child controls, it does feel very natural. Just rememeber to set the DataContext to the right relative source.

Created: 7/13/2005 6:54:04 AM
Have been uploaded

The zip file below contains the samples from Monday's webcast, and an additional samples that adds the following (based on questions I received):

  • The binding source is serializable. It simply saves to a hardcoded file, but you get the point.
  • The Velocity class supports the IEditableObject interface, so edits can be cancelled
  • Property setters validate data and those exceptions are caught, and the user is notified.  Look at the velocity Class property setters, and the OnDataError method in the Form1 class.



The samples
After I've added a few items for questions

Created: 6/12/2005 11:10:33 PM
From an older article that is still online, comparing my approach to another author's.

Yet another reader question (from an older article online at fawcette.com)

I just read your VS Magazine article (see links below) regarding data-driven client validation and I had sort of a general question for you.  How does your approach differ from the approach taken by Enrico Sabbadin in the March 2004 issue of VSM (see links below)?  Is his technique one of the data distribution methods that you outlined in Table 1 of your article?  Do you have an opinion on his techniques?  I am looking at this from the perspective of how best to implement business objects within our enterprise.  Any advice you can give would be highly appreciated.    

Enrico’s algorithms are a form of the validation we proposed in the first line of the table in our article. (I want to remind everyone that the article referenced was co-authored by Tony Surma, whose insight was invaluable. If memory serves correctly, he provided all the information in the table referenced.) Enrico’s solution used code to handle the validation events at the client side. He used the same events that we did, but his validators were using rules that were baked into the code. We tried to provide generic code for classes of rules that would be common in business applications. Then, a controller would read an XML configuration file (using any of the methods shown in our article) and create the proper objects using the data defined in the objects.

The main difference between Enrico’s approach and ours was that we built in some capabilities to modify the business rules by modifying the data file that drove them. This extra capability comes with increased complexity. So I would recommend our solutions only when it’s expected that such changes are likely in the future.



The article by Tony Surma and me
Build Data-Driven Client Validation
The article by Enrico Sabbadin
Use DataSets as Business Objects
Created: 3/1/2005 7:21:57 AM
It does work, if you are not changing the data. In fact, that's the preferred way if the user is not allowed to change the data.

I received the following question (which does related to Effective C#). I thought the discussion was of general interest, so I posted it here instead of in the blog relating to the book:

I have a question about some recommendations that seem to conflict. Item 7 (Prefer Immutable Atomic Value Type) and Item 38 (Utilize and Suuport Data Binding) seem to contradict each other. It was my understanding that the data binding classes only worked on public properties to synchronize data. If you only provide "get" properties and not "set" properties, how would this work?

It is correct that Data Binding works by reflecting on public properties to synchronize data between controls and data objects.

The first answer is quite simple: If you only provide get accessors, you can transfer the data value from the data object to the control (either a web control or a windows control). You’ll see in Item 38 that I have some examples of this technique. Those are the examples that use a property on a data object to set the foreground or background color of a control. Being read-only properties, there is no way to store the data back into the data object. When that’s what you want, it works just fine.

The second answer is a bit more complicated. You’ll note that I stated in Item 7 that not every type can be an immutable type. Some of your low-level data storage objects should be immutable, and should be value types. But, if everything is immutable, your users cannot change anything in your program. Once again, look at the examples in Item 38. Some support edits: those are not immutable. Some (like the color example) are immutable.

Finally, let’s look at these two recommendations in concert. You could have a mutable type (an employee record for example) contain an immutable type (like an address structure). You could support data binding and transactions using these two types. You would expose the get and set accessors on the employee record. The set methods could create copy of an internal address structure. You can see this idiom in Item 41. (It is in a counter example, but there are times when it is the correct idiom.)



Created: 1/20/2005 7:50:48 PM
Copies and boxes and performance, Oh My.

This caught me and members of a client team recently, so I thought I would share it. In a Windows application, we created a simple value type to store a couple properties. Something like this:

public struct WeatherObservation
{
  private int _low;
  public int Low
  {
    get { return _low ; }
    set { _low = value; }
  }

  private int _high;
  public int High
  {
    get { return _high; }
    set { _high = value; }
  }
}

We had a form that asked the user for input. We utilized Windows Forms Binding:

textBoxLow.DataBindings.Add( "Text", this._weatherData, "Low" );
textBoxHigh.DataBindings.Add( "Text", this._weatherData, "High" );

And, it did not work. The user’s changes never were stored back into the _weatherData structure. Why?

Well, I’m not going to keep you waiting, I’ll dive right into the answer. The problem is that WeatherObservation is a struct, not a class. Structs are value types. They are passed by value, not by reference. More than that, the .NET environment boxes structs to use them where a System.Object is expected.

Here, the method signature for DataBindings.Add is

void Add( string propertyName, object DataSource, string DataMember );

The data source member , a struct, must get boxed in order to match the signature of the Add method. That boxing makes a copy. The databinding infrastructure dutifully modifies the copy whenever the user makes changes. But nowhere are those changes propagated from the copy back to the original object. The bottom line is that structs just can’t participate in read/write databinding. You must use reference types.

One best practice will help you avoid running into this situation yourself. Structs should be immutable. Then, you’ll never expect to use them in read/write situations. This does not prevent you from using members of a struct for read only databinding. The initial values are copied to the control, the same way they are copied when boxed.

You can even use structs as the final storage medium for databainding. When you need to use read/write databinding with a struct, the struct (which should be immutable, remember) should be stored as a member of a reference type. Then, you bind the outer reference type (as the datasource) to the control. The value type can be the datamember, or you can provide access to individual properties of the value type through the outer reference type.

I’ll close by addressing one common question: Why use value types at all? In many cases, the right answer is to avoid value types. It’s certainly simpler. But value types can and do provide some important performance benefits. The small snippet of code above isolated the behavior I wanted to show you, but the actual application was analyzing experiment results for an engineering application. Each experiment run generated several thousand points. The engineers were working with over 500,000 elements in one session. And, the application performs quite a few numerical calculations on all the values to interpret the experiment’s results. Collections that large do exhibit serious performance degradations when all the data are stored in reference types. The memory management issues do matter. Your mileage may vary, and you should always benchmark these kinds of performance issues. But, in general, I’ve found that the value types do offer performance benefits for datasets over 10,000, and then only when you are performing calculations that require you to examine each of the elements individually.



Created: 12/6/2004 5:37:23 AM
This one asks how to handle Properties of embedded objects.

Question:

Bill, 

After reading your paper on Visual Studio Magazine, I spent a few hours trying to bind to a subproperty and... I'm wondering if it is possible!

I first coded a ContactList class, a collection of Contact. ContactList is setup as your AddressList so I can use it as a component and bind my UI to it. Nice!

I then added an Addresses property - of type AddressList - to the Contact class. This enabled me to select contactList1 as DataSource and contactList1.Addresses as DataMember in the properties box for a DataGrid. Very nice!

Then I added a Phone property to the Contact class. Phone has type PhoneNumber, a custom class with 2 properties AreaCode and Number. My goal was to use the properties box to bind the Text property of a TextBox control (WinForms) to contactList1.PhoneNumber.AreaCode (in section Data/DataBindings/text of the properties box). But I missed something. I can't managed to have the PhoneNumber property to "expand" in the properties box. I've tried to use differents attributes for AreaCode and Phone properties. I also searched for an interface similar to ITypedList or IListSource, but for a single instance, not a list.

Do you have any idea on how to do it?

Anyway, thank you for the great value paper!

Answer:

Like almost everything, there is more than one answer. The simple answer is that you can modify your Contact class to contain properties for the phone number fields: AreaCode and PhoneNumber. These would simply delegate the work to the contained Phone object.

The other answer might be more elegant, but it is quite a bit more work. The Contact class must support the ICustomTypeDescriptor interface. The key method for your example is ICustomTypeDescriptor.GetProperties(). This method returns a collection of PropertyDescriptor objects, or objects of a class that derives from PropertyDescriptor. A PropertyDescriptor contains information on the name of the property, and can access the property’s Get and Set methods. In your example the name would be something like “PhoneAreaCode”, or “PhoneNumber”. The PropertyDescriptor’s “GetValue” method returns the value of the Phone objects Number property, by going through the Contact and Phone objects. There is a similar “SetValue” property, that sets the value of a named property by going through the Contact and Phone objects.

Incidentally, DataRowView supports the ICustomTypeDescriptor interface to provide the support for named columns in a typed dataset. That implementation uses reflection to determine what columns and relationships are available on a particular dataset. Those are exposed through the designer. At runtime, the same implementation handles the get and set methods for columns in each DataTable. Otherwise, the databinding libraries would not work with indexers, as used to access individual cells in the DataSet.



The original referenced article
Published June 2003 on Fawcette.com
Created: 12/3/2004 10:22:21 PM
A few questions and some answers about how to best perform data binding when you create windows forms.

Question: (or actually a few questions. Answers are inline)

I'm an up-and-coming .net developer whose trying to implement databinding to business objects. Your article here has been invaluable. It's the shortest, sweetest, thing I've found to get me up to speed. And I'm happy to say I've got a lot of things working. There's two questions I was hoping you could answer for me though, if you have a moment.

Other than precluding non-serialized events (thanks to Lhotka for pointing this out to me) is there any reason not to use VB.net versus C#? My company prefers VB so that's the route I need to go, unless there's a reason I shouldn't.

Answer: No, there really isn’t much difference. In fact, my favorite resource for Windows DataBinding is Chris Sell’s book. It’s available in both VB.NET and C# versions.

Is it just me, or is databinding to multiple controls finicky? I find your sample (linked above) works fine with just a datagrid. And I am usually able to add textboxes also, binding to the same collection at the same time. But it seems to blow up sometimes. I'm not exactly sure what causes it. But I thought maybe off the top of your head, you would know if this should even work at all?

Answer: Once again, Chris Sells discusses this. The key is that you must have the same datasource for all the controls. If you do that correctly, the CurrencyManager will keep the different controls in synch. However, if you have different datasources, you get different Binding Managers. Different Binding Managers means different binding contexts, which means that the different controls do not stay in synch when the Current index changes. My suggestion is to look at your code and make sure you use the same object for the DataSource in all cases. The DataMember is what you change to get different properties in each different control.



The original article
A discussion of databinding and multiple controls
Chris Sell's book
The C# Version
Chris Sell's book
The VB.NET Version
Rockford Lhotka's blog
Another great resource
Created: 9/18/2004 7:06:21 AM
ITypedList and when to use it.

Over the past two weeks, I’ve gotten two questions relating to Windows Forms Databinding and custom collections.

In the first case, the developer had created a collection that held polymorphic items:

public class MyBaseClass
{

  // internals elided.

}


public
class Derived1 : MyBaseClass
{

  // internals elided.

}


public
class Derived2 : MyBaseClass
{

  // internals elided.

}


public
class Derived3 : MyBaseClass
{

  // internals elided.

}


ArrayList myCollection = new
ArrayList();
myCollection.Add( new Derived1());

myCollection.Add( new Derived2());

myCollection.Add( new Derived3());


// Use
a data source doesn’t work:
MyDataGrid.DataSource = myCollection;


This does not work because the WindowsForms DataGrid class makes an assumption that all the objects in the collection are the exact same type. In the above example, it assumes all objects are of type Derived1. That fails. This person wanted the DataGrid to assume that it had a collection of MyBaseClass objects.

The second question involved navigation. (If you are not familiar with navigating in a datagrid, see this MSDN article) I had a colleague create a collection where one of the properties was itself a collection. For example:

public classCustomer
{

  public string Name

  {

    get{ return _name;}

  }


  // The contained collection:

  private
ArrayList _orders;
  public IList Orders

  {

    return _orders;

  }

}

He wanted to bind a data grid to a list of customers and allow users to navigate to the set of orders for that customer. That did not work either.

Well, the answer to both questions is the same: Implement the ITypedList interface. ITypedList contains two methods:

public interface ITypedList
{

  public PropertyDescriptorCollection GetItemProperties(

    PropertyDescriptor[] listAccessors);

  public string GetListName( PropertyDescriptor[]

    listAccessors);

}

Both of these routines give information about the elements in the collection. GetItemProperties() returns a collection that describes all the properties that should be displayed in the collection. For a single level collection, these routines are always called with a null listAccessors parameter. That will solve the first problem. You simply return a name for your collection for GetListName:

public string GetListName( PropertyDescriptor[]
  listAccessors)

{

  return "MyBaseClass";

}

For GetItemProperties, you return a collection of all the properties you want displayed:

public PropertyDescriptorCollection
  GetItemProperties( PropertyDescriptor[]

  listAccessors)

{

  return TypeDescriptor.GetProperties(

    typeof( MyBaseClass ));

}

That solves the first problem. To solve the second problem, you need to understand the listAccessors parameter. This is an array of PropertyDescriptors that describe how to navigate from the top-level list to the specific collection currently being used. My simple example above had only one contained type. Therefore, the listAccessors parameter will either be null, or contain one element. That tells you what should be returned:

public string GetListName( PropertyDescriptor[]
  listAccessors)

{

  if ( null
== listAccessors )
    return "Customers";

  else

  {

    PropertyDescriptor p = listAccessors[ 0 ];

    return p.DisplayName;

  }

}

The GetItemProperties() method is similar. You return the public properties of the type contained in the collection referenced by listAccessors[0]. In my simple example above, listAccessors[0] would be the type ArrayList, which is the type of the collection. You need to return the type of the objects in the collection (here that would be the Order class).

The whole point of this discussion is that the DataGrid uses reflection to determine how to bind to your data. If your datasource supports the ITypedList interface, those methods are used to support navigation and to determine which columns should be displayed. If not, the DataGrid displays all the properties found in the first item in the collection, and navigation is not supported.

You can learn more here: http://www.ftponline.com/vsm/2003_06/online/wagner/default_pf.aspx



Created: 6/7/2004 6:14:19 AM
Question and answer on the DataGrid, Datasets.How do you format the information, and trap user interaction.

Question:

I have a question, do you happen to know how to format data as it is going into a datagrid from a dataset and dataadapter?  I want to format my numbers in one for one field with four decimal places and then the next field with two decimal places and another with 3 digits total and no decimal places. I cannot control the data that user is putting in, but the data that is displayed in the application should be easier. Any ideas?

It is f or Win forms, if it were web forms I would be all set, because the Help that comes with Visual Studio provides an example.  I actually need to format entire columns of data. 

I do not know if you know the answer to this question, but is there a way for me to check data as it goes into each cell in a datagrid? As I see it, the data adapter fills with data depending on the query, then this data fills the data set.  I want to make sure that there is only numeric data and that it is formatted correctly.  I have been knocking myself out trying to nest SQL statements for the data adapter for the formatting and I cannot figure it out, but checking each cell's data is a different matter.  Any help is appreciated.

Answer:

Formatting data in the DataGrid is quite simple. You can do it in the designer, or in code.  This figure  shows how it's done in the designer.  The "Format" property of the DataGridTextBoxColumn is a standard .NET string format specifier.  In the attached JPG, I've set the format for the Price column to N4, which displays 4 decimal places. All the format specifiers you need are in thisMSDN page.This is one of my gripes with VS.NET in the current version.  If you are using the default mechanism of displaying *all* columns, you need to create every column by hand in the designer.

Or, you can write code to find the column, and change the specifier that way, in your form's load handler.

DataGridTableStyle style = dataGridTitles.TableStyles["titles"];
DataGridTextBoxColumn columnStyle = style.GridColumnStyles["Price"]
as DataGridTextBoxColumn;
columnStyle.Format = "N2";

Verifying the data requires subscribing to the DataColumnChangeEvent in the dataset This event gives you both the current & proposed values for the column.  You can allow or cancel any change.



Created: 5/3/2004 9:52:32 PM
The state of the change has a bearing on how you should examine the changes in a dataset.

Q: Why does Dataset.GetChanges() return an empty dataset? Examine the following code: The dataset stored in ChangedDoc.xml is empty. Why?

ds.ReadXml("http://localhost:400/TMSEProto/Proposal.xml");
ds.AcceptChanges();
ds.Tables["LineDetail"].Rows[2].Delete();

DataSet ds1;
ds1 = ds.GetChanges(DataRowState.Deleted);
ds1.WriteXmlSchema("c:\\ChangedSchema.xml");
ds1.WriteXml("c:\\ChangedDoc.xml");
// ChangedDoc.xml is empty :-(

A: It’s all in the Diffgrams.

There is more than one WriteXml method.  DataSet.GetChanges() does return the deleted rows. But, they are marked as deleted, so they are hidden from normal view.  To write the deleted rows, you need to serialize the dataset asa diffgram:

WriteXml( XmlWriteMode.DiffGram );

This will serialize both the original and current values, and will therefore include the deleted rows. The deleted rows will be marked as deleted. In fact, every modified row will show two versions: the original and the modified version.



Created: 3/31/2004 7:33:07 AM
Question and Answer on creating and using DataBinding in your own types.

Q: When you bind to business objects, then you not only want to bind
to the properties of the objects, often you want to display properties
of related objects.
 
Example: You have a DataGrid displaying a list of Order objects, the
class Order has a property OrderCustomer that returns a object of class Customer.
When you now display a list of Orders, then whenever you add the
OrderCustomer column to the grid you get a string containing the
name "Cstomer". I guess this happens, because the databinding mechanism
calls object.ToString() on each property. I can think of many instances
where it would be very useful to display the Customer Name in the row
of an order, so this would be a property of a property. 

A:
You are correct.  You get the "Customer" output because of the default ToString behavior. If you override the Object.ToString() method in your Customer object to return the Name property, that behavior would change.

On a case to case basis, this can be achieved if you would define a
property Customer_Name in the Order class. But then there are so many
possibilities, and it does not make sense to code all of these possibilities
when you do create the class. In a certain sense, you then do not follow
the object oriented programming paradigm.
 
I don't think it makes sense to create a list of all properties and sub_properties
that a class has; I believe that there must be a smarter way to do that.
 There are three ways to do this.  Which makes the most sense depends on your application.
 
1: Use the datagrid navigation paradigm.  In this version, you "drilldown" from the Order table into the selected customer(s) in the customer table. This works well when the users will view the navigation up and down the hierarchy using the DataGrid navigation strategy.
 
2: Expose individual sub-properties as you described above. This is the best choice when you have a small number of properties to add.
 
3: Create a new combined data-binding class that contains both the customer and the order objects, and therefore exposes both. This is somewhat of a heavy-weight version of 2.  However, you can use some data-tier logic to create a combined set using a join.



The referenced article.
The original article on DataBinding

Current Projects

I create content for .NET Core. My work appears in the .NET Core documentation site. I'm primarily responsible for the section that will help you learn C#.

All of these projects are Open Source (using the Creative Commons license for content, and the MIT license for code). If you would like to contribute, visit our GitHub Repository. Or, if you have questions, comments, or ideas for improvement, please create an issue for us.

I'm also the president of Humanitarian Toolbox. We build Open Source software that supports Humanitarian Disaster Relief efforts. We'd appreciate any help you can give to our projects. Look at our GitHub home page to see a list of our current projects. See what interests you, and dive in.

Or, if you have a group of volunteers, talk to us about hosting a codeathon event.