How to add a DataGridTemplateColumn using a button to a WPFToolkit DataGrid that is bound to a DataTable?

Ok, so here is my goal. I have a DataGrid that is going to be bound to a DataTable.

I want to add a DataGridTemplateColumn when the DataContext changes.

For each row, I have an value that is either normal, warning, or error. If normal, I don’t want a button on the column at all. If error or warning, I want a button.

So the DataTable looks something like this but in my larger app (this is a minimal example) the data is dynamic in that it can contain different numbers of rows, difference column names, etc. So a static View and static binding isn’t going to work.

Field Value Compare
a 1 1
b 2 3
c 3 5
d 4 4

So, the idea is to get the WPFToolkit’s DataGrid view to look like this.  If the numbers differ by 1, it is a warning.  If the numbers differ by 2 it is an error.

Field Value Compare Action
a 1 1 Normal
b 2 3
c 3 5
d 4 4 Normal

So how do I do this with a WPFToolKit DataGrid that is bound to a Table?

Hopefully, I will figure this out:
Windows 7 64 bit
Visual Studio 2008 SP1
.NET 3.5
WPToolKit

I don’t have it working yet…

Step 1 – Create a new WPF Application project in Visual Studio

Step 2 – Add WPFToolKit as a Reference

  1. Right-click on project and choose Add Reference.
  2. Under the first tab called .NET select WPFToolkit.

Step 3 – Create the View

  1. Open the Window1.xaml.
    <Window x:Class="DataGridAddButtonColumnTest.Window1"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:wpftk="clr-namespace:Microsoft.Windows.Controls;assembly=WPFToolkit"
        Title="Window1" Height="300" Width="300" Loaded="Window_Loaded">
        <Grid>
            <wpftk:DataGrid ItemsSource="{Binding}" Name="mDataGrid" CanUserAddRows="False" IsReadOnly="True" DataContextChanged="mDataGrid_DataContextChanged"></wpftk:DataGrid>
        </Grid>
    </Window>
    
    

Step 4 – Create the Data

  1. Create a TestData class.
    using System;
    using System.Collections.Generic;
    using System.Data;
    using System.Linq;
    using System.Text;
    
    namespace DataGridAddButtonColumnTest
    {
        public class TestData
        {
            #region Member Variables
            DataTable mTable;
            #endregion
    
            #region Constructors
    
    		 /*
    		 * The default constructor
     		 */
            public TestData()
            {
                mTable = MakeSampleDataTable();
            }
    
            #endregion
    
            #region Properties
    
            public DataTable Table
            {
                get { return mTable; }
                set { mTable = value; }
            }
    
    
            #endregion
    
            #region Functions
            private DataTable MakeSampleDataTable()
            {
                DataTable table = new DataTable();
                table.Columns.Add("Field", typeof(string));
                table.Columns.Add("Value", typeof(int));
                table.Columns.Add("Compare", typeof(string));
                //table.Columns.Add("Action", typeof(string));
    
                table.Rows.Add("a", "1", "1");
                table.Rows.Add("b", "2", "3");
                table.Rows.Add("c", "3", "5");
                table.Rows.Add("d", "4", "1");
    
                // Or should I include the button data here or not?
                //DataTable table = new DataTable();
                //table.Columns.Add("Field", typeof(string));
                //table.Columns.Add("Value", typeof(int));
                //table.Columns.Add("Compare", typeof(string));
                //table.Columns.Add("Action", typeof(string));
    
                //table.Rows.Add("a", "1", "1", "Normal");
                //table.Rows.Add("b", "2", "3", "Warning");
                //table.Rows.Add("c", "3", "5", "Error");
                //table.Rows.Add("d", "4", "1", "Normal");
    
    
                return table;
            }
            #endregion
        }
    }
    [/source]
    </li>
    	<li>Create a TestDataModel Class
    
    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Data;
    using System.Linq;
    using System.Text;
    
    namespace DataGridAddButtonColumnTest
    {
        public class TestDataModel : INotifyPropertyChanged
        {
            #region Member Variables
            readonly TestData mTestData;
            public event PropertyChangedEventHandler PropertyChanged;
    
            #endregion
    
            #region Constructors
    
            /*
    		 * The default constructor
     		 */
            public TestDataModel(TestData inTestData)
            {
                mTestData = inTestData;
            }
    
            #endregion
    
            #region Properties
            public DataView View
            {
                get { return mTestData.Table.DefaultView; }
            }
    
            public TestData TestData
            {
                get { return mTestData; }
            }
    
            #endregion
    
            #region Functions
            #endregion
    
            #region Enums
            #endregion
    
            // Not sure if I even need to implement this for this test
            #region INotifyPropertyChanged Members
            protected virtual void OnPropertyChanged(PropertyChangedEventArgs e)
            {
    
                if (this.PropertyChanged != null)
    
                    this.PropertyChanged(this, e);
            }
    
            #endregion
        }
    }
    
  2. Add code to the Window1.xaml.cs file
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Controls.Primitives;
    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 Microsoft.Windows.Controls;
    
    namespace DataGridAddButtonColumnTest
    {
        /// <summary>
        /// Interaction logic for Window1.xaml
        /// </summary>
        public partial class Window1 : Window
        {
            public Window1()
            {
                InitializeComponent();
            }
    
            private void Window_Loaded(object sender, RoutedEventArgs e)
            {
                TestData td = new TestData();
                TestDataModel tdm = new TestDataModel(td);
                mDataGrid.DataContext = tdm.View;
                CreateActionButtonColumn();
            }
    
            private void mDataGrid_DataContextChanged(object sender, DependencyPropertyChangedEventArgs e)
            {
    
            }
    
            public void CreateActionButtonColumn()
            {
                Binding binding = new Binding("PropertyName") { Mode = BindingMode.TwoWay };
                DataGridTemplateColumn templateColumn = new DataGridTemplateColumn { CanUserReorder = false, Width = 85, CanUserSort = true };
                BindingOperations.SetBinding(templateColumn, DataGridColumn.HeaderProperty, binding);
                DataTemplate dataTemplate = new DataTemplate();
                FrameworkElementFactory tmpButton = new FrameworkElementFactory(typeof(Button));
                tmpButton.SetBinding(Button.NameProperty, binding);
                dataTemplate.VisualTree = tmpButton;
                templateColumn.CellTemplate = dataTemplate;
                mDataGrid.Columns.Add(templateColumn);
    
            }
    
        }
    }
    
    

Help! I don’t know how to finish this…

UPDATE 3/22/2010
I have an answer from http://social.msdn.microsoft.com/Forums/en-US/wpf/thread/6619249d-4353-4747-b3ad-d2748ac26d7b.

I will re-write this post with the correct details.

Leave a Reply

How to post code in comments?