Binding collection indexes to a WPF DataGrid at runtime
- by bearda
After trying to develop our own control to display a table of data we stumbled on the WPF toolkit DataGrid and thought we were saved. A couple hours later I'm scratching my head trying to figure out if it can do what we really want it to do. The DataGrid seems to be based on displaying various properties of a single object, where I think I need something that can display a collection's items,
I want to display a table of strings with a variable number of rows and a variable number of columns. Each row represents the state of a number of inputs at a given time. The number of samples may change, and the number of inputs may change at runtime. As a result, I can't create a custom object that represents a row with a property for each input. This makes the DataGrid binding more complicated, since I can't bind to a fixed property for each column.
I thought I found a workaround for this by binding to ".[" + channelIndex + ]" but it hasn't worked out quite the way I wanted. Right now I have a collection of a collection of strings that represents the two-dimensional array of strings. I'm using ObservableCollection so string change event notifications work, but I can use any collection type needed. It looked like everything was working great until I realized that every row was showing the same line of data. Binding in C# is not my strong suit, so I'm kind of lost on what's going wrong. Is what I'm trying to do overall even possible with the WPF Toolkit DataGrid?
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 Microsoft.Windows.Controls;
using System.ComponentModel;
using System.Collections;
using System.Collections.ObjectModel;
namespace WRE.NGDAS.UILayer
{
/// <summary>
/// Interaction logic for DataTableControl.xaml
/// </summary>
public partial class DataTableControl : UserControl
{
#region Constants
private const int lineHeight = 25;
#endregion
#region Type Definitions
private class TableChannelInfo
{
internal string ChannelName = string.Empty;
internal int Column = 0;
public override string ToString()
{
return ChannelName;
}
}
internal class NotifyString : INotifyPropertyChanged
{
private string text = String.Empty;
public event PropertyChangedEventHandler PropertyChanged;
public string Text
{
get
{
return text;
}
set
{
text = value;
NotifyPropertyChanged( "Text" );
}
}
public NotifyString(string newText)
{
text = newText;
}
protected void NotifyPropertyChanged( string propertyChanged )
{
if ( PropertyChanged != null )
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyChanged));
}
}
}
#endregion
#region Private Data Members
string[] channels = null;
int numberFixed = 0;
int numberOfRows = 0;
ObservableCollection<ObservableCollection<NotifyString>> tableText = null;
#endregion
public DataTableControl( List<string> channelNames, List<string> nameToolTips, int numberFixedColumns, int numberRows )
{
InitializeComponent();
numberFixed = numberFixedColumns;
numberOfRows = numberRows;
tableText = new ObservableCollection<ObservableCollection<NotifyString>>();
dataGrid.ItemsSource = tableText;
channels = new string[channelNames.Count];
for (int channelIndex = 0; channelIndex < channelNames.Count; channelIndex++)
{
channels[channelIndex] = channelNames[channelIndex];
tableText.Add(new ObservableCollection<NotifyString>());
for (int i = 0; i < numberOfRows; i++)
{
tableText[channelIndex].Add( new NotifyString(String.Empty) );
}
Binding textBinding = new Binding( ".[" + channelIndex + "]" );
textBinding.Mode = BindingMode.OneWay;
textBinding.UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged;
textBinding.Source = tableText[channelIndex];
DataGridTextColumn newColumn = new DataGridTextColumn();
newColumn.Header = channelNames[channelIndex];
newColumn.DisplayIndex = channelIndex;
newColumn.Binding = textBinding;
if ( channelIndex < numberFixed )
{
newColumn.CanUserReorder = false;
}
dataGrid.Columns.Add(newColumn);
}
//Height = lineHeight + numberOfRows * lineHeight;
}
internal void UpdateChannelRow( int rowNumber, List<string> channelValues, DisplayColors color )
{
if ( rowNumber < numberOfRows )
{
for (int column = 0; column < channelValues.Count; column++)
{
if ( column < channels.GetLength(0) )
{
tableText[column][rowNumber].Text = channelValues[column];
}
}
}
}
}
}