简体   繁体   中英

How to speed up the following WPF UI code

I am trying to understand why my following WPF C# code, that I use to display a kind of grid view of my input information, is so slow, and especially how to improve it in order to speed up the controls rendering.

I have the following input, that can vary according to the user selection:

public class Field
{
    public string Key;
    public Tuple<string, bool> Value;
}


var fields = new List<Field>();
// fill fields...

And for each field I create a control that is inserted into a 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;
}

The number of fields is between 1000-2000 on average. On my machine filling up the VirtualizingStackPanel can require even more than 1 second; I haven't measured this time, but it is clear that it's very slow for the user.

I have no problems presenting 1.000.000 items (and even more) and it will take more time to create the data collection then presenting it.

Model class

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); }

}

The View

<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>

The whole project is here

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM