1 using System.Collections.Generic; 2 using System.Diagnostics; 3 using System.Globalization; 4 using System.Web.DynamicData.Util; 5 using System.Web.Resources; 6 using System.Web.UI; 7 using System.Web.UI.WebControls; 8 9 namespace System.Web.DynamicData { 10 11 /// <summary> 12 /// DynamicControlParameter is similar to ControlParameter, but understainds higher level concepts. e.g. in a 13 /// master-details scenario using a GridView and DetailsView, you only need to point the DetailsView's datasource 14 /// to the GridView (using a DynamicControlParameter), and it does the right thing. This works even for 15 /// multi-part primary keys 16 /// </summary> 17 public class DynamicControlParameter : Parameter, IWhereParametersProvider { 18 19 /// <summary> 20 /// </summary> DynamicControlParameter()21 public DynamicControlParameter() { } 22 23 /// <summary> 24 /// </summary> DynamicControlParameter(string controlId)25 public DynamicControlParameter(string controlId) { ControlId = controlId; } 26 27 /// <summary> 28 /// The ID of the control from which the parameter gets its data 29 /// </summary> 30 public string ControlId { get; set; } 31 32 /// <summary> 33 /// See IWhereParametersProvider.GetWhereParameters 34 /// </summary> GetWhereParameters(IDynamicDataSource dataSource)35 public virtual IEnumerable<Parameter> GetWhereParameters(IDynamicDataSource dataSource) { 36 Debug.Assert(dataSource != null); 37 38 // Find the control that the ControlParameter uses 39 Control control = Misc.FindControl((Control)dataSource, ControlId); 40 41 if (control == null) { 42 throw new InvalidOperationException(String.Format( 43 CultureInfo.CurrentCulture, DynamicDataResources.DynamicControlParameter_DynamicDataSourceControlNotFound, ControlId)); 44 } 45 46 // If the control is itself a parameter provider, delegate to it 47 var whereParametersProvider = control as IWhereParametersProvider; 48 if (whereParametersProvider != null) { 49 return whereParametersProvider.GetWhereParameters(dataSource); 50 } 51 52 IControlParameterTarget paramTarget = DynamicDataManager.GetControlParameterTarget(control); 53 54 if (paramTarget == null) { 55 throw new InvalidOperationException(String.Format(CultureInfo.CurrentCulture, 56 DynamicDataResources.DynamicControlParameter_DynamicDataSourceControlCannotBeUsedAsParent, ControlId)); 57 } 58 59 string columnName = Name; 60 MetaColumn column = null; 61 MetaTable table = MetaTableHelper.GetTableWithFullFallback(dataSource, HttpContext.Current.ToWrapper()); 62 if (!String.IsNullOrEmpty(columnName)) { 63 column = table.GetColumn(columnName); 64 } 65 else { 66 // There was no Name attribute telling us what field to filter, but maybe 67 // the control given us data has that info 68 column = paramTarget.FilteredColumn; 69 } 70 71 if (column == null) { 72 // If there is no specific column, we're setting the primary key 73 74 if (paramTarget.Table != table) { 75 throw new Exception(String.Format(CultureInfo.CurrentCulture, 76 DynamicDataResources.DynamicControlParameter_InvalidPK, 77 ControlId, paramTarget.Table, table.Name)); 78 } 79 80 return GetPrimaryKeyControlWhereParameters(control, paramTarget); 81 } 82 else if (column is MetaForeignKeyColumn) { 83 return GetForeignKeyControlWhereParameters(control, paramTarget, (MetaForeignKeyColumn)column); 84 } 85 return GetPropertyControlWhereParameters(control, paramTarget, column); 86 } 87 GetPropertyControlWhereParameters(Control control, IControlParameterTarget paramTarget, MetaColumn column)88 private IEnumerable<Parameter> GetPropertyControlWhereParameters(Control control, 89 IControlParameterTarget paramTarget, MetaColumn column) { 90 ControlParameter controlParameter = new ControlParameter() { 91 Name = column.Name, 92 ControlID = control.UniqueID, 93 PropertyName = paramTarget.GetPropertyNameExpression(column.Name) 94 }; 95 96 DataSourceUtil.SetParameterTypeCodeAndDbType(controlParameter, column); 97 98 yield return controlParameter; 99 } 100 GetPrimaryKeyControlWhereParameters(Control control, IControlParameterTarget paramTarget)101 private IEnumerable<Parameter> GetPrimaryKeyControlWhereParameters(Control control, 102 IControlParameterTarget paramTarget) { 103 104 MetaTable parentTable = paramTarget.Table; 105 if (parentTable != null) { 106 // For each PK column in the table, we need to create a ControlParameter 107 foreach (var keyColumn in parentTable.PrimaryKeyColumns) { 108 var controlParameter = new ControlParameter() { 109 Name = keyColumn.Name, 110 ControlID = control.UniqueID, 111 PropertyName = paramTarget.GetPropertyNameExpression(keyColumn.Name) 112 }; 113 114 DataSourceUtil.SetParameterTypeCodeAndDbType(controlParameter, keyColumn); 115 116 yield return controlParameter; 117 } 118 } 119 } 120 GetForeignKeyControlWhereParameters(Control control, IControlParameterTarget paramTarget, MetaForeignKeyColumn column)121 private IEnumerable<Parameter> GetForeignKeyControlWhereParameters(Control control, 122 IControlParameterTarget paramTarget, MetaForeignKeyColumn column) { 123 124 MetaTable parentTable = paramTarget.Table; 125 if (parentTable != null) { 126 string namePrefix = String.Empty; 127 // Make sure the data types match 128 if (column.ColumnType != parentTable.EntityType) { 129 throw new Exception(String.Format(CultureInfo.CurrentCulture, 130 DynamicDataResources.DynamicControlParameter_DynamicDataSourceColumnNotCompatibleWithTable, 131 column.DisplayName, parentTable.Name)); 132 } 133 134 // For each underlying FK, we need to create a ControlParameter 135 Debug.Assert(column.ForeignKeyNames.Count == parentTable.PrimaryKeyColumns.Count); 136 int index = 0; 137 foreach (var fkName in column.ForeignKeyNames) { 138 MetaColumn parentTablePKColumn = parentTable.PrimaryKeyColumns[index++]; 139 140 var controlParameter = new ControlParameter() { 141 Name = fkName, 142 ControlID = control.UniqueID, 143 PropertyName = paramTarget.GetPropertyNameExpression(parentTablePKColumn.Name) 144 }; 145 146 DataSourceUtil.SetParameterTypeCodeAndDbType(controlParameter, parentTablePKColumn); 147 148 yield return controlParameter; 149 } 150 } 151 } 152 153 /// <summary> 154 /// same as base 155 /// </summary> 156 /// <param name="context"></param> 157 /// <param name="control"></param> 158 /// <returns></returns> Evaluate(HttpContext context, Control control)159 protected override object Evaluate(HttpContext context, Control control) { 160 // If this gets called, it means we never had a chance to expand the parameter. Give an error 161 // telling the user to use a DynamicDataManager 162 throw new InvalidOperationException(String.Format( 163 CultureInfo.CurrentCulture, DynamicDataResources.DynamicParameter_NeedExpansion, typeof(DynamicControlParameter).Name)); 164 } 165 } 166 } 167