none
DataGrid显示隐藏行内存增大、卡顿问题 RRS feed

  • 问题

  • 通过DataGridRow的Visibility属性绑定实现行的显示隐藏,隐藏时没问题,但在显示时内存一直增大,比重新绑定性能差很多,感觉DataGrid的虚拟化失效了,写了个简单的demo,也是如此,看了下DataGridRow的源码,没发现和虚拟化相关的代码,那应该怎么处理这个问题? 是否有可以通过设置某个属性来解决?

            <DataGrid VerticalAlignment="Top" Name="dg"
                      EnableColumnVirtualization="True"
                      EnableRowVirtualization="True"
                      CanUserAddRows="False"
                      AutoGenerateColumns="False">
                <DataGrid.RowStyle>
                    <Style TargetType="DataGridRow">
                        <Setter Property="Visibility" Value="{Binding isVisible}"/>
                    </Style>
                </DataGrid.RowStyle>
                <DataGrid.Columns>
                    <DataGridTextColumn Header="序号" Binding="{Binding index}" Width="0.2*"/>
                    <DataGridTextColumn Header="名称" Binding="{Binding Name}" Width="0.4*"/>
                    <DataGridTextColumn Header="号码" Binding="{Binding PhoneNum}" Width="0.4*"/>
                </DataGrid.Columns>
            </DataGrid>

    namespace WpfDataGrid
    {
        /// <summary>
        /// MainWindow.xaml 的交互逻辑
        /// </summary>
        public partial class MainWindow : Window
        {
            List<Model> mlist;
            public MainWindow()
            {
                InitializeComponent();
    
                mlist = new List<Model>();
                
                for(int i=0;i<100*50;i++)
                {
                    var m = new Model();
                    m.index = i;
                    m.Name = "测试数据测试数据测试数据测试数据测试数据测试数据测试数据"+i;
                    m.PhoneNum = i+"测试数据测试数据测试数据测试数据测试数据测试数据测试数据";
                    mlist.Add(m);
                }
            }
    
            private void Button_Click(object sender, RoutedEventArgs e)
            {
                var btn = sender as Button;
                var tag = btn.Tag as string;
                switch (tag)
                {
                    case "init":
                        dg.ItemsSource = mlist;
                        break;
                    case "hide":
                        for (int i = 3; i < mlist.Count; i++)
                        {
                            mlist[i].isVisible = Visibility.Collapsed;
                        }
                        break;
                    case "show":
                        for (int i = 3; i < mlist.Count; i++)
                        {
                            mlist[i].isVisible = Visibility.Visible;
                        }
                        break;
                }
                
            }
        }
    
        public class Model:INotifyPropertyChanged
        {
            public int index { get; set; }
            public string Name { get; set; }
            public string PhoneNum { get; set; }
    
            Visibility _isVisible;
            public Visibility isVisible
            {
                get
                {
                    return _isVisible;
                }
                set
                {
                    _isVisible = value;
                    OnPropertyChanged("isVisible");
                }
            }
    
            public event PropertyChangedEventHandler PropertyChanged;
    
            protected void OnPropertyChanged(string name)
            {
                if (PropertyChanged == null)
                    return;
                PropertyChanged(this, new PropertyChangedEventArgs(name));
            }
        }
    }

    2020年7月30日 2:29

答案

  • 你好,

    你的隐藏部分的代码有问题,你错用了Collapsed去隐藏数据,你应该用Hidden,你应该把隐藏部分的代码改为:

    case "hide":
                        for (int i = 3; i < mlist.Count; i++)
                        {
                            mlist[i].isVisible = Visibility.Hidden;
                        }

    Collapsed 不显示元素,并且不在布局中为它保留空间,所以mlist.Count会不断变化for循环会发生死循环。Hidden不显示元素,但是在布局中为元素保留空间。所以你应该使用Hidden。

    谢谢

    Daisy Tian


    MSDN Community Support
    Please remember to click "Mark as Answer" the responses that resolved your issue, and to click "Unmark as Answer" if not. This can be beneficial to other community members reading this thread. If you have any compliments or complaints to MSDN Support, feel free to contact MSDNFSF@microsoft.com.

    2020年8月6日 6:11

