15

I'm trying to create a DataGridTableStyle object so that I can control the column widths of a DataGrid. I've created a BindingSource object bound to a List. Actually it's bound to an anonymous type list created though Linq in the following manner (variable names changed for clarity of what I'm doing):

List<myType> myList = new List<myType>(someCapacity);
.
...populate the list with query from database...
.

var query = from i in myList
            select new
            {
                i.FieldA,
                i.FieldB,
                i.FieldC
            };

myBindingSource.DataSource = query;
myDataGrid.DataSource = myBindingSource;

Then I create a DataGridTableStyle object and add it to the datagrid. However, it never applies my table style properties I set up because I can't seem set the proper myDataGridTableStyle.MappingName property.

I've searched Google for about 1/2 an hour and keep seeing links to the same question throughout a bunch of different forums (literally the same text, like someone just copied and pasted the question... I hate that...). Anyway, none of the suggestions work, just like the guy says on all the other sites.

So does anybody here know what I need to set the MappingName property to in order to have my TableStyle actually work properly? Where can I grab the name from? (It can't be blank... that only works with a BindingSource that is bound to a DataTable or SqlCeResultSet etc.).

I'm thinking it could be an issue with me using Linq to create an anonymous, more specialized version of the objects with only the fields I need. Should I just try to bind the BindingSource directly to the List object? Or maybe even bind the DataGrid directly to the List object and skip the binding source altogether.

Thanks

PS - C#, Compact Framework v3.5

UPDATE:

I've posted an answer below that solved my problem. Whether or not it's the best approach, it did work. Worth a peek if you're having the same issue I had.

Jason Down
  • 21,731
  • 12
  • 83
  • 117
  • You usually see duplicate questions because many sites are aggregating the same newsgroups so in some cases the question was only posted once yet re-displayed in the web multiple times in different locations. – Quibblesome Jan 07 '09 at 14:13
  • True enough... just frustrating sometimes because the same question takes up the first 10 pages on Google. It'd be nice if they could be filtered as being the same. – Jason Down Jan 07 '09 at 14:22

5 Answers5

26

I've found the way to make this work. I'll break it out into sections...


List<myType> myList = new List<myType>(someCapacity);
.
...populate the list with query from database...
.

DataGridTableStyle myDataGridTableStyle = new DatGridtTableStyle();
DataGridTextBoxColumn colA = new DataGridTextBoxColumn();
DataGridTextBoxColumn colB = new DataGridTextBoxColumn();
DataGridTextBoxColumn colC = new DataGridTextBoxColumn();

colA.MappingName = "FieldA";
colA.HeaderText = "Field A";
colA.Width = 50; // or whatever;

colB.MappingName = "FieldB";
.
... etc. (lather, rinse, repeat for each column I want)
.

myDataGridTableStyle.GridColumnStyles.Add(colA);
myDataGridTableStyle.GridColumnStyles.Add(colB);
myDataGridTableStyle.GridColumnStyles.Add(colC);

var query = from i in myList
            select new
            {
                i.FieldA,
                i.FieldB,
                i.FieldC
            };

myBindingSource.DataSource = query.ToList(); // Thanks Marc Gravell

// wasn't sure what else to pass in here, but null worked.
myDataGridTableStyle.MappingName = myBindingSource.GetListName(null); 

myDataGrid.TableStyles.Clear(); // Recommended on MSDN in the code examples.
myDataGrid.TablesStyles.Add(myDataGridTableStyle);
myDataGrid.DataSource = myBindingSource;

So basically, the DataGridTableStyle.MappingName needs to know what type of object it is mapping to. Since my object is an anonymous type (created with Linq), I don't know what it is until runtime. After I bind the list of the anonymous type to the binding source, I can use BindingSource.GetListName(null) to get the string representation of the anonymous type.

One thing to note. If I just bound the myList (which is type "myType") directly to the binding source, I could have just used the string "myType" as the value for DataGridTableStyle.MappingName.

Hopefully this is useful to other people!

Jason Down
  • 21,731
  • 12
  • 83
  • 117
9

Just to add to the collection of answers already on this page....

I was just frustrated with this same issue trying to develop my fist application using windows forms and compact framework (For Windows Mobile 6.5).

What I found out, through Marc Gravell's comment above is that indeed is possible to get the run time MappingName inspecting the properties of the DataGrid. Doing this I found out that when binding my List<MyType> directly to the DataSource property of the DataGrid, the DataGrid was actually looking for a DataGridTableStyle with the MappingName of

"List`1"

instead of any combination of List<MyType> or MyType...

So... by putting "List`1" in the Mapping name on the DataGridTableStyle Collection Editor (at design time), I was able to customize the columns and other properties without having to create them all at run time.

I just hope this adds some more to the answers already provided. Thank you all for providing me with the guidelines.

Marcio Gabe
  • 181
  • 3
  • 9
  • 2
    +1 - An alternative is to use tableStyle.MappingName = yourList.GetType().Name; I saw it [here](http://stackoverflow.com/a/866337/743433) – Gilney Oct 02 '13 at 21:21
2

The query returns IEnumerable<T> for some T, but most binding sources (except ASP.NET) require IList (such as any IList<T> implementation) - try adding .ToList() - i.e.

myBindingSource.DataSource = query.ToList();

A BindingList<T> might work even better (if it is supported in CF 3.5) since it has better support for some of the common binding scenarios; if you need this (and assuming BindingList<T> exists on CF 3.5), you can add an extension method:

static BindingList<T> ToBindingList<T>(this IEnumerable<T> data)
{
    return new BindingList<T>(new List<T>(data));
}

then call:

myBindingSource.DataSource = query.ToBindingList();

For completeness, an alternative to an IList is IListSource (or even Type for purely-metadata scenarios), which is why DataSource is commonly typed as object; if it wasn't for this issue, the compiler probably would have been able to tell you the problem (i.e. if DataSource was defined as IList).

Marc Gravell
  • 1,026,079
  • 266
  • 2,566
  • 2,900
  • Thanks Mark. I'll try the query.ToList() approach first. I'm still wondering what I actually need to set my TableStyle.MappingName to though. How do I get the name from the BindingSource object (e.g. bs.List.GetType().Name or something like that)? Thanks again – Jason Down Jan 07 '09 at 14:23
  • What do you mean by the "name" of the BindingSource? Can you clarify? – Marc Gravell Jan 07 '09 at 14:27
  • 1
    Some searching suggests that you can check the dataGrid.m_tabstyActive field in the Quick Watch window; this should give you the name you need to use to avoid getting a new style. – Marc Gravell Jan 07 '09 at 14:29
  • The DataTableGridStyle needs the MappingName set to whatever datasource you are using. I've tried the name of the BindingSource, but it doesn't seem to work, so my DataTableGridStyle doesn't actually apply to the DataGrid. Now I'm trying to get the name of the underlying list in the bs. – Jason Down Jan 07 '09 at 14:32
  • Ya I did see that link. I actually wanted to create my own DataGridTableStyle object though and have that apply, rather than using the one that is used by default. I guess I can try changing the default style object's properties if that's possible. – Jason Down Jan 07 '09 at 14:36
  • Yeah I remember what a pain this is, I have code at home that encountered the same issue so i'll try to post later tonight after checking it. It's another of those DataSet > BO scenarios that makes one annoyed. – Quibblesome Jan 07 '09 at 15:05
  • I also tried the debugger link myself but could never find the property that guy spoke about. – Quibblesome Jan 07 '09 at 15:06
  • I managed to get it to work. I'll post up once I figure what I did (made the mistake of changing 3 things at once, so now I need to figure out what actually caused it to work). – Jason Down Jan 07 '09 at 15:14
1

I followed this answer and found that the MappingName always came out to be the underlying class name (myType in the example).

So it seems that putting the collection it through the BindingSource solves the problem anyway and that there is then no need for BindingSource.GetListName(null).

Also I found no need to ToList() the query as the BindingSource will also do this for you.

Many thanks to Jason Down for putting me on the right track.

0

I was facing same problem for setting column width. After lot of R & D, i changed code as below and its working fine. Code:

DataGridTableStyle tableStyle = new DataGridTableStyle();
tableStyle.MappingName = dgCustom.DataSource.GetType().Name;

where dgCustom is DataGrid ID in dgCustom.DataSource.GetType().Name which is working perfectly.

Tunaki
  • 132,869
  • 46
  • 340
  • 423