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
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.
- Edited by Ivan Ruttkay-Nedecky Thursday, August 16, 2012 10:31 AM
-
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
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 AMModerator
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
- Edited by XAML guyMicrosoft Community Contributor, Moderator Thursday, August 16, 2012 11:52 AM added snippets
- Edited by XAML guyMicrosoft Community Contributor, Moderator Thursday, August 16, 2012 11:53 AM added snippets
- Marked As Answer by Catchbobbie Wednesday, August 22, 2012 9:48 AM
-
Friday, August 17, 2012 3:08 PMHi 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

