简体   繁体   中英

Improving Winforms performance with large number of controls

Are there any ways to improve performance when constructing several forms with large numbers of controls (500+)?

Our controls are laid out in a label + 6 text box per row configuration, as shown below:

图片

We have used the following containers to structure our controls:

  • DevExpress' XtraLayoutControl
  • Panels around each row and moving manually
  • Common table control

We can't use a grid as the text boxes have to be hidden on a case-by-case basis and our forms have to look fairly close to the printouts. Also, each row has it's own data type, so we need to add validation and editors for each.

The table control is the most performant, where each form takes around 2 seconds to load.

As each of these will represent a document in our software and we allow users to open multiple documents at once, we are trying to find a way to improve the performance.

One suggestion was to cache the actual form and have a state object that stores the data. However, we allow the user to see more than one document at once.

Another suggestion was to load the document in parts and show each part as it becomes loaded. This isn't ideal as we are known for having a document that looks almost exactly like the printout.

Are there any other strategies available, or should we just bight the bullet at tell our customers that this program will be slower than it's VB6 predecessor?

An example of the form design we're redeveloping is here: Link

Complex datatype handling and stuff is to you, this is a 5 minute before-lunch sample to show how much winforms sucks and how much WPF rules:

namespace WpfApplication5
{

public partial class MainWindow : Window
{
    private List<Item> _items;
    public List<Item> Items
    {
        get { return _items ?? (_items = new List<Item>()); }
    }

    public MainWindow()
    {
        InitializeComponent();

        Items.Add(new Item() {Description = "Base metal Thickness"});

        for (var i = 32; i > 0; i--)
        {
            Items.Add(new Item() {Description = "Metal Specification " + i.ToString()});
        }

        Items.Add(new Item() { Description = "Base metal specification" });

        DataContext = this;
    }
}

public class Item: INotifyPropertyChanged
{
    private List<string> _values;
    public List<string> Values
    {
        get { return _values ?? (_values = new List<string>()); }
    }

    public event PropertyChangedEventHandler PropertyChanged;

    public string Description { get; set; }

    protected virtual void OnPropertyChanged(string propertyName)
    {
        var handler = PropertyChanged;
        if (handler != null) 
            handler(this, new PropertyChangedEventArgs(propertyName));
    }

    public Item()
    {
        Values.Add("Value1");
        Values.Add("Value2");
        Values.Add("Value3");
        Values.Add("Value4");
        Values.Add("Value5");
        Values.Add("Value6");
    }
}
}

XAML:

<Window x:Class="WpfApplication5.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525">
    <ItemsControl ItemsSource="{Binding Items}">
        <ItemsControl.ItemTemplate>
            <DataTemplate>
                <StackPanel Orientation="Horizontal">
                    <TextBlock Text="{Binding Description}" Width="130"/>
                    <ItemsControl ItemsSource="{Binding Values}">
                        <ItemsControl.ItemsPanel>
                            <ItemsPanelTemplate>
                                <StackPanel Orientation="Horizontal"/>
                            </ItemsPanelTemplate>
                        </ItemsControl.ItemsPanel>
                        <ItemsControl.ItemTemplate>
                            <DataTemplate>
                                <TextBox Text="{Binding Path=.}" Margin="2" Width="90"/>
                            </DataTemplate>
                        </ItemsControl.ItemTemplate>
                    </ItemsControl>
                </StackPanel>
            </DataTemplate>
        </ItemsControl.ItemTemplate>
    </ItemsControl>
</Window>

I see that you have several other requirements here, such as hiding texboxes and stuff. It doesn't matter if these rows are a different data type, you just need to do a ViewModel (which in this case would be my public class Item , which hold the data you want to show in the screen, and let the user be able to interact with.

For example, you could replace the List<string> inside the Item class with something more complex, and add some properties like public bool IsVisible {get;set;} and so on.

I strongly suggest you take a look at WPF (at least for this screen in particular).

Copy and paste my code in a new -> WPF project and you can see the results for yourself.

We can't use a grid as the text boxes have to be hidden on a case-by-case basis.

I don't understand why this precludes the use of a DataGridView . A specific DataGridViewCell can be made read-only by setting the ReadOnly property to true . You could then use the DataGridView.CellFormatting event to hide the value of the read-only cells. If I recall correctly, the code would be similar to this:

private void grid_CellFormatting(object sender, DataGridViewCellFormattingEventArgs e)
{
    DataGridView grid = (DataGridView)sender;
    if (grid[e.ColumnIndex, e.RowIndex].ReadOnly)
    {
        e.Value = string.Empty;
        e.FormattingApplied = true;
    }
}

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