Question

I have datagrid with TrulyObservableCollection implemented (Notify ObservableCollection when Item changes) - I need to be informed if there is editation on line because I save my datagrid into sqlite (using sqlite-net).

That observable collection contains items of type lets say "plane" and each plane has property lastContact (where is time with last contact stored) and I have to display elapsed time from last contact in real time.

I did something like this:

modelView:

...
public TrulyObservableCollection<Plane> PlanesCollection { get; set; }
...

view (dateconverter is initialized no need to be written here)

<DataGrid ItemsSource="{Binding PlanesCollection}">    
    <DataGrid.Columns>
        <DataGridTextColumn Header="Call Signal" Binding="{Binding Path=CallSign}" Width="auto" />
        <DataGridTextColumn Header="Type" Binding="{Binding Path=Type}" Width="auto" />

        <DataGridTemplateColumn IsReadOnly="True" Header="Last Contact" Width="Auto">
            <DataGridTemplateColumn.CellTemplate>
                <DataTemplate>
                    <Grid>
                        <Grid.ColumnDefinitions>
                            <ColumnDefinition Width="*" />
                            <ColumnDefinition Width="*" />
                        </Grid.ColumnDefinitions>

                        <TextBlock HorizontalAlignment="Stretch" TextAlignment="Center" Grid.Column="0" Text="{Binding Path=LastContact, StringFormat=\{0:HH:mm\}}" />
                        <TextBlock HorizontalAlignment="Stretch" TextAlignment="Center" Grid.Column="1" Text="{Binding Path=LastContact, Converter={StaticResource dateConverter}}" />
                    </Grid>
                </DataTemplate>
            </DataGridTemplateColumn.CellTemplate>
        </DataGridTemplateColumn>
    </DataGrid.Columns>    
</Datagrid> 

and converter only displays elapsed time from last contact.

My problem is that I don't know how to update (it has to be updated at least every minute) cell with elapsed time without refreshing whole datagrid which is not good solution because when user types something into row and datagrid is refreshed everything typed into cell is lost...

So my question is how to do it properly (or is my whole concept bad?) Thanks

Was it helpful?

Solution

One solution could be MultiBinding -- the first property would be the existing LastContact, and the second property would be a new one on your view model called "CurrentTime" or something. Run a timer that updates the CurrentTime property every X seconds, and that should trigger an update on the binding.

Something like this:

<TextBlock>
    <TextBlock.Text>
        <MultiBinding Converter="{StaticResource multiDateConverter}">
            <Binding Path="LastContact" />
            <Binding Path="DataContext.CurrentTime" 
                     RelativeSource="{RelativeSource AncestorType=DataGrid}" />
        </MultiBinding>
    </TextBlock.Text>
</TextBlock>

Here you would need to change your date converter to be an IMultiValueConverter. Just an example:

public class MultiDateConverter : IMultiValueConverter
{
    public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
    {
        if (!(values.First() is DateTime))
            return DependencyProperty.UnsetValue;
        return string.Format("{0:N1} seconds ago", DateTime.Now.Subtract((DateTime)values.First()).TotalSeconds);
    }

    public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}

The last piece is just to run a dispatcher timer to update the new "CurrentTime" property:

const int refreshRateInSeconds = 1;
var timer = new DispatcherTimer();
timer.Tick += (sender, args) => CurrentTime = DateTime.Now;
timer.Interval = TimeSpan.FromSeconds(refreshRateInSeconds);
timer.Start();
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top