Posts tagged ‘DataGrid’

How to disable row selection in a WPF DataGrid?

Disabling row selection in the WPF DataGrid included in .NET Framework 4 is not really easy. It is extremely difficult to do, unless you have the right tools and know exactly how to do it.

But all the difficulty is in figuring out how to do it. Once you know how to do it, the steps are quite easy to perform.

First, you basically have to use a copy of the default DataGrid style.  However, the easiest way to get a copy of the default DataGrid style is using Expression Blend.

Step 1 – Create a copy of the DataGrid’s default style

I used Expression Blend and .NET 4 to do this first step. Visual Studio 2010 doesn’t have this feature.  However, you don’t need Expression Blend because you can just copy the default style right here from this post.

(This step is a replica of the steps I posted earlier here:
How to create a copy of a control’s default style?)

  1. Open Expression Blend.
  2. Create a new WPF project. (I just used a temp project as I am coding in Visual Studio.)
  3. Add a DataGrid to your MainWindow.xaml.
  4. Right-click on the DataGrid and choose Edit Template | Edit a Copy.
  5. On the Create Style Resource page, click the “New…” button near the bottom right, just to the right of the Resource dictionary option.
  6. In the New Item window, provide a name, such as ResourceDictionaryDataGridSelectDisabled.xaml.
  7. Click OK to create the file and to return the Create Style Resource page.
  8. Make sure Resource dictionary is selected (it should be) and click OK.

You have now created a copy of the DataGrid’s default style as a Resource Dictionary file.

Note: Now that you have the DataGrid’s default style in a file, you can copy it to the project you are really working on.  I am not going to walk you through this.

Step 2 – Edit the DataGrid Style

On line 66, there is an ItemsPresenter object.  Set IsHitTestVisible="False" on this line as shown below. This is the only edit I have done.

Note: Notice I did not add an x:Key so that it will become the default style for any object that has access to this resource dictionary.

