Link to home
Start Free TrialLog in
Avatar of jknj72
jknj72

asked on

Trying to generate GridView columns programmatically

I have a program where I am trying to generate the columns dynamically from an IEnumerable datasource, which Ive never used before, and Im having trouble with. I assign the Datasource to the gridview  and then I try to create the columns but it was orignally done in C# but I am dtrying to do it in VB.NEt so I havent been able to get this done.

Here is the code in C#...I tried to convert to VB.NET using Telerix but Im passing in a DataView as the source where in this code its passing in a dynamic source, which cant be done in VB so when I try to run the GetProperties I am getting the same values? Can someone help me out here to get this done in VB.NET passing in a DataView or a DataTable?

 public static void PrepareColumns(dynamic source, DataControlFieldCollection columns, Func<string, string> headerNameFormatter)
        {
            // if ViewState is enabled, the columns info will be persisted between requests and we only want to add the column
            // the first time the grid is requested.
            if (columns.Count == 0)
            {
                // at this point, the datasource must have been prepared and it must be a list
                var properties = source[0].GetType().GetProperties();
                foreach (var property in properties)
                {
                    var name = property.Name;

                    var field = new BoundField
                                    {
                                        DataField = name,
                                        HeaderText =
                                            headerNameFormatter == null
                                                ? SeperateNamesWithSpace(name)
                                                : headerNameFormatter(name),
                                        SortExpression = name,
                                        HtmlEncode = false
                                    };

                    if (property.PropertyType.Name == "DateTime")
                    {
                        field.DataFormatString = "{0:dd-MMM-yyyy}";
                    }

                    columns.Add(field);
                }
            }
        }
Avatar of jknj72
jknj72

ASKER

Sorry I meant to say that I am NOT getting the same values in the GetProperties
Avatar of it_saige
In all honesty, I believe this might be what you are after:
Module Extensions
	<System.Runtime.CompilerServices.Extension()> _
	Public Sub PrepareColumns(Of T)(ByVal source As IEnumerable(Of T), ByVal columns As DataControlFieldCollection, ByVal headerNameFormatter As Func(Of String, String))
		' if ViewState is enabled, the columns info will be persisted between requests and we only want to add the column 
		' the first time the grid is requested. 
		If columns.Count = 0 Then
			' at this point, the datasource must have been prepared and it must be a list
			Dim properties = source(0).[GetType]().GetProperties()
			For Each [property] As PropertyInfo In properties
				Dim name = [property].Name

				Dim field = New BoundField() With { _
					.DataField = name, _
					.HeaderText = If(headerNameFormatter Is Nothing, SeperateNamesWithSpace(name), headerNameFormatter(name)), _
					.SortExpression = name, _
					.HtmlEncode = False _
				}

				If [property].PropertyType.Name = "DateTime" Then
					field.DataFormatString = "{0:dd-MMM-yyyy}"
				End If

				columns.Add(field)
			Next
		End If
	End Sub
End Module

Open in new window

-saige-
Avatar of jknj72

ASKER

I got an error on this  
"Unable to cast object of type 'System.Data.DataRowView' to type 'System.Collections.IEnumerable'. "
on
Dim properties = source(0).[GetType]().GetProperties()

In the example I am going off of it is using a System.Linq.Enumerable.WhereSelectIsIterator as the source and I am using a database so I am passing in a different type as the original.  But I think Im in the ballpark!

In my example I am passing in a DataView, as the source,, which is causing a problem for me. I have the datasource set and can pass in a datatable or whatever if I need to?

Thanks for your help
Avatar of jknj72

ASKER

Just so you know I prepare the DataSource prior to the Columns so maybe I need to change anything here? Again, his is obviously in C# but Im doing it in VB

        public static void PrepareDataSource(
            GridView gvGeneric,
            StateBag viewState,
            ref IEnumerable DataSource,
            ref int _totalRowCount,
            Func<GridViewSortEventArgs, IEnumerable> sorting)
        {
            var column = viewState[Const.SortExpression] as string;
            SortDirection sortDirection = SortDirection.Ascending;
            if (viewState[Const.SortDirection] != null)
            {
                sortDirection = (SortDirection)viewState[Const.SortDirection];
            }

            var temp = DataSource.Cast<object>();
            _totalRowCount = temp.Count();

            if (column != null)
            {
                var source = SortingHelper.GetSortedObjects(new GridViewSortEventArgs(column, sortDirection), temp, sorting);
                DataSource = source;
            }
            else if (DataSource.GetType().Name != Const.ListTypeName)
            {
                DataSource = temp.ToList();
            }

            gvGeneric.DataSource = DataSource;
        }
