RowVirtualization cause incorrect background color for rows

牧云@^-^@ 提交于 2019-11-28 06:28:29

问题


I have a WPF application and there is a Datagrid in some pages. This datagrid needs to load 5000 rows at once (Pagination is not an option for me) and this takes ages. I set EnableRowVirtualization=True and the performance is acceptable now, but there is a problem here. In my datagrid I need to set different background colors to different rows depending on a column value (say STATUS), changing EnableRowVirtualization from False to True, caused incorrect coloring when I scroll.

----Edit----

Here is my XAML code:

<my:DataGrid Name="dgDataGrid" DockPanel.Dock="Top" AutoGenerateColumns="False"  ClipboardCopyMode="ExcludeHeader" 
                     CanUserDeleteRows="True" RowHeight="20" SelectionMode="Extended"  SelectionUnit="FullRow" FontFamily="Tahoma" 
                     ItemsSource="{Binding}"  VirtualizingStackPanel.VirtualizationMode="Recycling" VirtualizingStackPanel.IsVirtualizing="True" 
                     EnableRowVirtualization="True" EnableColumnVirtualization="False" IsSynchronizedWithCurrentItem="True" BorderBrush="Blue"  
                     RowBackground="White" HorizontalGridLinesBrush="Blue"  GridLinesVisibility="Horizontal" VerticalGridLinesBrush="Blue"  
                     IsTextSearchEnabled="False" IsTabStop="True" HeadersVisibility="All" Loaded="dgDataGrid_Loaded"  
                     ContextMenuOpening="dgDataGrid_ContextMenuOpening" LoadingRow="dgDataGrid_LoadingRow" 
                     ScrollViewer.IsDeferredScrollingEnabled ="True">
            <my:DataGrid.Resources>

            </my:DataGrid.Resources>

            <my:DataGrid.RowHeaderTemplate>
                <DataTemplate>
                    <TextBlock Text="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type my:DataGridRow}}, Path=Header}"></TextBlock>
                </DataTemplate>
            </my:DataGrid.RowHeaderTemplate>
            <my:DataGrid.ColumnHeaderStyle>
                <Style TargetType="my:DataGridColumnHeader">
                    <Setter Property="ContentTemplate">
                        <Setter.Value>
                            <DataTemplate>
                                <TextBlock Text="{Binding}" Foreground="Blue"/>
                            </DataTemplate>
                        </Setter.Value>
                    </Setter>
                </Style>
            </my:DataGrid.ColumnHeaderStyle>

            <my:DataGrid.ContextMenu>
                <ContextMenu Name="cmDataGrid" StaysOpen="True">
                    <MenuItem Name="mnuView" Header="نمایش">
                        <MenuItem Name="mnuHideColumn"  Header="Hide Column" Click="mnuHideColumn_Click"/>
                        <MenuItem Name="mnuShowColumn" Header="Show Column"/>
                        <Separator/>
                        <MenuItem Name="mnuGroupByColumn" 
                          Header="Group by this column" Click="mnuGroupColumn_Click" />
                        <MenuItem Name="mnuClearGroups" 
                          Header="Clear grouping" Click="mnuGroupColumn_Click" />
                        <Separator/>
                        <MenuItem Header="Header Alignment">
                            <MenuItem Name="mnuHeaderCenter" Header="Center"/>
                            <MenuItem Name="mnuHeaderLeft" Header="Left"/>
                            <MenuItem Name="mnuHeaderRight" Header="Right"/>
                        </MenuItem>
                        <MenuItem Header="Content Alignment">
                            <MenuItem Name="mnuContentCenter" Header="Center"/>
                            <MenuItem Name="mnuContentLeft" Header="Left"/>
                            <MenuItem Name="mnuContentRight" Header="Right"/>
                        </MenuItem>
                    </MenuItem>
                </ContextMenu>
            </my:DataGrid.ContextMenu>
        </my:DataGrid>

and following codes do the bindings:

Note: all my columns are getting generated on the fly depends on the object requested to be loaded:

public static DataGridColumn CreateTextBoxWithBackgroudColumn(DataColumn dataCol, string columnName)
        {
            DataGridTemplateColumn dgtc = new DataGridTemplateColumn();
            dgtc.Header = columnName;
            dgtc.HeaderStyle = (Style)(App.Current as App).FindResource("ColumnHeaderStyle");

            FrameworkElementFactory cellTemplateFactory = new FrameworkElementFactory(typeof(TextBlock));
            Binding dataBinding = new Binding(dataCol.ColumnName);
            dataBinding.Mode = BindingMode.TwoWay;
            dataBinding.UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged;

            dataBinding.Converter = new BackGroundConverter();

            cellTemplateFactory.SetBinding(TextBlock.BackgroundProperty, dataBinding);
            DataTemplate cellTemplate = new DataTemplate();
            cellTemplate.VisualTree = cellTemplateFactory;
            cellTemplate.Seal();
            dgtc.CellTemplate = cellTemplate;

            return dgtc;
        }

The returned DataGridColumn will be added to my DataGrid columns.

Is that possible to have both RowVirtualization and coloring at the same time?

Thanks.


回答1:


This may be a bit too late for you since you apparently found a working solution for you, but hopefully it can help others. I had a similar problem just now and after some googling found out that the reason for this behaviour is that the default value for VirtualizationMode is Recycling. This means that item containers are reused and thus the coloring of the background will stick even if the item that occupies the container after scrolling says it should not be colored.

To solve this simply set the VirtualizationMode to Standard, like so:

<DataGrid VirtualizingStackPanel.VirtualizationMode="Standard" />

The containers will then be recreated and destroyed when you scroll, applying any changes you do in the LoadingRow event.




回答2:


Well as Eirik said it might be too late. but i would be glad if it can help others. You can do this EnableRowVirtualization = "True" (so it won't affect your performance in case of large data). And just code this on dgOrders_LoadingRow event.

private void dgOrders_LoadingRow(object sender, DataGridRowEventArgs e)
{

        OrderDetail item = e.Row.Item as OrderDetail; //parse data into your bject type which is 
        if (item != null)
        {
             if (item.Note== "Loss") //your condition
             {
                 e.Row.Background = Brushes.Red;
             }
             else                    //otherwise default color
             {
                 e.Row.Background = Brushes.White;
             }
        }
    }



回答3:


As RowVirtualization is not working well for row background coloring, I added a column and colored it instead of whole row.



来源:https://stackoverflow.com/questions/17133286/rowvirtualization-cause-incorrect-background-color-for-rows

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!