<ResourceDictionary
	xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
	xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
	>
	<Style TargetType="{x:Type DataGrid}">
		<Setter Property="Background" Value="{DynamicResource {x:Static SystemColors.ControlBrushKey}}"/>
		<Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}"/>
		<Setter Property="BorderBrush" Value="#FF688CAF"/>
		<Setter Property="BorderThickness" Value="1"/>
		<Setter Property="RowDetailsVisibilityMode" Value="VisibleWhenSelected"/>
		<Setter Property="ScrollViewer.CanContentScroll" Value="true"/>
		<Setter Property="ScrollViewer.PanningMode" Value="Both"/>
		<Setter Property="Stylus.IsFlicksEnabled" Value="False"/>
		<Setter Property="Template">
			<Setter.Value>
				<ControlTemplate TargetType="{x:Type DataGrid}">
					<Border BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}"
						Background="{TemplateBinding Background}" Padding="{TemplateBinding Padding}" SnapsToDevicePixels="True">
						<ScrollViewer x:Name="DG_ScrollViewer" Focusable="false">
							<ScrollViewer.Template>
								<ControlTemplate TargetType="{x:Type ScrollViewer}">
									<Grid>
										<Grid.ColumnDefinitions>
											<ColumnDefinition Width="Auto"/>
											<ColumnDefinition Width="*"/>
											<ColumnDefinition Width="Auto"/>
										</Grid.ColumnDefinitions>
										<Grid.RowDefinitions>
											<RowDefinition Height="Auto"/>
											<RowDefinition Height="*"/>
											<RowDefinition Height="Auto"/>
										</Grid.RowDefinitions>
										<Button Command="{x:Static DataGrid.SelectAllCommand}" Focusable="false"
											Style="{DynamicResource {ComponentResourceKey ResourceId=DataGridSelectAllButtonStyle,
													TypeInTargetAssembly={x:Type DataGrid}}}"
											Visibility="{Binding HeadersVisibility, ConverterParameter={x:Static DataGridHeadersVisibility.All},
														 Converter={x:Static DataGrid.HeadersVisibilityConverter},
														 RelativeSource={RelativeSource AncestorType={x:Type DataGrid}}}"
											Width="{Binding CellsPanelHorizontalOffset,
													RelativeSource={RelativeSource AncestorType={x:Type DataGrid}}}"/>
										<DataGridColumnHeadersPresenter x:Name="PART_ColumnHeadersPresenter" Grid.Column="1"
											Visibility="{Binding HeadersVisibility, ConverterParameter={x:Static DataGridHeadersVisibility.Column},
														 Converter={x:Static DataGrid.HeadersVisibilityConverter},
														 RelativeSource={RelativeSource AncestorType={x:Type DataGrid}}}"/>
										<ScrollContentPresenter x:Name="PART_ScrollContentPresenter"
											CanContentScroll="{TemplateBinding CanContentScroll}" Grid.ColumnSpan="2" Grid.Row="1"/>
										<ScrollBar x:Name="PART_VerticalScrollBar" Grid.Column="2" Maximum="{TemplateBinding ScrollableHeight}"
											Orientation="Vertical" Grid.Row="1"
											Visibility="{TemplateBinding ComputedVerticalScrollBarVisibility}"
											Value="{Binding VerticalOffset, Mode=OneWay, RelativeSource={RelativeSource TemplatedParent}}"
											ViewportSize="{TemplateBinding ViewportHeight}"/>
										<Grid Grid.Column="1" Grid.Row="2">
											<Grid.ColumnDefinitions>
												<ColumnDefinition Width="{Binding NonFrozenColumnsViewportHorizontalOffset,
																 RelativeSource={RelativeSource AncestorType={x:Type DataGrid}}}"/>
												<ColumnDefinition Width="*"/>
											</Grid.ColumnDefinitions>
											<ScrollBar x:Name="PART_HorizontalScrollBar" Grid.Column="1" Maximum="{TemplateBinding ScrollableWidth}"
												Orientation="Horizontal" Visibility="{TemplateBinding ComputedHorizontalScrollBarVisibility}"
												Value="{Binding HorizontalOffset, Mode=OneWay, RelativeSource={RelativeSource TemplatedParent}}"
												ViewportSize="{TemplateBinding ViewportWidth}"/>
										</Grid>
									</Grid>
								</ControlTemplate>
							</ScrollViewer.Template>
							<ItemsPresenter SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" IsHitTestVisible="False"/>
						</ScrollViewer>
					</Border>
				</ControlTemplate>
			</Setter.Value>
		</Setter>
		<Style.Triggers>
			<Trigger Property="IsGrouping" Value="true">
				<Setter Property="ScrollViewer.CanContentScroll" Value="false"/>
			</Trigger>
		</Style.Triggers>
	</Style>
	<!-- Resource dictionary entries should be defined here. -->
</ResourceDictionary>

Step 3 – Configure the DataGrid to use the new style

Now that you have your new style in a resource dictionary (and I assume you have already added the file you created in Step 1 to your project), you can add the ResourceDictionary to the DataGrid’s object under DataGrid.Resources as shown.

<DataGrid ... />
    <DataGrid.Resources>
        <ResourceDictionary>
            <ResourceDictionary.MergedDictionaries>
                <ResourceDictionary Source="ResourceDictionaryDataGridSelectDisabled.xaml" />
            </ResourceDictionary.MergedDictionaries>
        </ResourceDictionary>
    </DataGrid.Resources>
</DataGrid>

I hope this helps you have some more success with a DataGrid from day one as it took me some time to get this working.

How to add a dynamic image and/or a dynamic button to a DataGrid row using a DataGridTemplateColumn and a DataTemplateSelector?

How to add a dynamic image and/or a dynamic button to a row using WPFToolKit DataGrid and DataGridTemplateColumns?

To start, I have a WPF project in Visual Studio 2008. I have installed the WPFToolKit and have added a reference to it in my project.

Often you want to display a DataGrid, but you don’t want to simply display it as is, you want to be able to enhance it and add functionality to it, such as adding an image to the start of each row or adding a button on each row.

Ok, so I have a table created using a DataTable that looks as follows:

IntVal StrVal
0 normal
1 warning
2 error

I am passing this to a WFPToolKit DataGrid.

As I pass this to a Datagrid I want to add two columns:

  1. I want to add an image that is different if it is normal, warning, or error.
  2. I want to add a button only if it is warning or error.

So the visual would look as follows:

