Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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.

like image 921
daniel59 Avatar asked Feb 05 '16 12:02

daniel59


2 Answers

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

like image 105
Anton Danylov Avatar answered Nov 15 '22 09:11

Anton Danylov


I doubt that you'll be able to make your solution generic within the approach you are using. It works fine for text-based data types which have a valid ToString() representation, that suits you. For working with the complex datatype such as Images, you'll probably have to use Templates, as Shadowed metioned, where you'll have to setup different properties for each complex type. For example for image it could be the size and source, for the button - background color. As an option, you can create some kind of template factory and apply the CellTemplateSelector, which will provide you with the nesseccary templates, but it is, as you've said - it is a completely new way.

like image 32
Alex Avatar answered Nov 15 '22 09:11

Alex