I'm not seeing where you prepare the columns.  Can provide the code associated with this?  Also it would help if you use code blocks.

1. Press the '[b]CODE[/b]' glyph in the formatting bar.

User generated image

2. This will insert code blocks.

User generated image

3. Code is formatted like the following.

This is example code

Open in new window


-saige-
Avatar of jknj72

ASKER

Ok sorry, I just pasted it in there? Could you not see my first post with the code in it? The Sub was called PrepareColumns

 public static void PrepareColumns(dynamic source, DataControlFieldCollection columns, Func<string, string> headerNameFormatter)
        {
            // if ViewState is enabled, the columns info will be persisted between requests and we only want to add the column 
            // the first time the grid is requested. 
            if (columns.Count == 0)
            {
                // at this point, the datasource must have been prepared and it must be a list
                var properties = source[0].GetType().GetProperties();
                foreach (var property in properties)
                {
                    var name = property.Name;

                    var field = new BoundField
                                    {
                                        DataField = name,
                                        HeaderText =
                                            headerNameFormatter == null
                                                ? SeperateNamesWithSpace(name)
                                                : headerNameFormatter(name),
                                        SortExpression = name,
                                        HtmlEncode = false
                                    };

                    if (property.PropertyType.Name == "DateTime")
                    {
                        field.DataFormatString = "{0:dd-MMM-yyyy}";
                    }

                    columns.Add(field);
                }
            }
        }

Open in new window


and then the PrepareDataSource which I call before the PrepareColumns

      public static void PrepareDataSource(
            GridView gvGeneric,
            StateBag viewState,
            ref IEnumerable DataSource,
            ref int _totalRowCount,
            Func<GridViewSortEventArgs, IEnumerable> sorting)
        {
            var column = viewState[Const.SortExpression] as string;
            SortDirection sortDirection = SortDirection.Ascending;
            if (viewState[Const.SortDirection] != null)
            {
                sortDirection = (SortDirection)viewState[Const.SortDirection];
            }

            var temp = DataSource.Cast<object>();
            _totalRowCount = temp.Count();

            if (column != null)
            {
                var source = SortingHelper.GetSortedObjects(new GridViewSortEventArgs(column, sortDirection), temp, sorting);
                DataSource = source;
            }
            else if (DataSource.GetType().Name != Const.ListTypeName)
            {
                DataSource = temp.ToList();
            }

            gvGeneric.DataSource = DataSource;
        }

Open in new window


Hope I did it correctly and thanks for your help!!!
Avatar of jknj72

ASKER

oh I see what you mean now...Thanks for the correction
You did fine.

To clarify, where is the code that calls the PrepareColumns and PrepareDataSource  methods?

-saige-
Avatar of jknj72

ASKER

Ahh sorry...Here it is... In my code I had to take out the sorting in the DataSource call and the HeaderFormatter in the Column call, so  you could ignore those parameters because I couldnt figure out the C# conversion to VB.NET so I had to work around it

        
    Public DataSource As IEnumerable
    'Public Event HeaderFormatting As Func(Of String, String)
    'Public Event Sorting As Func(Of GridViewSortEventArgs, IEnumerable)

        gvGeneric.AllowPaging = AllowSorting
        gvGeneric.AllowSorting = AllowSorting

        DataSourceHelper.PrepareDataSource(gvGeneric, ViewState, DataSource, _totalRowCount) ', Sorting(e))
        ColumnHelper.PrepareColumns(DataSource, gvGeneric.Columns) ', HeaderFormatting)

Open in new window

Avatar of jknj72

ASKER

Im thinking I need to convert the DataSource to a list because thats what they had it as in the example. I just created a dataset and tried to pass it in that way(tried a dataview as well) and it didnt work.
ASKER CERTIFIED SOLUTION
Avatar of it_saige
it_saige
Flag of United States of America image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of jknj72

ASKER

thanks Saige