Image IntVal StrVal Action
0 normal
1 warning
2 error

Step 1. Install prerequisites: Install Visual Studio 2008, and download and install the WPFToolkit.

You probably already have this done, and there are no steps for provided for these.

Step 2. Create a new WPF project in Visual studio 2008 and design the WPF interface

So once my project was created and the reference to WPFToolKit added, I then changed the XAML on my default Window1 class.

  1. I needed to add a reference to the toolkit here as well.
  2. I needed to add resources for my button.
  3. I needed to add three separate resources for my images.
  4. I needed to add a DataGrid.

Window1.xaml

<window x:Class="DataGridAddButtonAndImageColumns.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:wpftk="http://schemas.microsoft.com/wpf/2008/toolkit"
    Title="Window1" Height="300" Width="300">
    <window.Resources>
        <dataTemplate x:Key="FixThisTemplate">
            <button Name="mButtonFixThis" Click="ButtonFixThis_Click">Fix This</button>
        </dataTemplate>
        <dataTemplate x:Key="NormalTemplate">
        </dataTemplate>
        <dataTemplate x:Key="StatusTemplateNormal" x:Name="mNormalImage">
            <image Width="16" Height="16" Source="C:\Users\jbarneck\Documents\QuickTests\DataGridAddButtonAndImageColumns\DataGridAddButtonAndImageColumns\bin\Debug\Normal.png" />
        </dataTemplate>
        <dataTemplate x:Key="StatusTemplateWarning" x:Name="mWarningImage">
            <image Width="16" Height="16" Source="C:\Users\jbarneck\Documents\QuickTests\DataGridAddButtonAndImageColumns\DataGridAddButtonAndImageColumns\bin\Debug\Warning.png" />
        </dataTemplate>
        <dataTemplate x:Key="StatusTemplateError" x:Name="mErrorImage">
            <image Width="16" Height="16" Source="C:\Users\jbarneck\Documents\QuickTests\DataGridAddButtonAndImageColumns\DataGridAddButtonAndImageColumns\bin\Debug\Error.png" />
        </dataTemplate>
    </window.Resources>
    <grid>
        <wpftk:DataGrid Name="mDataGrid" ItemsSource="{Binding}" CanUserAddRows="False" IsReadOnly="True"></wpftk:DataGrid>
    </grid>
</window>

Step 3 – Create the data

The data can come from anywhere but for this basic example, I am just statically creating a DataTable in the Constructor.  I also added a property for the DataTable and the DataTable.DefaultView.

Data.cs

using System.Data;

namespace DataGridAddButtonAndImageColumns
{
    public class Data
    {
        #region Member Variables
        private DataTable mTable;
        #endregion

        #region Constructors

        /*
		 * The default constructor
 		 */
        public Data()
        {
            mTable = new DataTable();
            mTable.Columns.Add("IntVal", typeof(int));
            mTable.Columns.Add("StrVal", typeof(string));
            DataRow row0 = mTable.NewRow();
            row0["IntVal"] = 0;
            row0["StrVal"] = "normal";
            mTable.Rows.Add(row0);

            DataRow row1 = mTable.NewRow();
            row1["IntVal"] = 1;
            row1["StrVal"] = "warning";
            mTable.Rows.Add(row1);

            DataRow row2 = mTable.NewRow();
            row2["IntVal"] = 2;
            row2["StrVal"] = "error";
            mTable.Rows.Add(row2);

        }

        #endregion

        #region Properties
        public DataTable Table
        {
            get { return mTable; }
            set { mTable = value; }
        }

        public DataView View
        {
            get { return mTable.DefaultView; }
        }
        #endregion

        #region Functions
        #endregion

        #region Enums
        #endregion
    }
}

Step 4 – Create a ViewModel that implements INotifyPropertyChanged.

So creating a ViewModel is not exactly required but there really is benefit to the Model-View-ViewModel design pattern, so I will attempt to follow it even though this is a simple example application.

  1. I created a new object called DataViewModel.
  2. I implemented the INotifyPropertyChanged interface (though for this small application it isn’t used, I don’t want to leave it out cause you might need it for your application.)
  3. I changed the constructor to take the Data object I designed in the previous step.
  4. I expose the Table and the Table’s view as properties.

