Configuring 'AutoGenerateColumns' property of a DataGridView - c#

I have a datagridview configured to autogenerate columns based on my class (using databinding).
It works just fine for all my properties of type string. However, I have a property of an enum type, with a typeconverter to convert it to an image.
I'd like for my Grid's autogeneration of columns to produce a DataGridViewImageColumn instead of a DataGridViewTextBoxColumn.
The only DGV method that seems helpful is columns added. However, you cannot set the column there, only get & modify.
Any Ideas?

as far as i know, the AutoGeneration isn't very configurable
but you can make an alternative auto gen for yourself:
set autogen = false,
register to these events:
OnDataMemberChanged
OnDataSourceChanged
add a single function that will be triggered for both, which will create columns for the dataSource given:
header = column name
column type = according to what you want
data binding = the column name
etc.

Related

Telerik RAD Controls, how to set a List(Of GridViewRowInfo) as a RadGridView DataSource?

I'm looking for a C# or VB.NET solution for this.
UPDATE:
I have a RadGridView with 5 manualy defined columns by me:
AutoGenerateColumns property is set to False.
When I instace a GridViewRowInfo class I can set a lot of properties for this object:
Dim MyRow As New GridViewRowInfo(Me.RadGridView1.MasterView)
With MyRow
.Cells(0).Value = "My Value for Column 1"
.Cells(1).Value = "My Value for Column 2"
.Cells(2).Value = "My Value for Column 3"
.Cells(3).Value = "My Value for Column 4"
.Cells(4).Value = "My Value for Column 5"
.Height = 50
.Tag = New Object
.IsSelected = True
End With
And when I add that row the properties that I've previously set for that row takes effect inmediately:
RadGridView1.Rows.Add(MyRow)
If I want to add a collection of those rows just I can set a new collection of GridViewRowInfo that implements the IList interface:
Dim MyRows As New List(Of GridViewRowInfo)
MyRows.Add(MyRow1)
MyRows.Add(MyRow2)
MyRows.Add(MyRow3)
RadGridView1.Rows.AddRange(MyRows.ToArray)
Well, so my intention is to set a collection of those rows as DataSource, for example:
RadGridView1.DataSource = MyRows
So the first thing to notice is that I've set a collection of GridViewRowInfo and I've set different properties for each GridViewRowInfo that should take effect when adding the datasource-collection, the second thing is that if I update the datasource-collection to remove or add more rows then the RadGridView control should perform the updates automatically without more intervention ...not?
The problem is that any of those things happens:
As you could see in the image above, when I set a List(of GridViewRowInfo) as my DataSource, it only adds empty rows, and if I previously have set for example the Height property of one of the GridViewRowInfo inside it does not take effect when setting the Datasource:
I would like to perform this in the more direct way and the less extravagant way, I mean i'm not looking for create a custom class to be able to set that class as DataSource, and reproducing all the properties that exposes the GridViewRowInfo class or something so tricky in my custom class, 'cause If the RadGridView exposes a good GridViewRowInfo class with all that I need why I should consider to create a custom class to set it aa my DataSource?.
If I don't have a good idea or a missunderstanding of these concepts please clarify me them, I know that the usage of the datasource should not be used in that way (or I think so) but I really would like to do it to simplify the things even more to work directly with the datasource (and each row property) instead the control itself.
Also I've tried the oficial example in this link (but just using a list(Of String) instead), but it just adds a new column in my gridview named 'Length' (with a numeric data) in that column cell.
RadGridView supports two ways of populating with data:
Unbound mode where you can manually add the columns and the rows to the grid (just like you did)
Bound mode where you set the DataSource property of the control to one of the supported types, namely
Array and ArrayList of simple types or custom objects.
Generic Lists of simple types or custom objects.
BindingList or other IBindingList` implementations.
Database data using DataTable, DataSet or DataReader components from a wide range of providers (MS SQL, Oracle, Access,
anything accessible through OleDb).
So, you cannot bind the grid to collection of GridViewRowInfos (as you will only see the GridViewRowInfo type properties). You should either continue manually adding the as you are right now, or you can populate a DataTable for example with your data and set it as DataSource for the grid.
*All of the links and information are from the Telerik UI for WinForms documentation
If I don't have a good idea or a missunderstanding of these concepts please clarify them
You are confusing WHAT to display with HOW to display them which are 2 very different things. From their online guide: The RadGridView supports the standard Windows Forms data binding model which is to say the datasource provides data for the control, not presentation information.
Public Class MyObject
Public Property MyInt() As Integer
Public Property MyString() As String
...
Dim myList As New List(Of MyObject)()
myList.Add(New MyObject(1, "Outdoor"))
myList.Add(New MyObject(2, "Hardware"))
myList.Add(New MyObject(3, "Tools"))
myList.Add(New MyObject(4, "Books"))
myList.Add(New MyObject(5, "Appliances"))
RadGridView1.DataSource = myList
Result:
Note how the control automatically picks up the Property Names from the custom class: MyInt and MyString become column names. That is the only layout (HOW) related thing the grid picks up from the DataSource, and thats only when AutoGenerateColumns is True (otherwise they would be blank). When False, you control it by laying out the columns.
Now look at what you are attempting:
With MyRow
.Cells(0).Value = "My Value for Column 1"
.Cells(1).Value = "My Value for Column 2"
...
.Height = 50
.Tag = New Object
.IsSelected = True
There are many problems with this as a DataSource. Mainly, you are not supplying data for cells, but data in cells for cells. Your approach sort of mixes the unbound approach (explicitly specify what is to go into each cell), with binding to a datasource.
But, how is it supposed to know Value is a data display item? How is it supposed to know to drill into the cell collection to find Value? How is it supposed to know that Value is data but Tag is not? How is it supposed to know not to try to display Height as column data? Just because the name matches a control's property name?
What would happen if myObject by chance had a Height property related to my class? You want the control to interpret it as control layout information, but the rest of the world would want the patient's height, or building height or geo formation height to show as data. We would have to design classes with unique names not found in the control in order to get our data to show and prevent the control presentation from whimsically changing based on data and property names in the DataSource.
The GridviewRowInfo as the name suggests provides row information, not row data. Extensive presentation information is present in your List, but it doesnt work like you want because controls do not use the datasource to get presentation infomation.
The control does include Four ways to customize RadGridView appearance: Themes, UI editor, Events and Conditional Formatting.
There other elements like GridTableElement and GridTableBodyElement. Actually these elements contain some properties that control behavior and appearance of grid cells and rows, like GridTableElement.RowHeight, RowSpacing and so on.
tl;dr
Data passed in a DataSource, does not affect the presentation (aside from Column names with AutoGenerateColumns, but that is a function of that property, not the datasource.)

DataGridView AccessibleName

I have a DataGridView on a Winforms form and, as usual, space is limited. The column titles are therefore often abbreviated ("Qty.", "No." etc.). My screenreader (JAWS) handles the DataGridView like a table and reads the column header as I navigate through the "cells" (i.e. the controls in the grid). Ideally, I would like to get the screenreader to use an accessible name for the header, so it would read "quantity" instead of "queue tea why".
I can't find an AccessibleName property for the column or the column header. Does anyone know where it is lurking, or is it simply not available?
I do not know much about JAWS but if you you have a space issue with your DGV columns why don't you set the column header DefaultCellStyle > WrapMode property to true, So that if you use more than one word in any column header text it can be wrapped. So you might be able to use meaningful column names instead of abbreviations.
I don't know how JAWS works, if you just need a property called AccessibleName you can create a new DataGridView Column class inheriting from DataGridViewTextBoxColumn
public class AccessibleDataGridViewTextBoxColumn : DataGridViewTextBoxColumn
{
public string AccessibleName { get; set; }
}
and adding them to your DataGridView. You can then set the property with your desired text in the designer or in your code.

DataGridView not displaying my List

Although there are a lot of posts on this site about populating a gridview with objects, I can't get it working.
I have a class called Logs with 3 public properties - Time, Description and Error.
There is also a public property called logList that will return a List of Logs Objects.
And I have DataGridView in my WinForm, called myGV, with 3 columns called Time, Description and Error.
So I'm trying:
myGV.DataSource = Logs.logList.OrderBy(x => x.Time);
But my DataGridView displays nothing, even though logList does contain data.
Thanks for your work on this site!
UPDATE:
If I remove all columns from myGV it does display data. So how do match static columns to the properties in my List of Objects?
It's strange that you said If I remove all columns from myGV it does display data.... I reproduced your problem and the reason is your LINQ query is not executed. You have to call ToList() or similar method before using the result as DataSource of your DataGridView:
myGV.DataSource = Logs.logList.OrderBy(x => x.Time).ToList();
Of course, If your static columns don't have DataPropertyName matched with the properties of the DataSource, there will be more columns added to your DataGridView than you expect. For example, suppose all the Time, Description and Error are added at design time without assigning any DataPropertyName and yourDataGridView.AutoGenerateColumns = true (by default), if you assign the DataSource of your DataGridView as above, your DataGridView may have 6 columns at all, instead of 3. So you can assign the DataPropertyName of your added columns before assigning the DataSource for your DataGridView, something like this:
myGV.Columns["Time"].DataPropertyName = "Time";
myGV.Columns["Description"].DataPropertyName = "Description";
myGV.Columns["Error"].DataPropertyName = "Error";
myGV.DataSource = Logs.logList.OrderBy(x => x.Time).ToList();//This should be called at here after all the DataPropertyNames are initialized.
I recommend you to set myGV.AutoGenerateColumns = true (by default) and remove all the added columns, just let the DataGridView auto-generate columns for you.
After you manually add the columns, you have to make sure you update the DataPropertyName of each one of them:
Click in the little arrow on top of your DataGridView, to display the Control's Tasks.
Click on Edit Columns.
For each of your columns find the property DataPropertyName and change them to Date, Error and Description and whatever other names you have used for your columns.
Make sure these match with your Properties in your Logs class.
OrderBy() returns IOrderedEnumerable<> type of data, that are not bindable to DataGridView.
So you have to cast them to a Binding Source.
Use ToList() method like
"OrderBy().ToList()" to bind your gridview.
dataGridView1.DataSource = studList.OrderBy(a => a.Age).ToList();
It is working
For more info to bind DataGridView visit dataGridView binding

Array as DataSource of a DataGrid: how to customize columns?

In my Windows Mobile .NET application I have a simple array of object with the data I want to display in my DataGrid. To do this, I simply call:
myDataGrid.DataSource = myArray;
This works, but I have a problem with it: it uses all properties as columns and uses the names of the properties as the column headers. I can't figure out how to customize two things:
Select which subset of properties should be displayed as columns (say I have an ID, Name and Value property, I'd only want to show Name and Value);
Rename the column headers to make more sense (for example if the property is called ID display a column header saying "Number").
Is this possible at all?
As mentioned this is in a Windows Mobile .NET (version 2) application.
You need to set the Datagrid.TableStyles property to customize the layout.
http://msdn.microsoft.com/en-us/library/system.windows.forms.datagrid.tablestyles.aspx
More details on binding to an array of objects here:
http://msdn.microsoft.com/en-us/library/system.windows.forms.datagridtablestyle.mappingname(VS.71).aspx
To bind the
System.Windows.Forms.DataGrid to a
strongly typed array of objects, the
object must contain public properties.
To create a DataGridTableStyle that
displays such an array, set the
MappingName property to classname[]
where classname is replaced by the
class name. Also note that the
MappingName property is
case-sensitive.
I don't know if you know the name of the columns in advance? But if it's the case, you can go in the "Edit Columns" of your DataGridView and just create your columns there. In the "Data" Category, change the "DataPropertyName" from "(none)" to the name of the class property. From there you can customize the name, if it's visible, the size, etc. The DataGrid will bind it to your DataSource.
Also, there is a property "DataGridView.AutoGenerateColumns" that you can set to false so you don't have to bind all the properties of your object. I tought that migh help as well.
In this code _im is an object of table and I bind this object with DataGridView dgvItem after binding I change header text of dgvItem as required.
dgvItem.Rows.Clear();
dgvItem.DataSource = _im ;
dgvItem.Columns[2].HeaderText = "Mobile Code";
dgvItem.Columns[3].HeaderText = "Mobile Name";

How to control Column Type in DataGridView that is bound to a CustomObject?

I have a DataGridView in a C# WinForms app that is DataBound at runtime (through Form_Load) to a custom Object.
In the design view of the DataGridView I have no columns set up.
When the Form loads the the columns are automatically created based on the data in the Custom object that it is DataBound to.
My question is how can I control the the Columns that are automatically created.
For example if I want one of the columns to be a DataGridViewLinkColumn instead of the DataGridViewTextBoxColumn that is automatically created?
The default columns are based on the data-type. I haven't checked, but for a link you could try exposing the data as Uri, but that might be hopeful. Really, if you want a specific type of column - add the columns through code and set DataGridView.AutoGenerateColumns to false.
As Andrew implies; normally something like reflection is used to generate the columns, and you'll get a column for every (browsable + public + readable) property. There is a layer of abstraction on top of this if you need, but this won't help with adding a hyperlink column.
You can pre-create your columns in the designer. If the name of the column matches the name of the property the column will end up bound to, the databinding will take care of the DGV population for you as before.

Categories

Resources