Hi,
I am using a DataGrid (from Microsoft.Windows.Controls.DataGrid) to display items on and on this DataGrid I use a custom Column which extends DataGridBoundColumn. I have bound an ObservableCollection to the ItemSource of the DataGrid. Conversation is one of my own custom datatypes which a (among other things) has a boolean called active. I bound this boolean to the DataGrid as follows:
DataGridActiveImageColumn test = new DataGridActiveImageColumn();
test.Header = "Active";
Binding binding1 = new Binding("Active");
test.Binding = binding1;
ConversationsDataGrid.Columns.Add(test);
My custom DataGridBoundColumn DataGridActiveImageColumn overrides the GenerateElement method to let it return an Image depending on whether the conversation it is called for is active or not. The code for this is:
namespace Microsoft.Windows.Controls
{
class DataGridActiveImageColumn : DataGridBoundColumn
{
protected override FrameworkElement GenerateElement(DataGridCell cell, object dataItem)
{
// Create Image Element
Image myImage = new Image();
myImage.Width = 10;
bool active=false;
if (dataItem is Conversation)
{
Conversation c = (Conversation)dataItem;
active = c.Active;
}
BitmapImage myBitmapImage = new BitmapImage();
// BitmapImage.UriSource must be in a BeginInit/EndInit block
myBitmapImage.BeginInit();
if (active)
{
myBitmapImage.UriSource = new Uri(@"images\active.png", UriKind.Relative);
}
else
{
myBitmapImage.UriSource = new Uri(@"images\inactive.png", UriKind.Relative);
}
// To save significant application memory, set the DecodePixelWidth or
// DecodePixelHeight of the BitmapImage value of the image source to the desired
// height or width of the rendered image. If you don't do this, the application will
// cache the image as though it were rendered as its normal size rather then just
// the size that is displayed.
// Note: In order to preserve aspect ratio, set DecodePixelWidth
// or DecodePixelHeight but not both.
myBitmapImage.DecodePixelWidth = 10;
myBitmapImage.EndInit();
myImage.Source = myBitmapImage;
return myImage;
}
protected override FrameworkElement GenerateEditingElement(DataGridCell cell, object dataItem)
{
throw new NotImplementedException();
}
}
}
All this works as expected, and when during the running of the program the active boolean of conversations changes, this is automatically updated in the DataGrid.
However: When there are more entries on the DataGrid then fit at any one time (and vertical scrollbars are added) the behavior with respect to the column for all the conversations is strange. The conversations that are initially loaded are correct, but when I use the scrollbar of the DataGrid conversations that enter the view seems to have a random status (although more inactive than active ones, which corresponds to the actual ratio). When I scroll back up, the active images of the Conversations initially shown (before scrolling) are not correct anymore as well.
When I replace my custom DataGridBoundColumn class with (for instance) DataGridCheckBoxColumn it works as intended so my extension of the DataGridBoundColumn class must be incomplete. Personally I think it has something to do with the following:
From the MSDN page on the GenerateElement method (http://msdn.microsoft.com/en-us/library/system.windows.controls.datagridcolumn.generateelement%28VS.95%29.aspx):
Return Value
Type: System.Windows. FrameworkElement
A new, read-only element that is bound to the column's Binding property value.
I do return a new element (the image) but it is not bound to anything. I am not quite sure what I should do. Should I bind the Image to something? To what exactly? And why? (I have been experimenting, but was unsuccessful thus far, hence this post)
Thanks in advance.