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.
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
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With