【问题标题】:slow loading of controls inside wpf container gridwpf容器网格内的控件加载缓慢
【发布时间】:2017-08-04 03:47:30
【问题描述】:

我正在创建基于某些对象的动态 UI,并且由于要呈现大量项目,因此加载需要很长时间。 见下面的xml:-

 <ScrollViewer Grid.Row="2" ZoomMode="Enabled" x:Name="scrollviewer"  
        VirtualizingStackPanel.VirtualizationMode="Recycling"
        HorizontalScrollMode="Auto"
        VerticalScrollMode="Auto"
        VerticalSnapPointsType="None"
        HorizontalSnapPointsType="None"
        HorizontalScrollBarVisibility="Auto"
        VerticalScrollBarVisibility="Auto"
        MinZoomFactor="1" IsDoubleTapEnabled="True"
        RenderTransformOrigin="0,0">
        <Grid Background="#FFDDE6EB" x:Name="mygrid" VerticalAlignment="Center" HorizontalAlignment="Center">

        </Grid>
    </ScrollViewer>

滚动查看器位于高度为 10* 的行内。

动态加载项目的代码如下:-

  public static Grid LoadGridWithItems(Model m)
        {

            var grid = new Grid();
            grid.UseLayoutRounding = true;
            grid.RowDefinitions.Clear();
            grid.ColumnDefinitions.Clear();

            int count = m.Rows;
            for (int i = 0; i < count; i++)
            {
                grid.RowDefinitions.Add(new RowDefinition() { Height = new GridLength(1, GridUnitType.Auto) });
            }

            count = m.Columns;
            for (int i = 0; i < count; i++)
            {
                grid.ColumnDefinitions.Add(new ColumnDefinition() { Width = new GridLength(m.GetColumnWidth(i), GridUnitType.Star) });
            }
            foreach (Control control in m.Controls)
            {
          UIElement uicontrol=null;
                if (control.Type != null)
                {

                    switch (control.Type.ToLower())
                    {
                        case "textbox":
                             uicontrol=new TextBox();
                            break;
                        case "label":
                            uicontrol = new Label();;
                            break;

                      //bunch of other custom controls
                    }
                  }


                grid.Children.Add(uicontrol);
            }
            return grid;
        }

然后将此生成的网格作为子项添加到上述 xaml 中定义的“mygrid”中。有时项目超过 5000 个,加载大约需要 20-25 秒。 有关如何以更好的方式实施此方案的任何建议?

谢谢!

【问题讨论】:

  • 有什么理由不使用 MvvM?我之所以问,是因为如果您的要求允许,您可以将 ListViewVirtualization 一起使用,这意味着它只会在项目被带到查看时创建项目。这将显着提升性能,因为它将渲染 100 个项目而不是 5000 个。
  • 不能使用 mvvm 的唯一原因是因为每一行都有不同的控制组合,因此我没有可以使用的单一数据模板。添加到网格的控件仍然绑定到“控件”类中的属性,但只是我不确定如何为每一行生成不同的模板。
  • 查看TemplateSelector,您将能够选择要应用的模板,如果您将容器更改为ListView,那么您可以使用前面提到的Virtualization

标签: c# wpf performance xaml scrollviewer


【解决方案1】:

我们有同样的添加子控件的缓慢问题。一个可能的原因是它们是自下而上(在树中)添加的,而自上而下添加它们的速度非常快。这一切都在以下站点中进行了解释: https://docs.microsoft.com/en-us/dotnet/framework/wpf/advanced/optimizing-performance-layout-and-design 从中链接的页面是如何充分利用 WPF 的金矿。

【讨论】:

    【解决方案2】:

    如果您使用 ItemsControl 和 MVVM,您可以提高代码质量和可读性。此外,我认为性能会得到提升。像这样的:

    <ItemsControl ItemsSource="{Binding yourControlCollection}">
      <!-- Templates for your controls -->
      <ItemsControl.Resources>
        <DataTemplate DataType="{x:Type yourNameSpace:ComboBoxControl}">
            <ComboBox />
        </DataTemplate>
    
        <DataTemplate DataType="{x:Type yourNameSpace:TextControl}">
            <TextBox />
        </DataTemplate>
      </ItemsControl.Resources>
    </ItemsControl>
    

    此外,您可以更轻松地获取用户在表单中引入的值。您可以将值绑定到模型类中的属性,并且您拥有它。

    public class TextControl
    {
      public string TextValue { get; set; }
    }
    

    .

    <DataTemplate DataType="{x:Type yourNameSpace:TextControl}">
      <TextBox Text="{Binding TextValue}" />
    </DataTemplate>
    

    编辑。示例:

    xaml:

    <Window x:Class="WpfApplication2.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:WpfApplication2"
        Title="MainWindow" Height="350" Width="525">
    <ItemsControl ItemsSource="{Binding List}">
        <ItemsControl.Resources>
            <DataTemplate DataType="{x:Type local:ControlText}">
                <StackPanel Orientation="Horizontal" Background="Yellow">
                    <TextBlock Text="{Binding Label}" />
                    <TextBlock Text="{Binding Text}" />
                </StackPanel>
            </DataTemplate>
    
            <DataTemplate DataType="{x:Type local:ControlBool}">
                <StackPanel Orientation="Horizontal" Background="Orange">
                    <TextBlock Text="{Binding Label}" />
                    <CheckBox IsChecked="{Binding Value}" />
                </StackPanel>
            </DataTemplate>
    
        </ItemsControl.Resources>
    </ItemsControl>
    

    cs:

    using System;
    using System.Collections.Generic;
    using System.Windows;
    
    namespace WpfApplication2
    {
    public partial class MainWindow : Window
    {
        public IEnumerable<Control> List { get; set; }
    
        public MainWindow()
        {
            InitializeComponent();
    
            DataContext = this;
    
            var l = new List<Control>();
            l.Add(new ControlText() { Text = "Michael", Label = "Name" });
            l.Add(new ControlBool() { Value = true, Label = "C#" });
            l.Add(new ControlBool() { Value = false, Label = "WPF" });
            l.Add(new ControlText() { Text = "Martinez", Label= "Surname" });
    
            List = l;
        }
    }
    
    public abstract class Control
    {
        public String Label { get; set; }
    }
    
    public class ControlText : Control
    {
        public String Text { get; set; }
    }
    
    public class ControlBool : Control
    {
        public Boolean Value { get; set; }
    }
    }
    

    【讨论】:

    • 每一行都有不同的控件组合,因此无法使用单个数据模板,因此我使用这种方式来动态生成容器网格的内容。
    • 您可以拥有多个 DataTemplate,一个用于您在集合中拥有的每种类型的对象。
    • 抱歉,我只能将 ItemsControl 上的 DataTemplate 设置为单个模板;并且该特定模板将应用于 ItemsControl 中的所有行。我可以在哪里以及如何在 ItemsControl 上设置多个模板?
    猜你喜欢
    • 1970-01-01
    • 2013-02-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-07-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多