ListView programatically added columns shows type of item

2k views Asked by At

I got a ListView in another assembly and want to add a column to it. The items in the listview are objects of a class in that assembly.

When I add a column like this

var col : GridViewColumn = new GridViewColumn();
col.Header = "Header text";
list.View.Columns.Add(col);

the column appears but all rows in the listview have the name of the type of the item in that new column. Even when I change the value of the new column (itemclass.Items[newColIdx] = "zz") this does not display. There is no data binding or cell templates involved.

Why is that?

Edit: Maybe I can enhance the question: If a ListView.Items contains an array of class A - how do you control which things of A are displayed how in the GridView? I am in the need of reverse engineering here and DisplayMemberBinding is null so it does not use data binding AFAIK.

Bounty Question: When ToString() is called on every item (which represents a row), how is that mapped towards the columns of the GridView? How must I alter an item in the row so that the new column is filled?

Special problem when trying to find this solution is that this runs in a JScript sandbox within a bigger C# .NET application and no debugging possibility is supplied other than using message boxes and reflection.

Edit: The problem is that I am writing a JScript which runs in a 3rd party .NET application and gives me the opportunity to do many things possible with .NET. This is a script adding features to a listview. I can access the listview and it is filled with database data by the 3rd party app. I do not know how it does that. I can programatically add custom rows with custom content (not DB related). But when I add a custom column I do not seem to be able to se its value in den rows.

The added rows are of a type 3rdParty.ListRow and contain a property Items to which I assign a string array. The values of the array are displayed in the representative columns - but not in the added columns. There I only get the text 3rdParty.ListRow which is because ToString() was called on the ListRow.

So: How can I tell the new columns (e.g. index 5) to display ListRow.Items[5] and not ListRow.ToString()? I liked to do it the same way the already existing columns do it seems that all the properties Alex mentioned are undefined there. How would I set DataMemberBinding to achieve mapping to ListRow.Items[5]?

2

There are 2 answers

6
Alex Aza On BEST ANSWER

If column doesn't have DisplayMemberBinding or CellTemplate then ToString is called on each item in the grid and evaluated value is used as cell content.

For example, if you have class:

public class Person
{
    public string FirstName { get; set; }

    public string LastName { get; set; }

    public override string ToString()
    {
        return LastName;
    }
}

If you bind a collection of Person to the grid view:

var people =
    new List<Person>
    {
        new Person { FirstName = "Peter", LastName = "Smith" }, 
        new Person { FirstName = "Steve", LastName = "White" },
        new Person { FirstName = "Dave", LastName = "Gates" },
    };

listView1.ItemsSource = people;

And if you create a new column without binding, then LastName will be shown in this column, because overridden ToString() returns LastName. If you change ToString to return FirstName then new column will show FirstName.

Hope I understood your question correctly.

[Edit]

If you add many new columns and don't use DisplayMemberBinding then all the new columns will evaluate and show ToString() result. You need to set DisplayMemberBinding to show particular property.

var newColumn = new GridViewColumn();
newColumn.Header = "Test";
newColumn.DisplayMemberBinding = new Binding("FirstName");
gridView.Columns.Add(newColumn);

[Edit] Answers to your questions:

When ToString() is called on every item (which represents a row), how is that mapped towards the columns of the GridView? How must I alter an item in the row so that the new column is filled?

ToString is called when cell presenter is rendered, unless you specified binding or template, which would also use binding in the end. You cannot alter row item to control how it is represented in the grid, unless you override ToString or properties that are bound to the columns.

Not sure I understand your problem completely. You are adding a new column, right? Why don't you set DisplayMemberBinding property on your column? If you do this you will be able to show in the column whatever you want.

[Edit]

I think I answered your bounty question :). I think I already earned the bounty :).

However, here is the answer to your next question:

How would I set DataMemberBinding to achieve mapping to ListRow.Items[5]?

The answer:

newColumn.DisplayMemberBinding = new Binding("Items[5]");
1
Fabian Nicollier On

That's because the ToString() method of each items in the list is being called. If not overridden by the inheriting type, Object.ToString() returns the object's type name.

There's another issue where your list won't raise change events so the UI doesn't know the data has changed and needs to refresh.