2

I've to pivot information data from a query, and show images based on value read from the underlying database.

Let's say I have this data out of my query:

Identifiant|ProcessId|AlarmLevel
  BOUDA25  |   100   |    1
  BOUDA25  |   110   |    1
  BOUDA25  |   130   |    1
  BOUDA25  |   205   |    2
  BOUDA25  |   210   |    2

I now want to make the following WPF DataGrid display the actual images represented by images/circle_orange.ico, etc. Programmatically Generated

So far my code resembles this:

private void PopulateGrid(IEnumerable<AlarmeViewModel> alarmes) {        
    // Used to pivot the information data
    var table=new DataTable();

    // Generates the columns based on rows
    table.Columns.Add("Identifiant");
    table.Columns.Add("=>");

    alarmes.ForEach(a => a.Processes.ForEach(pid => table.Columns.Add(columnName:pid, type typeof(string))));

    // Generates the rows
    var images = new string[] {
        "images/circle_grey.ico",
        "images/circle_orange.ico",
        "images/circle_yellow.ico",
        "images/circle_red.ico",
        "images/circle_green.ico"        
    };

    alarmes.ForEach(a => {
        var row = table.NewRow();
        row[0] = a.Identifiant

        for(int i=0; i<a.Niveaux.Count; row[a.Processes[i]]=images[a.AlarmLevel[1]], i++);

        table.Rows.Add(row);
    });

    // Refreshes the DataGrid content
    alarmDataGrid.BeginInit();
    alarm.DataGrid.ItemsSource=table.DefaultView;
    alarmDataGrid.EndInit();
}

Now I'm stuck since three days to make those image display through an ImageSource binding.

I tried to let the DataGrid autogenerate the columns by itself, and I also tried by adding them in the code behind from the accepted answer of this question:

And this one also:

And I just can't get it. I know I'm close, but still missing the obvious, I guess.

Will Marcouiller
  • 23,773
  • 22
  • 96
  • 162
  • 1
    one more similar question: https://stackoverflow.com/q/40358111/1506454 – ASh Dec 17 '19 at 18:22
  • @ASh This is very helpful! Actually just need to figure out from that how I can make my converter read the alarm level from the rows so it assigns the correct image. Way simpler than what I had first. I think I'll update my code sample to reflect the changes. – Will Marcouiller Dec 17 '19 at 23:01

1 Answers1

1

You could handle the AutoGeneratingColumn event and programmatically create a DataGridTemplateColumn that contains an Image element. Try this:

private void OnAutoGeneratingColumn(object sender, DataGridAutoGeneratingColumnEventArgs e)
{
    if (e.PropertyName != "Identifiant" && e.PropertyName != "=>")
    {
        FrameworkElementFactory image = new FrameworkElementFactory(typeof(Image));
        image.SetBinding(Image.SourceProperty, new Binding(e.PropertyName));

        e.Column = new DataGridTemplateColumn
        {
            CellTemplate = new DataTemplate() { VisualTree = image },
            Header = e.PropertyName
        };
    }
}
mm8
  • 163,881
  • 10
  • 57
  • 88
  • Do I need to do anything special with the image files or just letting them as Content/Copy Always is fine? Because I feed the relative path to the image file as my screenshot shows, and when I use the code sample provided, it won't display any image or value. Like the cell is empty. I got to deliver this feature by next Friday, and I've worked on it since last Sunday. Growing nervous... – Will Marcouiller Dec 18 '19 at 12:12
  • Besides, when using the IValueConverter from the XAML DataTemplate as a DataGrid.Resources, my converter gets called, but it doesn't seem to work as I expected, namely the object value parameter is the whole row in the form of a DataRowView, instead of just a cell value at time. So it's nearly impossible to work around. I'm really at a dead end now. Your help is greatly appreciated. – Will Marcouiller Dec 18 '19 at 12:17
  • How do you use the coverter? You shouldn't need one. – mm8 Dec 18 '19 at 12:19
  • I'm no longer using it with your approach. I went all the way to your solution, but there must be something I'm doing wrong because it won't display any image. Even after I copied and pasted your code directly into my AutoGeneratingColumn implementation. – Will Marcouiller Dec 18 '19 at 12:21
  • Have you confirmed that the `AutoGeneratingColumn` event handler is actually invoked? – mm8 Dec 18 '19 at 12:29
  • Ayup! It is. Just put a breakpoint into it to double verify though I was sure. – Will Marcouiller Dec 18 '19 at 12:41
  • Are you sure that the image paths are valid? Try with another path and image. – mm8 Dec 18 '19 at 12:42
  • Pretty sure, since I use the same images for other XAML pre-defined columns in the app and they display just fine. It's really just with the auto-generating columns I've an issue. I tried replacing `images/circle_grey.ico` by `icon_exit.png` and removing the `images/` from `circle_orange.ico`. I even tried restarting my computer in case VS has cached something or the like. Images are set as Content/Copy Always. Should I consider to set them as Resource/Do Not Copy? I'm lost here. Your guidance is appreciated. You bring hope! :D – Will Marcouiller Dec 18 '19 at 12:49
  • Both resources/do not copy and content should work. There is something else going on in your code. You should provide a minimal repo. – mm8 Dec 18 '19 at 12:55
  • With your email, I could actually grant you access to the app. I'm that desperate. :( Otherwise, I will create a simpler app and reproduce this section of code in it and create a minimal repo as suggested. Thx from the bottom of my heart for your help! – Will Marcouiller Dec 18 '19 at 13:01
  • Please do the latter: https://stackoverflow.com/help/minimal-reproducible-example – mm8 Dec 18 '19 at 13:03
  • I created a GitHub repository for this with a tiny app that reproduces the issue: https://github.com/WillMarcouiller/AutoGeneratingColumnWpf – Will Marcouiller Dec 18 '19 at 14:59
  • 1
    @WillMarcouiller: As I expected, your image paths are invalid. Replace "images" with "../images" and it works, e.g.: `"../images/circle_grey.ico"`. – mm8 Dec 18 '19 at 15:23
  • Hell yeah! But why was the path incorrect? I mean, when deployed, there's an Images folder created at same level as the executable file. Hopefully it'll work when deployed. Do you have a clue as to how to resize the image, for the icon to be smaller in the grid rather than just resize the actual images? – Will Marcouiller Dec 18 '19 at 15:43
  • The path is relative to the `UserControl` which is located in the `UserControls` folder. You may want to read up on [pack URIs](https://learn.microsoft.com/en-us/dotnet/framework/wpf/app-development/pack-uris-in-wpf). They let you identify resources using paths relative to the root of the assembly. – mm8 Dec 18 '19 at 15:45
  • 1
    You definitely made my day! My sincerest thanks for your support! +1 and accepted answer. :) – Will Marcouiller Dec 18 '19 at 15:51