我试图理解为什么我用来显示输入信息的网格视图的以下WPF C#
代码是如此之慢,特别是如何改进它以加快控件的速度渲染。
我有以下输入,可根据用户选择而有所不同:
public class Field
{
public string Key;
public Tuple<string, bool> Value;
}
var fields = new List<Field>();
// fill fields...
对于每个字段,我创建一个插入VirtualizingStackPanel
的控件:
StackPanelFields.Children.Clear();
foreach (var f in fields)
StackPanelFields.Children.Add(GetFieldControl(f.Key, f.Value));
private Grid GetFieldControl(string name, Tuple<string, bool> value)
{
Debug.Assert(!String.IsNullOrWhiteSpace(name));
Debug.Assert(value != null);
// two-column grid
var grid = new Grid();
grid.ColumnDefinitions.Add(new ColumnDefinition());
grid.ColumnDefinitions.Add(new ColumnDefinition());
var color = value.Item2 ? Brushes.Black : Brushes.Red;
var nameTextblock = new TextBlock { Text = name, Margin = new Thickness(5, 0, 0, 5), Foreground = color };
grid.Children.Add(nameTextblock);
// value
var valueTextBox = new TextBox
{
Text = value.Item1,
Foreground = color,
TextWrapping = TextWrapping.Wrap,
IsReadOnly = true,
BorderThickness = new Thickness(0)
};
Grid.SetColumn(valueTextBox, 1);
grid.Children.Add(valueTextBox);
return grid;
}
字段数平均在1000-2000之间。在我的机器上填充VirtualizingStackPanel
可能需要超过1秒;我没有测量过这个时间,但显然对用户来说非常慢。
答案 0 :(得分:0)
我在呈现1.000.000项目(甚至更多)时没有任何问题,创建数据集合然后呈现它将花费更多时间。
模型类
public class Field : ObservableObject
{
private string _name;
private string _value;
private bool _flag;
public string Name { get => _name; set => Set(ref _name, value); }
public string Value { get => _value; set => Set(ref _value, value); }
public bool Flag { get => _flag; set => Set(ref _flag, value); }
}
MainViewModel
public class MainViewModel : ViewModelBase
{
private int _fieldcount;
private ObservableCollection<Models.Field> _fields;
public MainViewModel()
{
if (IsInDesignMode)
{
_fieldcount = 100;
}
else
{
_fieldcount = 1000000;
}
Initialize();
}
private void Initialize()
{
var fieldquery = Enumerable.Range(1, _fieldcount).Select(e => new Models.Field { Name = $"Field {e}", Value = $"Value {e}", Flag = false, });
Fields = new ObservableCollection<Models.Field>(fieldquery);
}
public ObservableCollection<Models.Field> Fields { get => _fields; set => Set(ref _fields, value); }
}
视图
<Window x:Class="WpfApp6.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:models="clr-namespace:WpfApp6.Models"
xmlns:local="clr-namespace:WpfApp6"
mc:Ignorable="d"
DataContext="{Binding Source={StaticResource Locator}, Path=Main}"
Title="MainWindow" Height="350" Width="525">
<Grid>
<ItemsControl VirtualizingStackPanel.IsVirtualizing="True"
ScrollViewer.CanContentScroll="True"
ItemsSource="{Binding Path=Fields}">
<ItemsControl.ItemTemplate>
<DataTemplate DataType="{x:Type models:Field}">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0" Text="{Binding Name}" />
<TextBox Grid.Column="1" Text="{Binding Value}" IsReadOnly="True"/>
</Grid>
</DataTemplate>
</ItemsControl.ItemTemplate>
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<VirtualizingStackPanel />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.Template>
<ControlTemplate>
<Border BorderThickness="{TemplateBinding Border.BorderThickness}"
Padding="{TemplateBinding Control.Padding}"
BorderBrush="{TemplateBinding Border.BorderBrush}"
Background="{TemplateBinding Panel.Background}"
SnapsToDevicePixels="True">
<ScrollViewer Padding="{TemplateBinding Control.Padding}" Focusable="False">
<ItemsPresenter SnapsToDevicePixels="{TemplateBinding UIElement.SnapsToDevicePixels}" />
</ScrollViewer>
</Border>
</ControlTemplate>
</ItemsControl.Template>
</ItemsControl>
</Grid>
</Window>
整个项目是here