DataViewModel.cs

using System;
using System.ComponentModel;
using System.Data;

namespace DataGridAddButtonAndImageColumns
{
    public class DataViewModel : INotifyPropertyChanged
    {
        #region Member Variables
        readonly Data mData;
        #endregion

        #region Constructors

        /*
		 * The default constructor
 		 */
        public DataViewModel(Data inData)
        {
            mData = inData;
        }

        #endregion

        #region Properties
        public DataView View
        {
            get { return mData.View; }
        }

        public DataTable Table
        {
            get { return mData.Table; }
        }
        #endregion

        #region Functions

        #endregion

        #region Enums
        #endregion

        #region INotifyPropertyChanged Members

        public event PropertyChangedEventHandler PropertyChanged;

        protected virtual void OnPropertyChanged(string propertyName)
        {
            if (this.PropertyChanged != null)
                this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }

        #endregion
    }
}

Step 5 – Add code to pass the DataTable to the DataGrid

So in the Window1.xaml.cs file, I create a new DataViewModel object and pass it a new Data object.  I then assign the DataTable to the DataGrid’s DataContext object. My class now looks as follows.

Window1.xaml.cs

using System.Windows;
using System.Windows.Controls;

namespace DataGridAddButtonAndImageColumns
{
    /// <summary>
    /// Interaction logic for Window1.xaml
    /// </summary>
    public partial class Window1 : Window
    {

        #region Member Variables
        #endregion

        #region Contructor
        public Window1()
        {
            InitializeComponent();
            DataViewModel model = new DataViewModel(new Data());

            // It is ok to pass either the DataTable or the DataView
            // so both lines below work, however I am only using one:
            //
            // mDataGrid.DataContext = model.View;
            // mDataGrid.DataContext = model.Table;

            mDataGrid.DataContext = model.Table;
        }
        #endregion

        #region Functions
        private void ButtonFixThis_Click(object sender, RoutedEventArgs e)
        {
            // Do something here
        }
        #endregion

        #region Properties
        #endregion
    }
}

Now I can compile and run see my simple DataGrid.

IntVal StrVal
0 normal
1 warning
2 error

Step 6 – Create the DataTemplateSelectors

I am going to use two DataTemplateSelector and I want them to share a base class, so first, I am going to create a base class for them.

  1. I inherit DataTemplateSelector.
  2. I add a function to find the parent Window1 object.

BaseDataTemplateSelector.cs

using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;

namespace DataGridAddButtonAndImageColumns
{
    public class BaseDataTemplateSelector : DataTemplateSelector
    {
        #region Member Variables
        #endregion

        #region Constructors
        /*
		 * The default constructor
 		 */
        public BaseDataTemplateSelector()
        {
        }
        #endregion

        #region Properties
        #endregion

        #region Functions
        protected Window1 GetWindow1(DependencyObject inContainer)
        {
            DependencyObject c = inContainer;
            while (true)
            {
                DependencyObject p = VisualTreeHelper.GetParent(c);

                if (c is Window1)
                {
                    //mSectionControl = c;
                    return c as Window1;
                }
                else
                {
                    c = p;
                }
            }
        }
        #endregion
    }
}

Now I create an ActionDataTemplateSelector and a StatusImageDataTemplateSelector.

The ActionDataTemplateSelector will overload the SelectTemplate function and correctly select the Fix button resource if the status is warning or error.

ActionDataTemplateSelector.cs

using System.Data;
using System.Windows;

namespace DataGridAddButtonAndImageColumns
{
    public class ActionDataTemplateSelector : BaseDataTemplateSelector
    {
        #region Constructors
        /*
		 * The default constructor
 		 */
        public ActionDataTemplateSelector()
        {
        }
        #endregion

        #region Functions
        public override DataTemplate SelectTemplate(object inItem, DependencyObject inContainer)
        {
            DataRowView row = inItem as DataRowView;

            if (row != null)
            {
                Window1 w = GetWindow1(inContainer);
                if (row.DataView.Table.Columns.Contains("IntVal"))
                {
                    if ((int)row["IntVal"] > 0)
                    {
                        return (DataTemplate)w.FindResource("FixThisTemplate");
                    }
                }
                return (DataTemplate)w.FindResource("NormalTemplate");
            }
            return null;
        }
        #endregion
    }
}

