01-21-2014 03:30 PM
I have an AnalogWaveform object with my data in it. Is it possible to databind this to the Microsoft WPF Datagrid control?
01-23-2014 09:40 AM
Hi cymrieg,
It doesn't seem like there's an obvious, traditional way to bind an AnalogWaveform object to a DataGrid control. Can I ask why you're trying to do this? Traditionally DataGrids are used to make "table" type UI's with mostly text and occasional pictures:
http://wpftutorial.net/DataGrid.html#selection
01-24-2014 11:24 AM
I want to use the graph to plot the data and I also want to be able to show the data in a "spreadsheet" (a.k.a. Datagrid). 1 column for the Timestamps and 1 colunm for the measurements.
I mean you are dead right the WPF data grid seems to be designed for showing contact info out of a database.
01-27-2014 04:39 PM
Hi cymrieg,
Thanks for the clarification. I was initially thinking you wanted to display the data as a waveform within the DataGrid. But now I see you want more of a table control with timestamps and numeric values for the measurements.
Can you use the Timing and Samples properties or the GetTimeStamps and GetRawData methods to programmatically extract the AnalogWaveform data?
http://zone.ni.com/reference/en-XX/help/372636F-01/mstudiowebhelp/html/b3168f32/
01-28-2014 03:40 PM
Expanding on Kelsey's suggestion, here is an example using the Samples of an analog waveform exposed through a "Waveform" property on the data context:
<DataGrid ItemsSource="{Binding Waveform.Samples}" AutoGenerateColumns="False">
<DataGrid.Columns>
<DataGridTextColumn Header="Index" Binding="{Binding Index}" />
<DataGridTextColumn Header="TimeStamp" Binding="{Binding TimeStamp}" />
<DataGridTextColumn Header="Value" Binding="{Binding Value}" />
</DataGrid.Columns>
</DataGrid>
It uses manually defined data grid columns to show the index, time stamp, and value of each AnalogWaveformSample in the Samples collection.
03-25-2014 03:15 PM
Paul,
That looks good, thanks.
How about when I have a series of waveforms (say one is current values and the others are voltage and resistance and so on)? I would like to show in this case 5 columns (Index, Timestamp, V, I and R. How can I bind then to the DataGrid?
Do I go down the route of an array of AnalogWaveforms or do I try and use the AnalogWaveformCollection. For the latter I don't see how to add the waveforms into the colection there is no Add method.
03-25-2014 05:00 PM
To get the data into a format the DataGrid can accept, you can either 1) create a custom object for each sample, or 2) bind back to the parent data context to access the other waveforms.
For option 1, you would change the binding from Waveform.Samples to your custom object collection, and add more columns binding to the Voltage, Current, etc properties on the custom object:
<DataGrid ItemsSource="{Binding Custom}" AutoGenerateColumns="False">
<DataGrid.Columns>
<DataGridTextColumn Header="Index" Binding="{Binding Index}" />
<DataGridTextColumn Header="TimeStamp" Binding="{Binding TimeStamp}" />
<DataGridTextColumn Header="V" Binding="{Binding Voltage}" />
<DataGridTextColumn Header="I" Binding="{Binding Current}" />
<DataGridTextColumn Header="R" Binding="{Binding Resistance}" />
</DataGrid.Columns>
</DataGrid>
For option 2, instead of having one Waveform property on the data context, you would either have separate Voltage, Current, etc properties for each waveform, or a collection of those waveforms. The example below illustrates both of these cases using a data context with Voltage, Current, Resistance, and Collection properties:
Code:
// Custom converter to index corresponding samples in parallel waveforms.
public sealed class WaveformIndexer : IMultiValueConverter {
public object Convert( object[] values, Type targetType, object parameter, CultureInfo culture ) {
var waveform = (AnalogWaveform<double>)values[0];
int index = (int)values[1];
var sample = waveform.Samples[index];
return sample.Value;
}
...
}
XAML:
<!-- separate waveform properties -->
<DataGrid ItemsSource="{Binding Voltage.Samples}" AutoGenerateColumns="False">
<!-- or collection of waveforms -->
<DataGrid ItemsSource="{Binding Collection[0].Samples}" AutoGenerateColumns="False">
<DataGrid.Resources>
<local:WaveformIndexer x:Key="Indexer" />
</DataGrid.Resources>
<DataGrid.Columns>
<DataGridTextColumn Header="Index" Binding="{Binding Index}" />
<DataGridTextColumn Header="TimeStamp" Binding="{Binding TimeStamp}" />
<DataGridTextColumn Header="V" Binding="{Binding Value}" />
<DataGridTextColumn Header="I">
<DataGridTextColumn.Binding>
<MultiBinding Converter="{StaticResource Indexer}" StringFormat="G">
<!-- separate waveform properties -->
<Binding Path="DataContext.Current" RelativeSource="{RelativeSource FindAncestor, AncestorType=DataGrid}" />
<Binding Path="Index" />
</MultiBinding>
</DataGridTextColumn.Binding>
</DataGridTextColumn>
<DataGridTextColumn Header="R">
<DataGridTextColumn.Binding>
<MultiBinding Converter="{StaticResource Indexer}" StringFormat="G">
<!-- collection of waveforms -->
<Binding Path="DataContext.Collection[2]" RelativeSource="{RelativeSource FindAncestor, AncestorType=DataGrid}" />
<Binding Path="Index" />
</MultiBinding>
</DataGridTextColumn.Binding>
</DataGridTextColumn>
</DataGrid.Columns>
</DataGrid>
(The AnalogWaveformCollection is used to represent a fixed set of data read by hardware, so it does not support modification.)
03-25-2014 05:29 PM
I only showed an example of having V, I and R but we are writing some generic code that can take data fron a Data Logger so there could be between 1 and 300 channels of data that we would like on the Datagrid. A column for each channel.
SO, that rules out the property per channel option.
I like the collection approach so what is the property "Collection" in the XAML? Is it a Collection of AnalogWaveform's or AnalogWaveformSamples?
Then I suppose it should also be an ObservableCollection so if we append data to the already existing channels (waveforms) the the DataGrid will see the additions.
03-26-2014 09:40 AM
What is the property "Collection" in the XAML?
For the example, I just used an array of AnalogWaveform<double>, but any IList would work.
Collection could be an ObservableCollection so the DataGrid will see when we append channels.
From what I know of the data grid, it is geard towards a fixed set of columns and a variable set of rows. Appending data to the example Collection property will not automatically add more columns.
Instead, I think you will need to create the columns for the data grid in code. This should make the bindings a lot simpler: you will still want one reference collection in the data grid for indexing, but all of the value columns can use a simple binding, changing the custom multi-value converter to an IValueConverter that takes the collection as a parameter. For example:
var converter = new WaveformIndexer( );
...
var bindingA = new Binding( "Index" ) { Converter = converter, ConverterParameter = waveformA };
var columnA = new DataGridTextColumn { Header = "Value A", Binding = bindingA };
dataGrid.Columns.Add( columnA );