1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398
|
namespace System.Web.DynamicData {
using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Diagnostics.CodeAnalysis;
using System.Data.Linq;
using System.Diagnostics;
using System.Globalization;
using System.Linq.Expressions;
using System.Web;
using System.Web.DynamicData.Util;
using System.Web.Resources;
using System.Web.UI;
using System.Web.UI.WebControls;
/// <summary>
/// Extension methods used by DynamicData
/// </summary>
public static class DynamicDataExtensions {
public static void SetMetaTable(this INamingContainer control, MetaTable table) {
SetMetaTableInternal(control, table, null/* defaultValues*/, new HttpContextWrapper(HttpContext.Current));
}
public static void SetMetaTable(this INamingContainer control, MetaTable table, IDictionary<string, object> defaultValues) {
if (defaultValues == null) {
throw new ArgumentNullException("defaultValues");
}
SetMetaTableInternal(control, table, defaultValues, new HttpContextWrapper(HttpContext.Current));
}
public static void SetMetaTable(this INamingContainer control, MetaTable table, object defaultValues) {
if (defaultValues == null) {
throw new ArgumentNullException("defaultValues");
}
SetMetaTableInternal(control, table, Misc.ConvertObjectToDictionary(defaultValues), new HttpContextWrapper(HttpContext.Current));
}
public static IDictionary<string, object> GetDefaultValues(this IDataSource dataSource) {
return GetDefaultValues(dataSource, new HttpContextWrapper(HttpContext.Current));
}
public static IDictionary<string, object> GetDefaultValues(this INamingContainer control) {
return GetDefaultValues(control, new HttpContextWrapper(HttpContext.Current));
}
public static MetaTable GetMetaTable(this IDataSource dataSource) {
return GetMetaTable(dataSource, new HttpContextWrapper(HttpContext.Current));
}
public static bool TryGetMetaTable(this IDataSource dataSource, out MetaTable table) {
return TryGetMetaTable(dataSource, new HttpContextWrapper(HttpContext.Current), out table);
}
public static MetaTable GetMetaTable(this INamingContainer control) {
return GetMetaTable(control, new HttpContextWrapper(HttpContext.Current));
}
public static bool TryGetMetaTable(this INamingContainer control, out MetaTable table) {
return TryGetMetaTable(control, new HttpContextWrapper(HttpContext.Current), out table);
}
internal static void ApplyFieldGenerator(INamingContainer control, MetaTable table) {
GridView gridView = control as GridView;
if (gridView != null && gridView.AutoGenerateColumns && gridView.ColumnsGenerator == null) {
gridView.ColumnsGenerator = new DefaultAutoFieldGenerator(table);
}
else {
DetailsView detailsView = control as DetailsView;
if (detailsView != null && detailsView.AutoGenerateRows && detailsView.RowsGenerator == null) {
detailsView.RowsGenerator = new DefaultAutoFieldGenerator(table);
}
}
}
internal static DefaultValueMapping GetDefaultValueMapping(object control, HttpContextBase context) {
IDictionary<object, MappingInfo> mapping = MetaTableHelper.GetMapping(context);
MappingInfo mappingInfo;
if (mapping.TryGetValue(control, out mappingInfo)) {
return mappingInfo.DefaultValueMapping;
}
return null;
}
internal static IDictionary<string, object> GetDefaultValues(object control, HttpContextBase context) {
DefaultValueMapping mapping = GetDefaultValueMapping(control, context);
if (mapping != null) {
return mapping.Values;
}
return null;
}
internal static MetaTable GetMetaTable(IDataSource dataSource, HttpContextBase context) {
MetaTable table;
if (TryGetMetaTable(dataSource, context, out table)) {
return table;
}
throw new InvalidOperationException(String.Format(CultureInfo.CurrentCulture, DynamicDataResources.MetaTable_CannotGetTableFromDataSource));
}
internal static bool TryGetMetaTable(IDataSource dataSource, HttpContextBase context, out MetaTable table) {
if (dataSource == null) {
throw new ArgumentNullException("dataSource");
}
Debug.Assert(context != null);
table = MetaTableHelper.GetTableFromMapping(context, dataSource);
if (table == null) {
var dynamicDataSource = dataSource as IDynamicDataSource;
if (dynamicDataSource != null) {
table = MetaTableHelper.GetTableFromDynamicDataSource(dynamicDataSource);
}
}
return table != null;
}
internal static MetaTable GetMetaTable(INamingContainer control, HttpContextBase context) {
MetaTable table;
if (!TryGetMetaTable(control, context, out table)) {
throw new InvalidOperationException(String.Format(CultureInfo.CurrentCulture, DynamicDataResources.MetaTable_CannotGetTableFromControl));
}
return table;
}
internal static bool TryGetMetaTable(INamingContainer control, HttpContextBase context, out MetaTable table) {
if (control == null) {
throw new ArgumentNullException("control");
}
table = MetaTableHelper.GetTableFromMapping(context, control);
return table != null;
}
internal static void SetMetaTableInternal(INamingContainer control, MetaTable table, IDictionary<string, object> defaultValues, HttpContextBase context) {
if (control == null) {
throw new ArgumentNullException("control");
}
if (table == null) {
throw new ArgumentNullException("table");
}
IDataBoundControl dataBoundControl = control as IDataBoundControl;
IDataSource dataSource = null;
if (dataBoundControl != null) {
dataSource = dataBoundControl.DataSourceObject;
}
MetaTableHelper.SetTableInMapping(context, control, table, defaultValues);
if (dataSource != null) {
// If the control being mapped is a databound control then register its datasource
MetaTableHelper.SetTableInMapping(context, dataSource, table, defaultValues);
}
}
/// <summary>
/// Return the MetaTable association with a datasource
/// </summary>
[SuppressMessage("Microsoft.Design", "CA1011:ConsiderPassingBaseTypesAsParameters", Justification = "This is a legacy API and cannot be changed")]
public static MetaTable GetTable(this IDynamicDataSource dataSource) {
return MetaTableHelper.GetTableWithFullFallback(dataSource, HttpContext.Current.ToWrapper());
}
/// <summary>
/// Expand Dynamic where parameter (e.g. DynamicControlParameter, DynamicQueryStringParameter) into
/// 'regular' parameters that the datasource can understand
/// </summary>
/// <param name="dataSource">The datasource which Where parameters need to be expanded</param>
public static void ExpandDynamicWhereParameters(this IDynamicDataSource dataSource) {
ParameterCollection whereParameters = dataSource.WhereParameters;
// First, check if any parameters need to be expanded
bool needProcessing = false;
foreach (Parameter parameter in whereParameters) {
if (parameter is IWhereParametersProvider) {
needProcessing = true;
break;
}
}
// If not, don't do anything
if (!needProcessing)
return;
// Make a copy of the parameters, and clear the collection
var whereParametersCopy = new Parameter[whereParameters.Count];
whereParameters.CopyTo(whereParametersCopy, 0);
whereParameters.Clear();
// Go through all the parameters and expand them
foreach (Parameter parameter in whereParametersCopy) {
ExpandWhereParameter(dataSource, parameter);
}
}
private static void ExpandWhereParameter(IDynamicDataSource dataSource, Parameter parameter) {
var provider = parameter as IWhereParametersProvider;
if (provider == null) {
// If it's a standard parameter, just add it
dataSource.WhereParameters.Add(parameter);
}
else {
// Get the list of sub-parameters and expand them recursively
IEnumerable<Parameter> newParameters = provider.GetWhereParameters(dataSource);
foreach (Parameter newParameter in newParameters) {
ExpandWhereParameter(dataSource, newParameter);
}
}
}
/// <summary>
/// Find the containing data control, and return the data source it points to
/// </summary>
public static IDynamicDataSource FindDataSourceControl(this Control current) {
return DataControlHelper.FindDataSourceControl(current);
}
/// <summary>
/// Find the containing data control, and return the MetaTable associated with it, if any
/// </summary>
public static MetaTable FindMetaTable(this Control current) {
return MetaTableHelper.FindMetaTable(current, HttpContext.Current.ToWrapper());
}
/// <summary>
/// Find the field template for a column within the current naming container
/// </summary>
public static Control FindFieldTemplate(this Control control, string columnName) {
return control.FindControl(DynamicControl.GetControlIDFromColumnName(columnName));
}
/// <summary>
/// Make the SelectedIndex sync up with the PersistedSelection. Concretely, what it means is that
/// if you select a row and then page away (or sort), the selection remains on that row
/// even if it's not currently visible.
/// </summary>
[Obsolete("Use the EnablePersistedSelection property on a databound control such as GridView or ListView.")]
public static void EnablePersistedSelection(this BaseDataBoundControl dataBoundControl) {
EnablePersistedSelectionInternal(dataBoundControl);
}
internal static void EnablePersistedSelectionInternal(BaseDataBoundControl dataBoundControl) {
IDataBoundListControl dataBoundListControl = dataBoundControl as IDataBoundListControl;
if (dataBoundListControl != null) {
dataBoundListControl.EnablePersistedSelection = true;
//
if (dataBoundListControl.SelectedIndex < 0) {
// Force the first item to be selected
dataBoundListControl.SelectedIndex = 0;
}
}
}
/// <summary>
/// Set the DataLoadOptions on a Linq To Sql datasource to force all the FK entities
/// to be directly loaded.
/// </summary>
/// <param name="dataSource">The data source for which we want to preload FKs</param>
/// <param name="rowType">The type of the entities returned by the data source</param>
public static void LoadWithForeignKeys(this LinqDataSource dataSource, Type rowType) {
dataSource.ContextCreated += delegate(object sender, LinqDataSourceStatusEventArgs e) {
// This only applies to a DLinq data context
var context = e.Result as DataContext;
if (context == null)
return;
DataLoadOptions loadOptions = null;
ParameterExpression tableParameter = null;
System.Data.Linq.Mapping.MetaTable metaTable = context.Mapping.GetTable(rowType);
foreach (System.Data.Linq.Mapping.MetaDataMember member in metaTable.RowType.DataMembers) {
if (member.IsAssociation && !member.Association.IsMany) {
if (member.Type.Equals(rowType)) continue;
if (loadOptions == null) {
loadOptions = new DataLoadOptions();
tableParameter = Expression.Parameter(rowType, "e");
}
var memberExpression = Expression.Property(tableParameter, member.Name);
loadOptions.LoadWith(Expression.Lambda(memberExpression, tableParameter));
}
}
if (loadOptions != null) {
context.LoadOptions = loadOptions;
}
};
}
public static void LoadWith<TEntity>(this LinqDataSource dataSource) {
LoadWithForeignKeys(dataSource, typeof(TEntity));
}
/// <summary>
/// Apply potential HTML encoding and formatting to a string that needs to be displayed
/// This logic is mostly copied from BoundField.FormatDataValue, but omits the old Whidbey behavior path
/// </summary>
/// <param name="fieldValue">The value that should be formatted</param>
/// <param name="formattingOptions">The IFieldFormattingOptions to use. This is useful when using options different from the column's</param>
/// <returns>the formatted value</returns>
public static string FormatValue(this IFieldFormattingOptions formattingOptions, object fieldValue) {
string formattedValue = String.Empty;
if (fieldValue != null) {
string dataValueString = fieldValue.ToString();
string formatting = formattingOptions.DataFormatString;
int dataValueStringLength = dataValueString.Length;
// If the result is still empty and ConvertEmptyStringToNull=true, replace the value with the NullDisplayText
if (dataValueStringLength == 0 && formattingOptions.ConvertEmptyStringToNull) {
dataValueString = formattingOptions.NullDisplayText;
}
else {
// If there's a format string, apply it to the raw data value
// If there's no format string, then dataValueString already has the right value
if (!String.IsNullOrEmpty(formatting)) {
dataValueString = String.Format(CultureInfo.CurrentCulture, formatting, fieldValue);
}
// Optionally HTML encode the value (including the format string, if any was applied)
if (!String.IsNullOrEmpty(dataValueString) && formattingOptions.HtmlEncode) {
dataValueString = HttpUtility.HtmlEncode(dataValueString);
}
}
formattedValue = dataValueString;
}
else {
formattedValue = formattingOptions.NullDisplayText;
}
return formattedValue;
}
/// <summary>
/// Similar to FormatValue, but the string is to be used when the field is in edit mode
/// </summary>
public static string FormatEditValue(this IFieldFormattingOptions formattingOptions, object fieldValue) {
string valueString;
// Apply the format string to it if that flag is set. Otherwise use it as is.
if (formattingOptions.ApplyFormatInEditMode) {
valueString = formattingOptions.FormatValue(fieldValue);
}
else {
valueString = (fieldValue != null) ? fieldValue.ToString() : String.Empty;
}
// Trim any trailing spaces as they cause unwanted behavior (since we limit the input length and the
// spaces cause the limit to be reach prematurely)
valueString = valueString.TrimEnd();
return valueString;
}
/// <summary>
/// Return either the input value or null based on ConvertEmptyStringToNull and NullDisplayText
/// </summary>
/// <param name="formattingOptions">the formatting options object</param>
/// <param name="value">The input value</param>
/// <returns>The converted value</returns>
public static object ConvertEditedValue(this IFieldFormattingOptions formattingOptions, string value) {
// If it's an empty string and ConvertEmptyStringToNull is set, make it null
if (String.IsNullOrEmpty(value) && formattingOptions.ConvertEmptyStringToNull) {
return null;
}
// If it's the NullDisplayText, return null
string nullDisplayText = formattingOptions.NullDisplayText;
if (value == nullDisplayText && !String.IsNullOrEmpty(nullDisplayText)) {
return null;
}
// Otherwise, return it unchanged
return value;
}
/// <summary>
/// If this column represents an enumeration type, this method returns that type. The caloumn can represent
/// an enumeration type if the underlying type is an enum, or if it is decoareted with EnumDataTypeAttribute.
/// If this column does not represent an enum, this method returns null.
/// </summary>
/// <param name="column"></param>
/// <returns></returns>
[SuppressMessage("Microsoft.Design", "CA1011:ConsiderPassingBaseTypesAsParameters", Justification = "The interface is internal")]
public static Type GetEnumType(this MetaColumn column) {
return GetEnumType((IMetaColumn)column);
}
internal static Type GetEnumType(this IMetaColumn column) {
return column.Attributes.GetAttributePropertyValue<EnumDataTypeAttribute, Type>(a => a.EnumType, null) ??
(column.ColumnType.IsEnum ? column.ColumnType : null);
}
internal static bool IsEnumType(this MetaColumn column, out Type enumType) {
enumType = column.GetEnumType();
return enumType != null;
}
}
}
|