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
- Right-click on project and choose Add Reference.
- Under the first tab called .NET select WPFToolkit.
Step 3 – Create the View
- 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
- 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 [sourcecode language="csharp"] 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 } }
- 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.