Hi all,
I have a class that has two ObservableCollection< TimeValue >'s, where TimeValue is a custom DateTime/Value pairing with change-notification (via INotifyPropertyChanged). I call these Targets and Actuals.
When I bind these to a chart, everything works perfectly, and I get two LineSeries. If I bind one of them to a DataGrid, with a column for "Date" and a column for "Value", works perfectly again. I even get the TwoWay binding that I need.
However, I need to have a DataGrid that has a "Date" column, and a column each for Targets and Actuals. The problem is that I need to list ALL dates in a range, whereas some of these dates may not have corresponding values in Targets, Actuals, or both.
So, I decided I would do a MultiBinding that takes Targets and Actuals as input, and outputs a combined TimeSeriesC, with null values whenever either of the originals had no value.
It works, but does not respond to any changes in the underlying data.
This works fine (binding to one ObservableCollection):
<ctrls:DataGrid Grid.Row="1" Height="400" AutoGenerateColumns="False" CanUserDeleteRows="False" SelectionUnit="Cell">
<ctrls:DataGrid.ItemsSource>
<Binding Path="Targets"/>
<!--<MultiBinding Converter="{StaticResource TargetActualListConverter}">
<Binding Path="Targets"/>
<Binding Path="Actuals"/>
</MultiBinding>-->
</ctrls:DataGrid.ItemsSource>
<ctrls:DataGrid.Columns>
<ctrls:DataGridTextColumn Header="Date" Binding="{Binding Date,StringFormat={}{0:ddd, MMM d}}"/>
<ctrls:DataGridTextColumn Header="Target" Binding="{Binding Value}"/>
<!--<ctrls:DataGridTextColumn Header="Target" Binding="{Binding Value[0]}"/>
<ctrls:DataGridTextColumn Header="Actual" Binding="{Binding Value[1]}"/>-->
</ctrls:DataGrid.Columns>
This works, but only when first initialized. No response to change-notification:
<ctrls:DataGrid Grid.Row="1" Height="400" AutoGenerateColumns="False" CanUserDeleteRows="False" SelectionUnit="Cell">
<ctrls:DataGrid.ItemsSource>
<!--<Binding Path="Targets"/>-->
<MultiBinding Converter="{StaticResource TargetActualListConverter}">
<Binding Path="Targets"/>
<Binding Path="Actuals"/>
</MultiBinding>
</ctrls:DataGrid.ItemsSource>
<ctrls:DataGrid.Columns>
<ctrls:DataGridTextColumn Header="Date" Binding="{Binding Date,StringFormat={}{0:ddd, MMM d}}"/>
<!--<ctrls:DataGridTextColumn Header="Target" Binding="{Binding Value}"/>-->
<ctrls:DataGridTextColumn Header="Target" Binding="{Binding Value[0]}"/>
<ctrls:DataGridTextColumn Header="Actual" Binding="{Binding Value[1]}"/>
</ctrls:DataGrid.Columns>
And here is my IMultiValueConverter:
class TargetActualListConverter : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
TimeSeries<double> Targets = values[0] as TimeSeries<double>;
TimeSeries<double> Actuals = values[1] as TimeSeries<double>;
DateTime[] range = TimeSeries<double>.GetDateRange(Targets, Actuals);//Get min and max Dates
int count = (range[1] - range[0]).Days;//total number of days
DateTime currDate = new DateTime();
TimeSeries<double?[]> combined = new TimeSeries<double?[]>();
for (int i = 0; i < count; i++)
{
currDate = range[0].AddDays(i);
double?[] vals = { Targets.Dates.Contains(currDate) ? (double?)Targets.GetValueByDate(currDate) : null, Actuals.Dates.Contains(currDate) ? (double?)Actuals.GetValueByDate(currDate) : null };
combined.Add(new TimeValue<double?[]>(currDate, vals));
}
return combined;
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, System.Globalization.CultureInfo culture)
{
TimeSeries<double?[]> combined = value as TimeSeries<double?[]>;
TimeSeries<double> Targets = new TimeSeries<double>();
TimeSeries<double> Actuals = new TimeSeries<double>();
foreach (TimeValue<double?[]> tv in combined)
{
if(tv.Value[0]!=null)
Targets.Add(new TimeValue<double>(tv.Date,(double)tv.Value[0]));
if (tv.Value[1] != null)
Actuals.Add(new TimeValue<double>(tv.Date, (double)tv.Value[1]));
}
TimeSeries<double>[] result = { Targets, Actuals };
return result;
}
}
I can't be too far off, since it displays the values.
What am I doing wrong? Or, alternatively, is there an easier way of doing this?
Thanks all!