当我使用 Convert 格式化日期时,WPF 数据绑定非常慢
我正在编写一个简单的应用程序来在 DataGrid 上显示一些数据。数据只是一个测量值(浮点数)和一个时间戳。时间戳是一个 uint,自 2000 年以来以秒为单位。
我成功完成了任务,但注意到显示数据网格需要很长时间(约 1 分钟)。大约有20,000条数据。我认为由一个 uint 和一个 float 组成的 20,000 个数据不会那么混乱。下一个请求是将时间显示为格式化时间,而不是自 2000 年以来的秒数。我通过使 XAML 看起来像这样来做到这一点:
<kit:DataGridTextColumn Header="FilteredValue" Binding="{Binding Path=FilteredValue}" />
<kit:DataGridTextColumn Header="Timestamp" Binding="{Binding Path=Timestamp, Converter={StaticResource TimeConverter}}" CanUserSort="False" />
TimeConverter 方法看起来像:
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
DateTime currentDateTime = new DateTime(2000, 1, 1, 0, 0, 0, DateTimeKind.Utc);
currentDateTime = currentDateTime.AddSeconds((uint)value);
return currentDateTime.ToString();
}
这也工作得很好。然而,事实证明,一些原始数据可能是0xFFFFFFFF。 这意味着没有数据或无效数据。在这种情况下,我不想转换为日期。所以我写道:
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if ((uint)value == 0xFFFFFFFF)
{
// don't bother to convert
return ((uint)value).ToString("X");
}
else
{
DateTime currentDateTime = new DateTime(2000, 1, 1, 0, 0, 0, DateTimeKind.Utc);
currentDateTime = currentDateTime.AddSeconds((uint)value);
return currentDateTime.ToString();
}
}
同样,它可以工作,但是非常慢。比原来慢,大约需要10分钟。我对此感到非常惊讶。难道只是额外的代码运行了23000次吗? 1. 我应该做什么?我可以在 XAML 中执行某些操作,以便在不需要时不会调用转换器吗? 2. 当我的其中一个测量值 (FilteredValues) 为 0xFFFFFFFF 时,它会显示为 NaN。这可能没问题,但如果只显示 0xFFFFFFFF 或“无数据”就更好了。我认为它被设置为 NaN 因为底层数据类型是浮点数。
有什么想法吗?
谢谢, Dave
这是 XAML。最后一个数据网格是我们感兴趣的一个。请注意,我什至将“IsVirtualizing”设置为“True”。另请注意 ScrollViewer 的使用。我这样做是因为否则我无法看到最后一个网格(最终显示时)上的所有行。删除此选项并不会加快速度。
<Window x:Class="STDatabaseReader.Window1" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:chartingToolkit="clr-namespace:System.Windows.Controls.DataVisualization.Charting;assembly=System.Windows.Controls.DataVisualization.Toolkit" xmlns:kit="http://schemas.microsoft.com/wpf/2008/toolkit" xmlns:local="clr-namespace:STDatabaseReader"
Title="Smart Transmitter Database Reader">
<Window.Resources>
<local:BytesToStringConverter x:Key="BytesToStringConverter"></local:BytesToStringConverter>
<local:TimeConverter x:Key="TimeConverter"></local:TimeConverter>
</Window.Resources>
<Grid>
<ScrollViewer>
<StackPanel Orientation="Vertical">
<Button Name="m_btnFetchData" HorizontalAlignment="Left" Click="m_btnFetchData_Click">Fetch File</Button>
<StackPanel Orientation="Horizontal">
<StackPanel Orientation="Vertical">
<Label HorizontalAlignment="Center">Partition 1</Label>
<kit:DataGrid Name="m_gridPartion1" AutoGenerateColumns="False">
<kit:DataGrid.Columns>
<kit:DataGridTextColumn Header="Header Info" Binding="{Binding Path=HeaderInfo, Converter={StaticResource BytesToStringConverter}}" CanUserSort="False" />
<kit:DataGridTextColumn Header="Transmitter Id" Binding="{Binding Path=TransmitterId, Converter={StaticResource BytesToStringConverter}}" CanUserSort="False" />
<kit:DataGridTextColumn Header="DeviceNumber" Binding="{Binding Path=DeviceNumber}" />
<kit:DataGridTextColumn Header="HardwareVersion" Binding="{Binding Path=HardwareVersion}" />
<kit:DataGridTextColumn Header="CRC" Binding="{Binding Path=CRC}" />
</kit:DataGrid.Columns>
</kit:DataGrid>
</StackPanel>
<StackPanel Orientation="Vertical">
<Label HorizontalAlignment="Center">Partition 3</Label>
<kit:DataGrid Name="m_gridPartion3" AutoGenerateColumns="False">
<kit:DataGrid.Columns>
<kit:DataGridTextColumn Header="Header Info" Binding="{Binding Path=HeaderInfo, Converter={StaticResource BytesToStringConverter}}" CanUserSort="False" />
<kit:DataGridTextColumn Header="SystemTime" Binding="{Binding Path=SystemTime, Converter={StaticResource TimeConverter}}" />
</kit:DataGrid.Columns>
</kit:DataGrid>
</StackPanel>
</StackPanel>
<StackPanel Orientation="Vertical">
<Label HorizontalAlignment="Center">Partition 2</Label>
<kit:DataGrid Name="m_gridPartion2" AutoGenerateColumns="False">
<kit:DataGrid.Columns>
<kit:DataGridTextColumn Header="Header Info" Binding="{Binding Path=HeaderInfo, Converter={StaticResource BytesToStringConverter}}" CanUserSort="False" />
<kit:DataGridTextColumn Header="FirmwareRevision" Binding="{Binding Path=FirmwareRevision, Converter={StaticResource BytesToStringConverter}}" CanUserSort="False" />
<kit:DataGridTextColumn Header="SoftwarePartNumber" Binding="{Binding Path=SoftwarePartNumber, Converter={StaticResource BytesToStringConverter}}" CanUserSort="False" />
<kit:DataGridTextColumn Header="FirmwareUpgradeTime" Binding="{Binding Path=FirmwareUpgradeTime,Converter={StaticResource TimeConverter}}" />
<kit:DataGridTextColumn Header="DatabaseEraseTime" Binding="{Binding Path=DatabaseEraseTime,Converter={StaticResource TimeConverter}}" />
<kit:DataGridTextColumn Header="RangeEnzymeElectrode" Binding="{Binding Path=RangeEnzymeElectrode}" />
<kit:DataGridTextColumn Header="OffsetEnzymeElectrode" Binding="{Binding Path=OffsetEnzymeElectrode}" />
<kit:DataGridTextColumn Header="BiasValue" Binding="{Binding Path=BiasValue}" />
</kit:DataGrid.Columns>
</kit:DataGrid>
</StackPanel>
<StackPanel Orientation="Horizontal">
<StackPanel Orientation="Vertical">
<Label HorizontalAlignment="Center">Partition 4 - HeaderInfo</Label>
<kit:DataGrid Name="m_gridDataHeader" AutoGenerateColumns="False">
<kit:DataGrid.Columns>
<kit:DataGridTextColumn Header="Header Info" Binding="{Binding Path=HeaderInfo, Converter={StaticResource BytesToStringConverter}}" CanUserSort="False" />
</kit:DataGrid.Columns>
</kit:DataGrid>
</StackPanel>
<StackPanel Orientation="Vertical">
<Label HorizontalAlignment="Center">Partition 4 - Chemistry Data</Label>
<kit:DataGrid Name="m_gridData" AutoGenerateColumns="False" VirtualizingStackPanel.IsVirtualizing="True" Loaded="m_gridData_Loaded">
<kit:DataGrid.Columns>
<!--
<kit:DataGridTextColumn Header="Noise" Binding="{Binding Path=Noise, StringFormat=\{0:X8\}}" />
<kit:DataGridTextColumn Header="FilteredValue" Binding="{Binding Path=FilteredValue, StringFormat='X'}" />
<kit:DataGridTextColumn Header="Timestamp" Binding="{Binding Path=Timestamp, StringFormat=\{0:X\}}" /> -->
<kit:DataGridTextColumn Header="Noise" Binding="{Binding Path=Noise}" />
<kit:DataGridTextColumn Header="FilteredValue" Binding="{Binding Path=FilteredValue}" />
<kit:DataGridTextColumn Header="Timestamp" Binding="{Binding Path=Timestamp, Converter={StaticResource TimeConverter}}" CanUserSort="False" />
</kit:DataGrid.Columns>
</kit:DataGrid>
</StackPanel >
</StackPanel>
</StackPanel>
</ScrollViewer>
</Grid>
I'm writing a simple app to display some data on a DataGrid. The data is just a measurement (float) and a timestamp. The timestamp a uint and is in seconds since 2000.
I sucessfully accomplished the task but did notice it takes a long time (~1 minute) to display the datagrid. There are about 20,000 data. I wouldn't think 20,000 datum consisting of a uint and a float was that mush. The next request was to display the time as formatted time instead of seconds since 2000. This I did by making the XAML look like this:
<kit:DataGridTextColumn Header="FilteredValue" Binding="{Binding Path=FilteredValue}" />
<kit:DataGridTextColumn Header="Timestamp" Binding="{Binding Path=Timestamp, Converter={StaticResource TimeConverter}}" CanUserSort="False" />
The TimeConverter method looks like:
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
DateTime currentDateTime = new DateTime(2000, 1, 1, 0, 0, 0, DateTimeKind.Utc);
currentDateTime = currentDateTime.AddSeconds((uint)value);
return currentDateTime.ToString();
}
This also worked fine. However, it turns out that some of the raw data can be 0xFFFFFFFF.
This means that there is no data or invalid data. In this case, I don't want to convert to a date. So I wrote:
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if ((uint)value == 0xFFFFFFFF)
{
// don't bother to convert
return ((uint)value).ToString("X");
}
else
{
DateTime currentDateTime = new DateTime(2000, 1, 1, 0, 0, 0, DateTimeKind.Utc);
currentDateTime = currentDateTime.AddSeconds((uint)value);
return currentDateTime.ToString();
}
}
Again, it works, but it's very slow. Slower than the original and takes about 10 minutes. I was pretty amazed by this. Is it just the case that the extra code is running 23,000 times?
1. What should I be doing? Can I do something in XAML so my Converter is not called if not necessary?
2. When I have 0xFFFFFFFF for one of the measurements (FilteredValues) it gets displayed as NaN. This is probably ok, but it would be nice just to show 0xFFFFFFFF or "no data". I think it's getting set to NaN because the underlying data type is a float.
Any ideas?
Thanks,
Dave
Here is the XAML. The last Datagrid is the one of interest. Note that I even set "IsVirtualizing" to True". Also note the use of ScrollViewer. I did this because otherwise I can't see all the rows on the last grid (when it finally) displays. Removing this did not speed things up.
<Window x:Class="STDatabaseReader.Window1" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:chartingToolkit="clr-namespace:System.Windows.Controls.DataVisualization.Charting;assembly=System.Windows.Controls.DataVisualization.Toolkit" xmlns:kit="http://schemas.microsoft.com/wpf/2008/toolkit" xmlns:local="clr-namespace:STDatabaseReader"
Title="Smart Transmitter Database Reader">
<Window.Resources>
<local:BytesToStringConverter x:Key="BytesToStringConverter"></local:BytesToStringConverter>
<local:TimeConverter x:Key="TimeConverter"></local:TimeConverter>
</Window.Resources>
<Grid>
<ScrollViewer>
<StackPanel Orientation="Vertical">
<Button Name="m_btnFetchData" HorizontalAlignment="Left" Click="m_btnFetchData_Click">Fetch File</Button>
<StackPanel Orientation="Horizontal">
<StackPanel Orientation="Vertical">
<Label HorizontalAlignment="Center">Partition 1</Label>
<kit:DataGrid Name="m_gridPartion1" AutoGenerateColumns="False">
<kit:DataGrid.Columns>
<kit:DataGridTextColumn Header="Header Info" Binding="{Binding Path=HeaderInfo, Converter={StaticResource BytesToStringConverter}}" CanUserSort="False" />
<kit:DataGridTextColumn Header="Transmitter Id" Binding="{Binding Path=TransmitterId, Converter={StaticResource BytesToStringConverter}}" CanUserSort="False" />
<kit:DataGridTextColumn Header="DeviceNumber" Binding="{Binding Path=DeviceNumber}" />
<kit:DataGridTextColumn Header="HardwareVersion" Binding="{Binding Path=HardwareVersion}" />
<kit:DataGridTextColumn Header="CRC" Binding="{Binding Path=CRC}" />
</kit:DataGrid.Columns>
</kit:DataGrid>
</StackPanel>
<StackPanel Orientation="Vertical">
<Label HorizontalAlignment="Center">Partition 3</Label>
<kit:DataGrid Name="m_gridPartion3" AutoGenerateColumns="False">
<kit:DataGrid.Columns>
<kit:DataGridTextColumn Header="Header Info" Binding="{Binding Path=HeaderInfo, Converter={StaticResource BytesToStringConverter}}" CanUserSort="False" />
<kit:DataGridTextColumn Header="SystemTime" Binding="{Binding Path=SystemTime, Converter={StaticResource TimeConverter}}" />
</kit:DataGrid.Columns>
</kit:DataGrid>
</StackPanel>
</StackPanel>
<StackPanel Orientation="Vertical">
<Label HorizontalAlignment="Center">Partition 2</Label>
<kit:DataGrid Name="m_gridPartion2" AutoGenerateColumns="False">
<kit:DataGrid.Columns>
<kit:DataGridTextColumn Header="Header Info" Binding="{Binding Path=HeaderInfo, Converter={StaticResource BytesToStringConverter}}" CanUserSort="False" />
<kit:DataGridTextColumn Header="FirmwareRevision" Binding="{Binding Path=FirmwareRevision, Converter={StaticResource BytesToStringConverter}}" CanUserSort="False" />
<kit:DataGridTextColumn Header="SoftwarePartNumber" Binding="{Binding Path=SoftwarePartNumber, Converter={StaticResource BytesToStringConverter}}" CanUserSort="False" />
<kit:DataGridTextColumn Header="FirmwareUpgradeTime" Binding="{Binding Path=FirmwareUpgradeTime,Converter={StaticResource TimeConverter}}" />
<kit:DataGridTextColumn Header="DatabaseEraseTime" Binding="{Binding Path=DatabaseEraseTime,Converter={StaticResource TimeConverter}}" />
<kit:DataGridTextColumn Header="RangeEnzymeElectrode" Binding="{Binding Path=RangeEnzymeElectrode}" />
<kit:DataGridTextColumn Header="OffsetEnzymeElectrode" Binding="{Binding Path=OffsetEnzymeElectrode}" />
<kit:DataGridTextColumn Header="BiasValue" Binding="{Binding Path=BiasValue}" />
</kit:DataGrid.Columns>
</kit:DataGrid>
</StackPanel>
<StackPanel Orientation="Horizontal">
<StackPanel Orientation="Vertical">
<Label HorizontalAlignment="Center">Partition 4 - HeaderInfo</Label>
<kit:DataGrid Name="m_gridDataHeader" AutoGenerateColumns="False">
<kit:DataGrid.Columns>
<kit:DataGridTextColumn Header="Header Info" Binding="{Binding Path=HeaderInfo, Converter={StaticResource BytesToStringConverter}}" CanUserSort="False" />
</kit:DataGrid.Columns>
</kit:DataGrid>
</StackPanel>
<StackPanel Orientation="Vertical">
<Label HorizontalAlignment="Center">Partition 4 - Chemistry Data</Label>
<kit:DataGrid Name="m_gridData" AutoGenerateColumns="False" VirtualizingStackPanel.IsVirtualizing="True" Loaded="m_gridData_Loaded">
<kit:DataGrid.Columns>
<!--
<kit:DataGridTextColumn Header="Noise" Binding="{Binding Path=Noise, StringFormat=\{0:X8\}}" />
<kit:DataGridTextColumn Header="FilteredValue" Binding="{Binding Path=FilteredValue, StringFormat='X'}" />
<kit:DataGridTextColumn Header="Timestamp" Binding="{Binding Path=Timestamp, StringFormat=\{0:X\}}" /> -->
<kit:DataGridTextColumn Header="Noise" Binding="{Binding Path=Noise}" />
<kit:DataGridTextColumn Header="FilteredValue" Binding="{Binding Path=FilteredValue}" />
<kit:DataGridTextColumn Header="Timestamp" Binding="{Binding Path=Timestamp, Converter={StaticResource TimeConverter}}" CanUserSort="False" />
</kit:DataGrid.Columns>
</kit:DataGrid>
</StackPanel >
</StackPanel>
</StackPanel>
</ScrollViewer>
</Grid>
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
由于该列是 DataGridTextColumn,您只需将其返回到转换器即可使其显示 0xFFFFFFFF
至于
DataGrid
速度较慢,它应该使用VirtualizingStackPanel< /code> 默认情况下,所以如果您没有更改它,那么它应该非常快,因为您只会使用当前用户可见的
DataGridRows
。此外,转换器中的代码几乎不需要花费任何时间。因此,
DataGrid
速度缓慢的最可能原因可能是您已将ItemsPanel
更改为VirtualizingStackPanel
以外的其他内容,或者禁用了虚拟化不知何故,但如果不查看DataGrid
的定义方式,就很难判断编辑
在
DataGrid
完成加载后运行以下代码,例如在DataGrid
的Loaded
事件中。如果MessageBox
显示很大的数字(不应超过 50),那么您就找到了问题的根源。例如,使用 StackPanel 作为父面板会非常慢,因为 DataGrid 可以消耗无限的垂直空间,因此将生成所有行,
但使用 Grid 将会非常快,因为
DataGrid
将受到高度限制,因此可以使用虚拟化Since the column is a
DataGridTextColumn
you can make it display 0xFFFFFFFF by just returning it in the converterAs for the
DataGrid
being slow, it should be using aVirtualizingStackPanel
by default so if you haven't changed this then it should be pretty fast since you'll only be working with theDataGridRows
that are visible to the user at the moment. Also the code in the converter should take virtually no time.So the most likely reason for your
DataGrid
being slow is probably that you've changed theItemsPanel
to something else than aVirtualizingStackPanel
or disabled the virtualization somehow but it's hard to tell without seeing how yourDataGrid
is definedEdit
Run the following code after your
DataGrid
has finished loading, for example in theLoaded
event for theDataGrid
. If theMessageBox
displays a large number (shouldn't be above 50) then you have the source of your problem.For example, using a
StackPanel
as the parent panel will be very slow since theDataGrid
can consume unlimited vertical space so all the rows will be generatedbut using a
Grid
will be very fast because theDataGrid
will be restricted in height so Virtualization can be used