我正在开发一个小应用程序,该应用程序显示DataGrid
中的人员列表。我已经把我的脚趾浸在async
线程池(punny,嗯?)中,大部分都运行良好。但是,我现在遇到了一个问题。我理解问题的根源,但我很难找到解决方案。
在我的DataGrid
中,我有Style
DataTriggers
根据我的视图模型的属性更新行的Visibility
。我在Levenshtein距离搜索期间使用该属性来确定是否将显示行。当我清除搜索时,我会在集合中的所有对象上将属性IsResult
设置为true
,以重新显示完整列表。
我知道问题是UI的快速Layout
更新,而不是迭代过程本身。我已通过性能分析证实了这一点。我知道async/await
并不是解决所有UI问题的神奇解决方案,因此我需要就如何更优雅地管理此操作提出一些指导。
该项目不够大,无法保证在DataGrid
模式下运行Virtual
的复杂性,所以我希望有另一种解决方案,无论我是如何进行的。 ; m执行搜索或如何围绕DataGrid
。
数据网格
<Style x:Key="EditableDataGrid" TargetType="DataGrid">
<Setter Property="IsReadOnly" Value="True"/>
<Setter Property="AutoGenerateColumns" Value="False"/>
<Setter Property="RowBackground" Value="WhiteSmoke"/>
<Setter Property="AlternatingRowBackground" Value="AntiqueWhite"/>
<EventSetter Event="MouseDoubleClick" Handler="GridDoubleClick"/>
<Style.Triggers>
<DataTrigger Binding="{Binding Path=Editing}" Value="True">
<Setter Property="IsReadOnly" Value="False"/>
</DataTrigger>
<DataTrigger Binding="{Binding Path=Adding}" Value="True">
<Setter Property="IsReadOnly" Value="False"/>
</DataTrigger>
</Style.Triggers>
</Style>
<DataGrid Name="FlaggedPersonDataGrid"
Grid.Column="0"
ItemsSource="{Binding FlaggedPeople}"
Style="{StaticResource EditableDataGrid}">
<DataGrid.RowStyle>
<Style TargetType="DataGridRow">
<Style.Triggers>
<DataTrigger Binding="{Binding Path=IsResult}" Value="False">
<Setter Property="Visibility" Value="Collapsed"/>
</DataTrigger>
</Style.Triggers>
</Style>
</DataGrid.RowStyle>
<DataGrid.Columns>
<DataGridTextColumn Width="*" Header="Last Name"
Binding="{Binding LastName, UpdateSourceTrigger=LostFocus}"/>
<DataGridTextColumn Width="*" Header="First Name"
Binding="{Binding FirstName, UpdateSourceTrigger=LostFocus}"/>
</DataGrid.Columns>
<DataGrid.Resources>
<SolidColorBrush x:Key="{x:Static SystemColors.InactiveSelectionHighlightBrushKey}"
Color="#FF3399FF"/>
</DataGrid.Resources>
</DataGrid>
搜索功能
private async Task ExecuteSearchAsync()
{
string searchTerm = SearchText.Text;
double lastNameScore, firstNameScore, distanceScore, searchSensitivity;
ObservableCollection<FlaggedPersonViewModel> searchBase = contextViewModel.FlaggedPeople;
searchSensitivity = SensitivitySlider.Value / 100;
await Task.Run
(() =>
{
foreach (FlaggedPersonViewModel person in searchBase)
{
lastNameScore = GetLevenshteinDistance(searchTerm, person.LastName, false);
lastNameScore = (person.LastName.Length - lastNameScore) / person.LastName.Length;
firstNameScore = GetLevenshteinDistance(searchTerm, person.FirstName, false);
firstNameScore = (person.FirstName.Length - firstNameScore) / person.FirstName.Length;
distanceScore = System.Math.Max(firstNameScore, lastNameScore);
if (distanceScore > searchSensitivity)
person.IsResult = true;
else
person.IsResult = false;
}
});
}
清除搜索功能
private async Task ClearSearchAsync()
{
ObservableCollection<FlaggedPersonViewModel> searchBase = contextViewModel.FlaggedPeople;
await Task.Run
(() =>
{
foreach (FlaggedPersonViewModel person in searchBase)
person.IsResult = true;
});
}
处理程序调用搜索操作
private async void Search_Click(object sender, RoutedEventArgs e)
{
if (contextViewModel.Searching)
{
contextViewModel.Processing = true;
//Already searching, revert to clear state
contextViewModel.Searching = false;
await ClearSearchAsync();
contextViewModel.Processing = false;
}
else
{
contextViewModel.Processing = true;
contextViewModel.Searching = true;
await ExecuteSearchAsync();
contextViewModel.Processing = false;
}
}
效果资料
修改
我从await Task.Run
函数中删除了ClearSearchAsync
,以便在主线程上运行该进程。它似乎进一步降低了性能。
异步运行时为1.42秒,同步运行中为2.39
2017年7月14日更新 目前,我只是尝试重新运行查询并将新的集合投入网格中。我对此并不满意,因为看起来好像是用大锤做细节工作。
答案 0 :(得分:0)
当许多动作/事件试图同时执行时,特别是在UI上的很多移动部件往往会减慢更新速度。
我发现上述代码没有立即出现问题,但建议重构一些方法调用以使用显式依赖项,特别是考虑到调用的异步性质,以便识别与UI相关的组件如何与之交互。
ExecuteSearchAsync Refactored
set makeprg=javac\ %
ClearSearchAsync Refactored
private async Task ExecuteSearchAsync(string searchTerm, ObservableCollection<FlaggedPersonViewModel> searchBase, double searchSensitivity) {
double lastNameScore, firstNameScore, distanceScore;
await Task.Run
(() => {
foreach (FlaggedPersonViewModel person in searchBase) {
lastNameScore = GetLevenshteinDistance(searchTerm, person.LastName, false);
lastNameScore = (person.LastName.Length - lastNameScore) / person.LastName.Length;
firstNameScore = GetLevenshteinDistance(searchTerm, person.FirstName, false);
firstNameScore = (person.FirstName.Length - firstNameScore) / person.FirstName.Length;
distanceScore = System.Math.Max(firstNameScore, lastNameScore);
if (distanceScore > searchSensitivity)
person.IsResult = true;
else
person.IsResult = false;
}
});
}
重构事件处理程序。
private async Task ClearSearchAsync(ObservableCollection<FlaggedPersonViewModel> searchBase) {
await Task.Run
(() => {
foreach (FlaggedPersonViewModel person in searchBase)
person.IsResult = true;
});
}