全部回复

  • 你好,

    一般内存过大会与虚拟化话有关,我发现你已经设置了EnableColumnVirtualization="True" 和EnableRowVirtualization="True"。于是我测试了你的demo,并没有发现项目占用过多问题或者内存持续增大的问题.下图是我运行你的demo并且等待39秒的结果:

    内存占用一直维持在70M左右。我是根据你所给的代码创建.Net framwork wpf 的项目直接测试的,所以如果我有遗漏复现问题的地方,请指出。

    Best regards

    Daisy  Tian


    MSDN Community Support
    Please remember to click "Mark as Answer" the responses that resolved your issue, and to click "Unmark as Answer" if not. This can be beneficial to other community members reading this thread. If you have any compliments or complaints to MSDN Support, feel free to contact MSDNFSF@microsoft.com.

    2020年7月30日 7:52
  • 需要先点一下隐藏,行隐藏,然后点显示。
    2020年7月31日 8:06
  • 后台绑定采用ICollectionView,用Filter实现了。

    但用这个模式就是不行,不知道有没有解决方案,问题先放着吧。

    2020年8月1日 0:55
  • 你好,

    你给的代码里边并没有图一中的显示,隐藏,加载三个按钮,所以我没有复现你的问题,如果可以的话,请你提供一下隐藏相关的代码,这样方便我复现你的问题。

    谢谢

    Daisy Tian


    MSDN Community Support
    Please remember to click "Mark as Answer" the responses that resolved your issue, and to click "Unmark as Answer" if not. This can be beneficial to other community members reading this thread. If you have any compliments or complaints to MSDN Support, feel free to contact MSDNFSF@microsoft.com.

    2020年8月3日 2:20
  • <Window x:Class="WpfDataGrid.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">
        <Grid>
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="*"/>
                <ColumnDefinition Width="100"/>
            </Grid.ColumnDefinitions>
            <DataGrid VerticalAlignment="Top" Name="dg"
                      EnableColumnVirtualization="True"
                      EnableRowVirtualization="True"
                      CanUserAddRows="False"
                      AutoGenerateColumns="False">
                <DataGrid.RowStyle>
                    <Style TargetType="DataGridRow">
                        <Setter Property="Visibility" Value="{Binding isVisible}"/>
                    </Style>
                </DataGrid.RowStyle>
                <DataGrid.Columns>
                    <DataGridTextColumn Header="序号" Binding="{Binding index}" Width="0.2*"/>
                    <DataGridTextColumn Header="名称" Binding="{Binding Name}" Width="0.4*"/>
                    <DataGridTextColumn Header="号码" Binding="{Binding PhoneNum}" Width="0.4*"/>
                </DataGrid.Columns>
            </DataGrid>
            <Button Content="隐藏" Name="btnhide" HorizontalAlignment="Left" Margin="15,51,0,0" VerticalAlignment="Top" Width="75" Grid.Column="1" Click="Button_Click" Tag="hide"/>
            <Button Content="显示" Name="btnshow" Grid.Column="1" HorizontalAlignment="Left" Margin="15,87,0,0" VerticalAlignment="Top" Width="75" Click="Button_Click" Tag="show"/>
            <Button Content="加载" Name="btninit" Grid.Column="1" HorizontalAlignment="Left" Margin="15,17,0,0" VerticalAlignment="Top" Width="75" Click="Button_Click" Tag="init"/>
    
        </Grid>
    </Window>


    2020年8月3日 2:32
  • 你好,

    你的隐藏部分的代码有问题,你错用了Collapsed去隐藏数据,你应该用Hidden,你应该把隐藏部分的代码改为:

    case "hide":
                        for (int i = 3; i < mlist.Count; i++)
                        {
                            mlist[i].isVisible = Visibility.Hidden;
                        }

    Collapsed 不显示元素,并且不在布局中为它保留空间,所以mlist.Count会不断变化for循环会发生死循环。Hidden不显示元素,但是在布局中为元素保留空间。所以你应该使用Hidden。

    谢谢

    Daisy Tian


    MSDN Community Support
    Please remember to click "Mark as Answer" the responses that resolved your issue, and to click "Unmark as Answer" if not. This can be beneficial to other community members reading this thread. If you have any compliments or complaints to MSDN Support, feel free to contact MSDNFSF@microsoft.com.

    2020年8月6日 6:11
  • 果然如此,感谢感谢,不卡顿了。

    时间有点久了,但还有个问题,Hidden的话纵向滚动条是不会消失的,因为布局还在。

    2020年9月11日 6:27
  • 你好,

    你可以手动设置你的DataGrid的ScrollViewer的ScrollBar是否可见,我此处只提供一个简单的示例,具体如设置,需要根据你的具体需求设置。顺便提一句,这是一个新的问题,最好重新开一个问题进行询问。

     case "hide":
                        for (int i = 3; i < mlist.Count; i++)
                        {
                            mlist[i].isVisible = Visibility.Hidden;
                            ScrollViewer sv1 = VisualTreeHelper.GetChild(VisualTreeHelper.GetChild(dg, 0), 0) as ScrollViewer;
                            sv1.VerticalScrollBarVisibility = ScrollBarVisibility.Hidden;
                        }
                        break;

    谢谢

    Daisy Tian


    MSDN Community Support
    Please remember to click "Mark as Answer" the responses that resolved your issue, and to click "Unmark as Answer" if not. This can be beneficial to other community members reading this thread. If you have any compliments or complaints to MSDN Support, feel free to contact MSDNFSF@microsoft.com.

    2020年9月11日 7:29