This is part three of a three part series on working with master-detail data. In part one I showed how to present detail values on the master using a utility I wrote called the SubPropertyAccessor. In part two I showed how the SubPropertyAccessor works. In this part, I introduce a descendant of DataGridViewColumn that will allow us to show the indexed detail data in line with the master data as additional columns. I also introduce a descendent of TypeDescriptionProvider that allows the DataGridView to see the SubProperty as a proper property so that the rest of the grid functionality will still work.
Note: The SubPropertyAccessor was called SubAttributeAccessor in parts one and two.
SubPropertyColumn
The whole point of having detail values appear as part of a master record is to show the data in a grid where the detail values would appear in columns next to the other properties in the record. In order to do this I created a descendant of DataGridViewColumn called SubPropertyColumn. Actually, SubPropertyColumn is a descendant of DataGridViewTextBoxColumn. The DataGridViewTextBoxColumn has most of the functionality I want. I only need to have the data marshaled in and out of the data bound item in a specific way.
The first thing we need is to know where the SubPropertyAccessor is on the data bound item. This will be a property on the column that can be set at design time in the DataGridView designer.
72: /// <summary>
73: /// The name of the property that is the indexed property.
74: /// Note that for sorting to work this
75: /// should be set to 'Properties'
76: /// </summary>
77: [Category("Data"),
78: DefaultValue("Properties"),
79: Description("The name of the property that is the indexed property.")]
80: public string IndexedPropertyName {
81: get { return fIndexedPropertyName; }
82: set {
83: fIndexedPropertyName = value;
84: }
85: }
Now that we know where to find the SubPropertyAccessor, we need to know which property we are looking for. This is the index that we will pass into the SubPropertyAccessor. We need another string property.
114: /// <summary>
115: /// The index to pass to the indexed property to get the value for this column.
116: /// </summary>
117: [Category("Data"),
118: DefaultValue(""),
119: Description("The index to pass to the indexed property to get the value for this column.")]
120: public string PropertyIndex {
121: get {
122: return base.DataPropertyName;
123: }
124: set {
125: base.DataPropertyName = value;
126: }
127: }
This property doesn’t have any backing data of its own. It is using the DataPropertyName of the base DataGridViewTextBoxColumn. We do this because the base DataGridColumn bases a lot of functionality on the DataPropertyName property. For example, if this property is blank the base DataGridColumn doesn’t consider the column to be a data bound column. If we are going to make use of the functionality provided by the base classes, we going to have to make them happy. This may seem like a kludge, but it’s better than having to reinvent the DataGridColumn.
More...