Change image in WPF datagrid template column at runtime

Answered Change image in WPF datagrid template column at runtime

  • Thursday, August 16, 2012 8:36 AM
     
     

    Hi all,

    Hope you are having a good day :)

    Need your help with following...

    I have a WPF datagrid which I am populating by importing an excel file. As I am not sure about the heading of the excel sheet so I bound the whole sheet using OleDb.

    Now I have to loop through all these records, do some calculation and then send it to different tables. I figured out that its ideal to actually loop through the datatable, rather than the grid itself. All said and done. 

    The problem I am facing is, I inserted a template column with an image in it. All I want is to change that image on runtime to show to the user that the application is working on this record at the moment and then change it again if its successfully processed that record or otherwise.

    Any help would be greatly appreciated.

    Regards,

    Deepak


    Thanks & Regards, Deepak

All Replies

  • Thursday, August 16, 2012 10:29 AM
     
      Has Code

    You could take advantage of the MVVM pattern.

    You can create a ViewModel instance for each of your record. This ViewModel contains a property, that defines the state of the record.

    public class RecordViewModel : INotifyPropertyChanged
    {
        public MyState CurrentState
        {
            get { return mCurrentState; }
            set
            {
                if(value != mCurrentState)
                {
                    mCurrentState = value;
                    RaisePropertyChanged("CurrentState");
                }
            }
        }
    }
    Then in your column`s DataTemplate, you can insert a trigger for each state:
    <DataTemplate.Triggers>
    	<DataTrigger Binding="{Binding CurrentState}" Value="ValueA">
    		<Setter Property="Source" TargetName="mMyImage" Value="C:\valueA.bmp" />
    	</DataTrigger>
    
    	<DataTrigger Binding="{Binding CurrentState}" Value="ValueB">
            	<Setter Property="Source" TargetName="mMyImage" Value="C:\valueB.bmp" />
    	</DataTrigger>
    </DataTemplate.Triggers>
    Please note, that provided code is not complete and represents only the main parts of the idea.


  • Thursday, August 16, 2012 11:21 AM
     
     

    Hi Deepak,

    if you use for loop the changes wont update periodically as the value changes in the datagrid. You need to trigger that in some event or in a timing event. only then the changes will be updated periodically.

    Use visual tree helper to access the Image.


  • Thursday, August 16, 2012 11:27 AM
     
      Has Code

    Hi Deepak I worked out, it works fine as you need

    Xaml

    <Window x:Class="DataTableAnimation.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            Title="MainWindow" Height="350" Width="525">
        <Grid>
            <DataGrid x:Name="AdditionGrid" AutoGenerateColumns="False">
                <DataGrid.Columns>
                    <DataGridTemplateColumn Header="A">
                        <DataGridTemplateColumn.CellTemplate>
                            <DataTemplate>
                                <TextBlock Text="{Binding Path=A}"></TextBlock>
                            </DataTemplate>
                        </DataGridTemplateColumn.CellTemplate>
                    </DataGridTemplateColumn>
                    <DataGridTemplateColumn Header="B">
                        <DataGridTemplateColumn.CellTemplate>
                            <DataTemplate>
                                <TextBlock Text="{Binding Path=B}"></TextBlock>
                            </DataTemplate>
                        </DataGridTemplateColumn.CellTemplate>
                    </DataGridTemplateColumn>
                    <DataGridTemplateColumn Header="SUM(A+B)">
                        <DataGridTemplateColumn.CellTemplate>
                            <DataTemplate>
                                <TextBlock></TextBlock>
                            </DataTemplate>
                        </DataGridTemplateColumn.CellTemplate>
                    </DataGridTemplateColumn>
                    <DataGridTemplateColumn Header="Status">
                        <DataGridTemplateColumn.CellTemplate>
                            <DataTemplate>
                                <Image x:Name="Status" Height="50" Width="50" Source="/DataTableAnimation;component/Images/Error.png"></Image>
                            </DataTemplate>
                        </DataGridTemplateColumn.CellTemplate>
                    </DataGridTemplateColumn>
                </DataGrid.Columns>
            </DataGrid>
        </Grid>
    </Window>
    


    Code Behind C#:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Data;
    using System.Windows.Documents;
    using System.Windows.Input;
    using System.Windows.Media;
    using System.Windows.Media.Imaging;
    using System.Windows.Navigation;
    using System.Windows.Shapes;
    using System.Windows.Controls.Primitives;
    using System.Windows.Threading;
    
    namespace DataTableAnimation
    {
        public partial class MainWindow : Window
        {
            DispatcherTimer UpdateTimer = new DispatcherTimer();
            int rowCount = 0;
            List<addition> addList = new List<addition>();
            public MainWindow()
            {
                InitializeComponent();
                addList.Add(new addition { A = 80, B = 90 });
                addList.Add(new addition { A = 70, B = 90 });
                addList.Add(new addition { A = 60, B = 90 });
                addList.Add(new addition { A = 50, B = 90 });
                addList.Add(new addition { A = 10, B = 90 });
                addList.Add(new addition { A = 0, B = 90 });
                addList.Add(new addition { A = 20, B = 90 });
                AdditionGrid.ItemsSource = addList;
                UpdateTimer.Interval = new TimeSpan(0,0,0,1);
                UpdateTimer.Tick+=new EventHandler(UpdateTimer_Tick);
                UpdateTimer.Start();
            }
    
            public void UpdateTimer_Tick(object sender, EventArgs e)
            {
                if(rowCount<addList.Count)
                {
                DataGridCell ImageCell = GetCell(rowCount, 3);
                DataGridCell Acell = GetCell(rowCount, 0);
                DataGridCell Bcell = GetCell(rowCount, 1);
                DataGridCell Resultcell = GetCell(rowCount, 2);
                Image img = GetVisualChild<Image>(ImageCell);
                TextBlock ATextBlock = GetVisualChild<TextBlock>(Acell);
                TextBlock BTextBlock = GetVisualChild<TextBlock>(Bcell);
                TextBlock ResultTextBlock = GetVisualChild<TextBlock>(Resultcell);
                ResultTextBlock.Background = new SolidColorBrush(Colors.LightGreen);
                ResultTextBlock.Text = (int.Parse(ATextBlock.Text) + int.Parse(BTextBlock.Text)).ToString();
                img.Source = new BitmapImage(new Uri("pack://application:,,,/Images/Correct.png"));
                rowCount += 1;
                }
            }  
       
            public DataGridCell GetCell(int row, int column)
            {
                DataGridRow rowContainer = GetRow(row);
                if (rowContainer != null)
                {
                    DataGridCellsPresenter presenter = GetVisualChild<DataGridCellsPresenter>(rowContainer);
                    if (presenter == null)
                    {
                        AdditionGrid.ScrollIntoView(rowContainer, AdditionGrid.Columns[column]);
                        presenter = GetVisualChild<DataGridCellsPresenter>(rowContainer);
                    }
                    DataGridCell cell = (DataGridCell)presenter.ItemContainerGenerator.ContainerFromIndex(column);
                    return cell;
                }
                return null;
            }
    
            public DataGridRow GetRow(int index)
            {
                DataGridRow row = (DataGridRow)AdditionGrid.ItemContainerGenerator.ContainerFromIndex(index);
                if (row == null)
                {
                    AdditionGrid.UpdateLayout();
                    AdditionGrid.ScrollIntoView(AdditionGrid.Items[index]);
                    row = (DataGridRow)AdditionGrid.ItemContainerGenerator.ContainerFromIndex(index);
                }
                return row;
            }
    
            public static T GetVisualChild<T>(Visual parent) where T : Visual
            {
                T child = default(T);
                int numVisuals = VisualTreeHelper.GetChildrenCount(parent);
                for (int i = 0; i < numVisuals; i++)
                {
                    Visual v = (Visual)VisualTreeHelper.GetChild(parent, i);
                    child = v as T;
                    if (child == null)
                    {
                        child = GetVisualChild<T>(v);
                    }
                    if (child != null)
                    {
                        break;
                    }
                }
                return child;
            }
        }
    
        public class addition
        {
            public int A { get; set; }
            public int B { get; set; }
        }
    }
    

    Screen Shot of my Output:

    Happy Programming!!!

  • Thursday, August 16, 2012 11:50 AM
    Moderator
     
     Answered Has Code

    Here's a quick MSDN Sample from me:

      

    http://code.msdn.microsoft.com/Excel-Spredsheet-Processing-746e38b3

      

                xlApp = new Excel.Application();
                var path = System.IO.Path.Combine(System.AppDomain.CurrentDomain.BaseDirectory, "Model", "Book1.xls");
                xlWorkBook = xlApp.Workbooks.Open(path, 0, true, 5, "", "", true, Microsoft.Office.Interop.Excel.XlPlatform.xlWindows, "\t", false, false, 0, true, 1, 0);
                xlWorkSheet = (Excel.Worksheet)xlWorkBook.Worksheets.get_Item(1);
    
                range = xlWorkSheet.UsedRange;
    
                for (var rCnt = 2; rCnt <= range.Rows.Count; rCnt++)
                {
                        MyData.Add(new MyClass
                        {
                            UserID = (int)(range.Cells[rCnt, 1] as Excel.Range).Value2,
                            Name = (string)(range.Cells[rCnt, 2] as Excel.Range).Value2,
                            Type = (UserTypes)Enum.Parse(typeof(UserTypes),(string)(range.Cells[rCnt, 3] as Excel.Range).Value2)
                        });
                }
    
                xlWorkBook.Close(true, null, null);
                xlApp.Quit();

     

            <DataGrid ItemsSource="{Binding MyData}" AutoGenerateColumns="False" >
                <DataGrid.Columns>
                    <DataGridTextColumn Binding="{Binding UserID}"/>
                    <DataGridTextColumn Binding="{Binding Name}"/>
                    <DataGridTextColumn Binding="{Binding Type}"/>
                    <DataGridTemplateColumn>
                        <DataGridTemplateColumn.CellTemplate>
                            <DataTemplate>
                                <Image Height="20" Width="20" Source="{Binding JobStatus, Converter={StaticResource JobStatusConverter}}"/>
                            </DataTemplate>
                        </DataGridTemplateColumn.CellTemplate>
                    </DataGridTemplateColumn>
                </DataGrid.Columns>
            </DataGrid>

      

        private void StartProcessing()
        {
            foreach (var job in MyData)
            {
                job.JobStatus = JobStatuses.Working;
                Thread.Sleep(1000);
                job.JobStatus = (rand.Next(2) > 0) ? JobStatuses.Pass : JobStatuses.Fail;
            }
        }

     

    Regards,
    Pete


    #PEJL



  • Friday, August 17, 2012 3:08 PM
     
     
    Hi Ivan,

    Thanks for the suggestion. Can you please provide a link from where I can get an example of the same (DataTemplate triggers). 
    Found this link and tried to implement it but it didn't say much about the triggers. 

    Thanks for your help and time.

    cheers,
    Deepak.

    Thanks & Regards, Deepak

  • Friday, August 17, 2012 4:32 PM
     
     

    Hey XAML guy,

    Thanks for the link. I did tried that. All is done, no errors nothing. But it doesn;t show the image.. :(

    I might be missing something tiny and silly... 

    Can you give me your email id so that I can post my code rather than posting here in bits...

    Thanks for your help mate.

    cheers,

    Deepak


    Thanks & Regards, Deepak

  • Monday, August 20, 2012 5:18 AM
     
     
    Can you please provide a link from where I can get an example of the same (DataTemplate triggers). 

    You can read more about DataTriggers here: DataTrigger on MSDN.

    A DataTrigger simply setts specific properties on your elements and performs specific actions, when a specific property of your data item meets specific value.

  • Wednesday, August 22, 2012 9:48 AM
     
     

    Thanks XAMLGuy.. 

    I made it work.. 

    Cheers.. :)


    Thanks & Regards, Deepak

  • Wednesday, August 22, 2012 10:11 AM
     
     

    Hi all,

    Back again..
    I did solved my earlier problem, but there is another issue I am facing now. I was able to change the images in the grid, but it didn't show/change the images until it has processed all the rows in the grid. 

    What I want is that it change the image(as busy) when its working on that row and then change image again (as pass/fail) when its done working on that row before moving onto next row...

    Any help please..

    Thanks again. 

    Deepak


    Thanks & Regards, Deepak