The StatusImageDataTemplateSelector also overloads the SelectTempate function and selects the correct image for the status.

StatusImageDataTemplateSelector .cs

using System.Data;
using System.Windows;

namespace DataGridAddButtonAndImageColumns
{
    public class StatusImageDataTemplateSelector : BaseDataTemplateSelector
    {
        #region Constructors

        /*
		 * The default constructor
 		 */
        public StatusImageDataTemplateSelector()
        {
        }
        #endregion

        #region Functions
        public override DataTemplate SelectTemplate(object inItem, DependencyObject inContainer)
        {
            DataRowView row = inItem as DataRowView;

            if (row != null)
            {
                if (row.DataView.Table.Columns.Contains("IntVal"))
                {
                    Window1 w = GetWindow1(inContainer);
                    int status = (int)row["IntVal"];
                    if (status == 0)
                    {
                        return (DataTemplate)w.FindResource("StatusTemplateNormal");
                    }
                    if (status == 1)
                    {
                        return (DataTemplate)w.FindResource("StatusTemplateWarning");
                    }
                    if (status == 2)
                    {
                        return (DataTemplate)w.FindResource("StatusTemplateError");
                    }
                }
            }
            return null;
        }
        #endregion
    }
}

Step 7 – Create functions that add the new columns and have the constructor call each function.

Each function must:

  1. Create a new DataGridTemplateColumn.
  2. Assign a string for the Header.
  3. Create a new DataTemplateSelector and assign it to the DataGridTemplateColumn’s CellTemplateSelector.
  4. Add the new DataGridTemplateColumn to the DataGrid.
        public void CreateActionButtonColumn()
        {
            DataGridTemplateColumn actionColumn = new DataGridTemplateColumn { CanUserReorder = false, Width = 85, CanUserSort = true };
            actionColumn.Header = "Action";
            actionColumn.CellTemplateSelector = new ActionDataTemplateSelector();
            mDataGrid.Columns.Add(actionColumn);
        }

        public void CreateStatusColumnWithImages()
        {
            DataGridTemplateColumn statusImageColumn = new DataGridTemplateColumn { CanUserReorder = false, Width = 85, CanUserSort = false };;
            statusImageColumn.Header = "Image";
            statusImageColumn.CellTemplateSelector = new StatusImageDataTemplateSelector();
            mDataGrid.Columns.Insert(0, statusImageColumn);
        }

Don’t forget to call the functions in the constructor.

        public Window1()
        {
            InitializeComponent();
            DataViewModel model = new DataViewModel(new Data());

            // It is ok to pass either the DataTable or the DataView
            // so both lines below work, however I am only using one:
            //
            // mDataGrid.DataContext = model.View;
            // mDataGrid.DataContext = model.Table;

            mDataGrid.DataContext = model.Table;
            CreateActionButtonColumn();
            CreateStatusColumnWithImages();
        }

Ok, so now you are finished. This should be working for you if you compile and run the program.

Image IntVal StrVal Action
0 normal
1 warning
2 error

Options for handling the images without using a static path

The images were called statically in the above example, however, that will be problematic in actual implementation as each program is installed in a different location and the install location can usually be chosen by a user. You have two options to resolve this, and I will show you how to do both:

  1. Embedding your images
  2. Using image files located in a relative path

Either option work.  The second option makes branding a little easier as code doesn’t have to be recompiled with new images to change the images, because the image files can simply be replaced.

Embedding your images
So you can embed your images as resources and use the embedded resources instead. To embed them, do this:

  1. In Visual Studio under your project, create a folder called Images.
  2. Copy your images into that folder.
  3. In the XAML, change each of the image resource lines as shown
            <image Width="16" Height="16" Source="Images\Warning.png" />

Using image files located in a relative path
I decided to NOT embed my images but instead solve this by using a relative path. My preference is for the images to come from actual files in an images directory that is relative to the directory from which the executable is launched:

\MyFolder\
\MyFolder\program.exe
\MyFolder\Images\
\MyFolder\Images\Normal.png
\MyFolder\Images\Warning.png
\MyFolder\Images\Error.png

