I wanted to share this tip because I feel some Visual Studio features look like magic. In this tip, you'll see how to convert a C# class into a DataSource.
DataSources are objects and objects are classes. Transforming a class into a DataSource is great because it allows you to use LINQ to enumerate and read the data. This is also useful when you create a report or need to have access to individual records in DataRow formats. So, take a class with the data definition and with custom properties and add a key to the class to make it appear as a DataSource.
Let's start by creating a class. By assigning some attributes to a class, you're telling the compiler to make it a data object. In the following code, we add a DataObjectAttribute to a partial class and also make it serializable.
  1. using System.ComponentModel;
  2. [System.Serializable]
  3. [DataObjectAttribute]
  4. public partial class ReportProcessosEAndamentos
  5. {
  6. public int ID { get; set; }
  7. public string Name { get; set; }
  8. pubblic string MyData => MyCustomDataTransforms(); // You can process fields from the table or project
  9. // ANY OTHERS PROPERTIES
  10. // You can Add readonly property using private:
  11. public int MyReadOnlyProperty { get; private set; }
  12. }
Now, we need to add a property to the function that will load the DataSource and retrieve a data list.
[DataObjectMethodAttribute(DataObjectMethodType.Select, true)]
  1. [DataObjectMethodAttribute(DataObjectMethodType.Select, true)] public static IEnumerable<BIExportData> GetList()
  2. => FillData(ConnectionString);
Here is a full sample from my real app www.Advocati.NET.
  1. using System;
  2. using System.Text;
  3. using System.Data;
  4. using System.Xml.Serialization;
  5. using System.Collections.Generic;
  6. using MenphisSI.DB;
  7. using System.Data.SqlClient;
  8. using System.ComponentModel; // Add Componente Model 01
  9. namespace MenphisSI.GerAdv
  10. {
  11. /// <summary>
  12. /// Objeto de nível de acesso a dados
  13. /// </summary>
  14. [System.Serializable]
  15. [DataObjectAttribute] // This Attribute in the top of the class 02
  16. // ReSharper disable once InconsistentNaming
  17. public partial class DBAcao : VAuditor, ICadastros
  18. {
  19. private string m_FDescricao;
  20. [XmlAttribute]
  21. public int ID {get;set;}
  22. [XmlAttribute]
  23. public string FDescricao
  24. {
  25. get => m_FDescricao ?? string.Empty;
  26. set => m_FDescricao = value;
  27. }
  28. public DBAcao() { }
  29. /// <summary>
  30. /// Lista a tabela
  31. /// </summary>
  32. /// <param name="cWhere"></param>
  33. /// <param name="cOrder"></param>
  34. /// <param name="cCnn"></param>
  35. /// <param name="nTop">/param>
  36. /// <returns></returns>
  37. [DataObjectMethodAttribute(DataObjectMethodType.Select, true)] // Add this property to be the readable entry point
  38. public static IEnumerable<DBAcao> Listar(string cWhere, string cOrder, string cCnn, int nTop = 0)
  39. {
  40. var cSql = new StringBuilder(TSql.Select);
  41. if (nTop > 0) cSql.Append($" TOP {nTop} ");
  42. cSql.Append(DBAcao.CamposSqlX);
  43. cSql.Append(TSql.From);
  44. cSql.Append($"[dbo].[{DBAcao.PTabelaNome}] ");
  45. if (cWhere.NotIsEmpty())
  46. {
  47. if (cWhere.NãoContemUpper(TSql.Where)) cSql.Append(TSql.Where);
  48. cSql.Append(cWhere);
  49. }
  50. if (cOrder.NotIsEmpty())
  51. {
  52. if (cOrder.NãoContemUpper(TSql.OrderBy))
  53. cSql.Append($"{TSql.OrderBy} {cOrder}");
  54. else
  55. cSql.Append(cOrder);
  56. }
  57. else if (DBAcao.CampoNome.NotIsEmpty())
  58. {
  59. cSql.Append($"{TSql.OrderBy}{DBAcao.CampoNome}");
  60. }
  61. DataTable ds;
  62. try
  63. {
  64. using (var oCnn = ConfiguracoesDBT.GetConnection(cCnn))
  65. {
  66. if (oCnn is null) yield break;
  67. ds = ConfiguracoesDBT.GetDataTable(cSql.ToString(), oCnn);
  68. }
  69. }
  70. catch { yield break; }
  71. if (ds.Rows.Count <= 0) yield break;
  72. for (var nt = 0; nt < ds.Rows.Count; nt++)
  73. yield return new DBAcao
  74. {
  75. ID = Convert.ToInt32(ds.Rows[nt][DBAcaoDicInfo.CampoCodigo]),
  76. FDescricao = ds.Rows[nt][DBAcaoDicInfo.Descricao].ToString(),
  77. };
  78. }
  79. }
Note that "yield return" is a powerful command that will return the object directly to the IEnumerable list instead of crerating a list and return it in the end of the function/method.
Now, let's take a look at the sample using Telerik as Object DataSource and how to use it.
Open the DataSource.
Name it, and choose your load method, mark to get only.
To use the class, you need to populate with data.
How to use your "new" data component source is up to you.
Good luck!