3

I have a Log object that contains a list of Curve objects. Each curve has a Name property and an array of doubles. I want the Name to be in the column header and the data below it. I have a user control with a datagid. Here is the XAML;

<UserControl x:Class="WellLab.UI.LogViewer"
         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
         xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
         xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
         mc:Ignorable="d" 
         d:DesignHeight="500" d:DesignWidth="500">
<Grid>
    <StackPanel Height="Auto" HorizontalAlignment="Stretch" Margin="0" Name="stackPanel1" VerticalAlignment="Stretch" Width="Auto">
        <ToolBarTray Height="26" Name="toolBarTray1" Width="Auto" />
        <ScrollViewer Height="Auto" Name="scrollViewer1" Width="Auto" HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Visible" CanContentScroll="True" Background="#E6ABA4A4">
            <DataGrid AutoGenerateColumns="True" Height="Auto" Name="logDataGrid" Width="Auto" ItemsSource="{Binding}" HorizontalAlignment="Left">
            </DataGrid>
        </ScrollViewer>
    </StackPanel>
</Grid>

In the code behind I have figured out how to create columns and name them, but I have not figured out how to bind the data.

public partial class LogViewer
{
    public LogViewer(Log log)
    {
        InitializeComponent();

        foreach (var curve in log.Curves)
        {
            var data = curve.GetData();
            var col = new DataGridTextColumn { Header = curve.Name };
            logDataGrid.Columns.Add(col);
        }
    }
}

I wont even show the code I tried to use to bind the array "data", since nothing even came close. I am sure I am missing something simple, but after hours of searching the web, I have to come begging for an answer.

spainchaud
  • 365
  • 3
  • 12
  • possible duplicate of [How can I display array elements in a WPF DataGrid?](http://stackoverflow.com/questions/5582226/how-can-i-display-array-elements-in-a-wpf-datagrid) – H.B. Jun 02 '12 at 22:38
  • @dbaseman: That doesn't help with arrays as there is no built-in logic to deal with them. – H.B. Jun 02 '12 at 23:25
  • @H.B. thanks for the clarification. I misunderstood the question. – McGarnagle Jun 02 '12 at 23:26
  • Typically when you bind an array to a DataGrid, each member of the array is a row, not a column. In your case you could have two columns, one for the Name, the other for the Data. If data is an array itself, then you could create a templated column to bind to each Data array with an ItemsControl of some sort. – Trevor Elliott Jun 03 '12 at 00:27
  • Moozhe has it right about each member of an array is a row. That is what I keep ending up with, which will not work for me. I expect the final solution to have two datagrids. One for the header, i.e., the names associated with the curve, and a separate datagrid, in a scrollviewer, to hold the curve data. The curve data is an array of doubles, typically with thousands of elements. – spainchaud Jun 03 '12 at 05:50

1 Answers1

3

You need to pivot the log data into a collection of RowDataItem where each row contains a collection of double values, one for each Curve. At the same time you can extract the column names. So the data would end up like this.

public class PivotedLogData : ViewModelBase
{
    public PivotedLogData(Log log)
    {
        ColumnNames = log.Curves.Select(c => c.Name).ToList();

        int numRows = log.Curves.Max(c => c.Values.Count);

        var items = new List<RowDataItem>(numRows);

        for (int i = 0; i < numRows; i++)
        {
            items.Add(new RowDataItem(
                          log.Curves.Select(
                              curve => curve.Values.Count > i
                                           ? curve.Values[i]
                                           : (double?) null).ToList()));
        }

        Items = items;
    }

    public IList<string> ColumnNames { get; private set; }
    public IEnumerable<RowDataItem> Items { get; private set; }
}

public class RowDataItem
{
    public RowDataItem(IList<double?> values)
    {
        Values = values;
    }

    public IList<double?> Values { get; private set; }
}

Then you would create DataGridTextColumn items as above but with a suitable binding

var pivoted = new PivotedLogData(log);

int columnIndex = 0;

foreach (var name in pivoted .ColumnName)
{
    dataGrid.Columns.Add(
        new DataGridTextColumn
            {
                Header = name,
                Binding = new Binding(string.Format("Values[{0}]", columnIndex++))
            });
}

Now bind the data to the grid

dataGrid.ItemsSource = pivoted.Items;
Phil
  • 42,255
  • 9
  • 100
  • 100
  • Thanks you for the example. It works perfectly. Unfortunately there are two problems. The data grid is way too slow. It took 10 seconds for a grid with 25,000 entries to open. A small number like this should open almost instantly. Also I need to be able to delete a single curve in my log and see a column in my grid go away. – spainchaud Jun 04 '12 at 01:32
  • To explain further, I am trying to emulate an existing program (Windows Forms) that uses data structures similiar to what I have. That program opens much larger data sets very quickly. I think it may be using a third party data grid control. I will have to ask the author how he did it. – spainchaud Jun 04 '12 at 01:55
  • I've tested with 10 curves of 250,000 entries. The pivot took 500ms (could be improved maybe). The grid display instantaneously. It should be simple to respond to an event (CurveRemoved) and then remove a column and all associated values. – Phil Jun 04 '12 at 08:20
  • I was able to dramatically speed up the data grid by putting it in a DockPanel, instead of a StackPanel, which also gave me scroll bars. I timed 4 cases, which includes pivoting, and filling the datagrid. Here are my times:Open log MPR Modeled. So a smaller case is about 2.5 secs. Maybe I can find another speed up. Time taken : 00:00:04.69 Number of points: 42500 Open log DTKRes Modeled Time taken : 00:00:02.92 Number of points: 22500 Open log RADRAngleMM Time taken : 00:00:02.51 Number of points: 22500 Open log RADRTargMM Time taken : 00:00:02.32 Number of points: 22500 – spainchaud Jun 04 '12 at 14:02
  • I will go to work in a few minutes and I can find out how they filled their winforms control. – spainchaud Jun 04 '12 at 14:06