Fuzzi59 Fuzzi59 - 2 months ago 24
C# Question

Add column to listview that contains an image

I want to add a row using data from a

ExpandoObject
, which is similar to a
Dictionary<string, object>
. The
string
is the header of the column and the
object
's value is value of the column.
Everytime, when I get new data I'm creating a new
GridView
, because the number of columns can be different. In the
List
myItems are all rows
Dictionary<string, object>
, that I want to show in my view.

This is how I add the columns to my view:

List<Column> columns = new List<Column>();

myItemValues = (IDictionary<string, object>)myItems[0];
// Key is the column, value is the value
foreach (var pair in myItemValues)
{
Column column = new Column();
column.Title = pair.Key;
column.SourceField = pair.Key;
columns.Add(column);
}
view.Columns.Clear();
foreach (var column in columns)
{
Binding binding = new Binding(column.SourceField);
if (column.SourceField == "Icon")
{
view.Columns.Add(new GridViewColumn
{
Header = column.Title,
DisplayMemberBinding = binding,
CellTemplate = new DataTemplate(typeof(Image))
});
}
else
{
view.Columns.Add(new GridViewColumn { Header = column.Title, DisplayMemberBinding = binding });
}
}


Direct after this I try to add the rows:

foreach (dynamic item in myItems)
{
this.listView.Items.Add(item);
}


I tryed to modify this solution for an other purpose. This solution works very well, if I only want to add values of the type
string
, but now I also want to display an
image
in the gridview, but if I add one to my gridview, it shows me just:


"System.Windows.Controls.Image"


Now I want to know, if I can modify my code so as I can display any type (or at least
images
and
strings
) in a gridview or do I have to use a completly new way and would be the way?

EDIT: In the previous approaches, it was said, that I need to create a new
DataTemplate
to show an image, but none of the solutions(Solution 1, Solution 2) I found is working for me.

Answer

The best way is to define DataTemplate for the Icon column in resources, and then to load it when creating column for the icon. I've modified your code to show the approach.

XAML

<Window x:Class="ListViewIcon.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:ListViewIcon"
        mc:Ignorable="d"
        Title="MainWindow" Height="350" Width="525">
    <Window.Resources>
        <ResourceDictionary>
            <DataTemplate x:Key="iconTemplate">
                <Image Source="{Binding Icon}"
                   Width="64"
                   Height="64"/>
            </DataTemplate>
        </ResourceDictionary>
    </Window.Resources>
    <Grid>
        <ListView x:Name="myListView"></ListView>

    </Grid>
</Window>

C#

public class Column
{
    public string Title { get; set; }
    public string SourceField { get; set; }
}

public partial class MainWindow : Window
{
    private BitmapImage LoadImage()
    {
        var img = new BitmapImage();
        img.BeginInit();
        img.UriSource = new Uri(@"D:\image.png", UriKind.Absolute);
        img.CacheOption = BitmapCacheOption.OnLoad;
        img.EndInit();

        return img;
    }

    public MainWindow()
    {
        InitializeComponent();

        GridView gridView = new GridView();
        this.myListView.View = gridView;

        List<dynamic> myItems = new List<dynamic>();
        dynamic myItem;
        IDictionary<string, object> myItemValues;

        var image = LoadImage();

        // Populate the objects with dynamic columns
        for (var i = 0; i < 100; i++)
        {
            myItem = new System.Dynamic.ExpandoObject();

            foreach (string column in new string[] { "Id", "Name", "Something" })
            {
                myItemValues = (IDictionary<string, object>)myItem;
                myItemValues[column] = "My value for " + column + " - " + i;
            }

            myItem.Icon = image;

            myItems.Add(myItem);
        }

        // Assuming that all objects have same columns - using first item to determine the columns
        List<Column> columns = new List<Column>();

        myItemValues = (IDictionary<string, object>)myItems[0];

        // Key is the column, value is the value
        foreach (var pair in myItemValues)
        {
            Column column = new Column();

            column.Title = pair.Key;
            column.SourceField = pair.Key;

            columns.Add(column);
        }

        // Add the column definitions to the list view
        gridView.Columns.Clear();

        foreach (var column in columns)
        {

            if (column.SourceField == "Icon")
            {
                gridView.Columns.Add(new GridViewColumn
                {
                    Header = column.Title,
                    CellTemplate = FindResource("iconTemplate") as DataTemplate
                });
            }
            else
            {
                var binding = new Binding(column.SourceField);
                gridView.Columns.Add(new GridViewColumn { Header = column.Title, DisplayMemberBinding = binding });
            }


        }

        // Add all items to the list
        foreach (dynamic item in myItems)
        {
            this.myListView.Items.Add(item);
        }

    }
}

Results

enter image description here

Comments