So in order to use relative paths, I found that I could create another object that inherits IValueConverter.

Here is what I had to do to create this:

  1. Create a new class called PathConverter.
  2. Make it inherit IValueConverter
  3. Implement the IValueConverter interface.
  4. Add code to the Convert function.
  5. Cast the “value” parameter to a DataRowView as each DataRow will be the calling object that is passed in as “value”.
  6. Get the relative path using System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location).
  7. Get the status value from the DataRowView and add a couple of if statements that return the relative + the image file path.
using System;
using System.Data;
using System.Globalization;
using System.Windows.Data;

namespace DataGridAddButtonAndImageColumns
{
    public class PathConverter : IValueConverter
    {
        #region Constructors
        /*
		 * The default constructor
 		 */
        public PathConverter()
        {
        }
        #endregion

        #region IValueConverter Members
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            DataRowView row = value as DataRowView;
            if (row != null)
            {
                if (row.DataView.Table.Columns.Contains("IntVal"))
                {
                    String workingDirectory = System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location);
                    int status = (int)row["IntVal"];
                    if (status == 0)
                    {
                        return workingDirectory + @"Images\Normal.png";
                    }
                    if (status == 1)
                    {
                        return workingDirectory + @"Images\Warning.png";
                    }
                    if (status == 2)
                    {
                        return workingDirectory + @"Images\Error.png";
                    }
                }
            }
            return null;
        }

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            throw new System.NotImplementedException();
        }
        #endregion
    }
}

Ok, I am not done yet.  I now needed to edit the XAML again.  here is what we do to the XAML:

  1. I add an xmlns reference to load the local namespace.
  2. I add in the windows resources and instance of the PathConverter.
  3. I change the Image Source value to: Source=”{Binding Converter={StaticResource ImagePathConverter}}”
<window x:Class="DataGridAddButtonAndImageColumns.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:wpftk="http://schemas.microsoft.com/wpf/2008/toolkit"
    xmlns:local="clr-namespace:DataGridAddButtonAndImageColumns"
    Title="Window1" Height="300" Width="300">
    <window.Resources>
        <local:PathConverter x:Key="ImagePathConverter" />
        <dataTemplate x:Key="FixThisTemplate">
            <button Name="mButtonFixThis" Click="ButtonFixThis_Click">Fix This</button>
        </dataTemplate>
        <dataTemplate x:Key="NormalTemplate">
        </dataTemplate>
        <dataTemplate x:Key="StatusTemplateNormal" x:Name="mNormalImage">
            <image Width="16" Height="16" Margin="3,0" Source="{Binding Converter={StaticResource ImagePathConverter}}" />
            <!--<image Width="16" Height="16" Source="Images\Normal.png" />--><!-- Embedded -->
        </dataTemplate>
        <dataTemplate x:Key="StatusTemplateWarning" x:Name="mWarningImage">
            <image Width="16" Height="16" Margin="3,0" Source="{Binding Converter={StaticResource ImagePathConverter}}" />
            <!--<image Width="16" Height="16" Source="Images\Warning.png" />--><!-- Embedded -->
        </dataTemplate>
        <dataTemplate x:Key="StatusTemplateError" x:Name="mErrorImage">
            <image Width="16" Height="16" Margin="3,0" Source="{Binding Converter={StaticResource ImagePathConverter}}" />
            <!--<image Width="16" Height="16" Source="Images\Error.png" />--><!-- Embedded -->
        </dataTemplate>
    </window.Resources>
    <grid>
        <wpftk:DataGrid Name="mDataGrid" ItemsSource="{Binding}" CanUserAddRows="False" IsReadOnly="True"></wpftk:DataGrid>
    </grid>
</window>

Ok, now we should be done.

Make sure to create the Images folder and add the images in the location where you exectuable runs. You may have to add the images folder to both the debug and release directories or otherwise resolve this, else you will get an exception when the images are not found.

Note: I wrote an improved version of this article and published it here:
http://www.codeproject.com/KB/WPF/AddImageToColumnDynamicly.aspx


Copyright ® Rhyous.com – Linking to this page is allowed without permission and as many as ten lines of this page can be used along with this link. Any other use of this page is allowed only by permission of Rhyous.com.