WPF DataGrid TemplateColumn - 滚动导致奇怪的效果

时间:2018-01-18 10:09:25

标签: c# wpf scroll datagrid datagridtemplatecolumn

我的数据网格中有一个奇怪的效果。在此示例中,datagrid有200行,第一列有递增索引。 datagrid有一个MaxHeight属性,所以我只看到加载前30行。

我可以向下滚动200行,但我从未在第一列中看到数字30-200只重复0-29!?! (我检查了该集合是否具有正确的值)

如果我将DataGridTemplateColumn中的列更改为DataGridTextColumn,我会看到所有值,但这不是我想要的。

有人知道,为什么单元格内容没有显示正确的值?

这是我的代码。这是大型MVVM项目的简化示例。请对这种结构宽容。

    <Window.Resources>
    <local:RowCellConverter x:Key="rcconv" />
    <DataTemplate DataType="{x:Type local:BusinessDataGrid}">
        <Grid
            Margin="5"
            HorizontalAlignment="Stretch"
            VerticalAlignment="Stretch"
            Background="Transparent"
            Focusable="False"
            Visibility="Visible">
            <DataGrid
                Name="dataGrid"
                Height="700"
                MaxHeight="600"
                AutoGenerateColumns="False"
                CanUserAddRows="False"
                CanUserDeleteRows="False"
                CanUserReorderColumns="False"
                CanUserResizeColumns="True"
                CanUserResizeRows="False"
                CanUserSortColumns="False"
                ColumnWidth="*"
                EnableColumnVirtualization="True"
                EnableRowVirtualization="True"
                Initialized="dataGrid_Initialized"
                ItemsSource="{Binding rows}"
                ScrollViewer.CanContentScroll="True"
                ScrollViewer.HorizontalScrollBarVisibility="Auto"
                ScrollViewer.VerticalScrollBarVisibility="Auto"
                SelectionMode="Single"
                SelectionUnit="CellOrRowHeader">
                <DataGrid.Resources>
                    <DataTemplate x:Key="MyFieldCell" DataType="DataGridTemplateColumn">
                        <StackPanel>
                            <TextBlock Background="LightSalmon">Hallo</TextBlock>
                            <TextBox
                                x:Name="TableCell"
                                DataContext="{Binding RelativeSource={RelativeSource AncestorType=DataGridCell}, Converter={StaticResource rcconv}}"
                                IsReadOnly="False"
                                Background="{Binding Path=StateColor}"
                                Text="{Binding Path=MyValue}" />
                        </StackPanel>
                    </DataTemplate>
                </DataGrid.Resources>
            </DataGrid>
        </Grid>
    </DataTemplate>
</Window.Resources>
<Grid>
    <ItemsControl Name="iControl" ItemsSource="{Binding Path=MainWindow.bFields}" />
</Grid>

背后的代码:

    public partial class MainWindow : Window
{
    public ObservableCollection<BusinessField> bFields = new ObservableCollection<BusinessField>();
    public MainWindow()
    {
        BusinessDataGrid bdg = new BusinessDataGrid();
        foreach (string col in new string[] { "Col1", "Col2", "Col3", "Col4", "Col5", "Col6", })
        {
            bdg.cols.Add(col);
        }
        for (int i = 0; i < 200; i++)
        {
            FieldRow fr = new FieldRow();
            foreach(string col in bdg.cols)
            {
                FieldCell fc = new FieldCell();
                fc.MyValue = string.Format("{0:000}{1}", i, col);
                fr.cells.Add(fc);
            }
            bdg.rows.Add(fr);
        }
        InitializeComponent();
        ItemsControl ic = iControl;
        ic.ItemsSource = bFields;
        bFields.Add(bdg);
    }

    private void dataGrid_Initialized(object sender, EventArgs e)
    {
        DataGrid dg = sender as DataGrid;
        if (dg != null)
        {
            BusinessDataGrid bdg = dg.DataContext as BusinessDataGrid;
            if (bdg != null)
                bdg.OnUIInitialized(dg);
        }
    }
}
public class BusinessField : INotifyPropertyChanged
{
    private PropertyChangedEventHandler propertyChangedEvent;
    public void SendPropertyChanged(string propertyName)
    {
        VerifyCalledOnUIThread();
        if (propertyChangedEvent != null)
            propertyChangedEvent(this, new PropertyChangedEventArgs(propertyName));
    }

    public event PropertyChangedEventHandler PropertyChanged
    {
        add
        {
            VerifyCalledOnUIThread();
            propertyChangedEvent += value;
        }
        remove
        {
            VerifyCalledOnUIThread();
            propertyChangedEvent -= value;
        }
    }
    [Conditional("Debug")]
    protected void VerifyCalledOnUIThread()
    {
        Debug.Assert(Dispatcher.CurrentDispatcher == Dispatcher.CurrentDispatcher, "Call must be made on UI thread.");
    }
}

public class BusinessDataGrid:BusinessField
{
    public List<string> cols = new List<string>();
    public ObservableCollection<FieldRow> rows = new ObservableCollection<FieldRow>();

    public void OnUIInitialized(DataGrid datagrid)
    {
        DataTemplate dt = (DataTemplate)datagrid.Resources["MyFieldCell"];
        datagrid.Columns.Clear();
        foreach(string col in cols)
        {
            DataGridTemplateColumn dgtc = new DataGridTemplateColumn()
            {
                CellTemplate = dt,
                Visibility = Visibility.Visible,
                Header = col,
                SortMemberPath=col,
            };
            datagrid.Columns.Add(dgtc);
        }
        datagrid.ItemsSource = rows;
    }

}

public class RowCellConverter : IValueConverter
{
    #region IValueConverter Members

    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        DataGridCell cell = value as DataGridCell;

        if((string)parameter == "FieldCell")
        {

        }
        if (cell == null)
            return null;
        DataGridCellsPresenter dgcp = TreeHelper.GetVisualParent<DataGridCellsPresenter>(cell);

        int ci = dgcp.ItemContainerGenerator.IndexFromContainer(cell);
        FieldRow fr = cell.DataContext as FieldRow;
        if (fr == null)
            return null;

        object ret = null;
        switch((string)parameter)
        {
            case "StateColor":
                ret = fr.cells[ci].StateColor;
                break;
            case "MyValue":
                ret = fr.cells[ci].MyValue;
                break;
            default:
                ret = fr.cells[ci];
                break;
        }
        return ret;
    }

    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}
public class TreeHelper
{
    #endregion
    public static T GetVisualChild<T>(DependencyObject obj) where T : DependencyObject
    {
        for (int i = 0; i < VisualTreeHelper.GetChildrenCount(obj); i++)
        {
            DependencyObject child = VisualTreeHelper.GetChild(obj, i);
            if (child != null && child is T)
                return (T)child;
            else
            {
                T childOfChild = GetVisualChild<T>(child);
                if (childOfChild != null)
                    return childOfChild;
            }
        }
        return null;
    }

    public static T GetVisualParent<T>(DependencyObject child) where T : DependencyObject
    {
        //get parent item
        DependencyObject parentObject = VisualTreeHelper.GetParent(child);    //we’ve reached the end of the tree
        if (parentObject == null) return null;

        //check if the parent matches the type we’re looking for
        T parent = parentObject as T;
        if (parent != null)
            return parent;
        else
            return GetVisualParent<T>(parentObject);
    }
}
public enum FieldCellState
{
    Ok,
    Error
}

public class FieldRow
{
    public ObservableCollection<FieldCell> cells = new ObservableCollection<FieldCell>();
}
public class FieldCell : INotifyPropertyChanged
{
    public string Colname;
    private string myValue;

    public override string ToString()
    {
        return MyValue;
    }

    public string MyValue
    {
        get { return myValue; }
        set { myValue = value; }
    }
    public FieldCellState MyState
    {
        get { return (MyValue.Contains("7")) ? FieldCellState.Error : FieldCellState.Ok; }
    }
    public Brush StateColor
    {
        get { return (MyState == FieldCellState.Ok) ? new SolidColorBrush(Colors.LightGreen) : new SolidColorBrush(Colors.LightSalmon); }
    }
    private PropertyChangedEventHandler propertyChangedEvent;
    public void SendPropertyChanged(string propertyName)
    {
        VerifyCalledOnUIThread();
        if (propertyChangedEvent != null)
            propertyChangedEvent(this, new PropertyChangedEventArgs(propertyName));
    }

    public event PropertyChangedEventHandler PropertyChanged
    {
        add
        {
            VerifyCalledOnUIThread();
            propertyChangedEvent += value;
        }
        remove
        {
            VerifyCalledOnUIThread();
            propertyChangedEvent -= value;
        }
    }
    [Conditional("Debug")]
    protected void VerifyCalledOnUIThread()
    {
        Debug.Assert(Dispatcher.CurrentDispatcher == Dispatcher.CurrentDispatcher, "Call must be made on UI thread.");
    }
}

2 个答案:

答案 0 :(得分:0)

这是因为你启用了这两个选项

EnableColumnVirtualization="True"
EnableRowVirtualization="True"

它会尝试为您虚拟化它。尝试将它们设为False,看看你是否能正确看到你的内容。请记住将它们设置为false会导致DataGrid加载速度变慢。

尝试为每列执行此操作,而不是在资源级别创建模板。这只是一个例子,您可以根据自己的风格进行调整。

                <DataGridTemplateColumn Header="Some Name" IsReadOnly="False" Width="*">
                    <DataGridTemplateColumn.CellTemplate>
                        <DataTemplate>
                            <RichTextBox>
                                <FlowDocument IsOptimalParagraphEnabled="True" IsHyphenationEnabled="True">
                                    <Paragraph FontFamily="Segoe UI" FontSize="14">
                                        <Run Text="{Binding Path=First ,Mode=TwoWay , UpdateSourceTrigger=PropertyChanged}" />
                                        <Run Text="{Binding Path=FirstText ,Mode=TwoWay , UpdateSourceTrigger=PropertyChanged}" />
                                        <Run Text="{Binding Path=SearchedText ,Mode=TwoWay , UpdateSourceTrigger=PropertyChanged}" Background="#FFE34C"/>
                                        <Run Text="{Binding Path=SecondText ,Mode=TwoWay , UpdateSourceTrigger=PropertyChanged}" />
                                    </Paragraph>
                                </FlowDocument>
                            </RichTextBox>
                        </DataTemplate>
                    </DataGridTemplateColumn.CellTemplate>
                </DataGridTemplateColumn>

答案 1 :(得分:-1)

好像你在使用第三方网格?问题是如何虚拟化

我有一次这个问题,原因是我正在使用网格的标识列,因此该列是自动生成的。

网格正在虚拟化,因此无法计算视图上方或下方的行数。

如果你不需要它可以停止虚拟化(200行左右不会有任何区别)

或添加一个绑定到集合中项目索引的新列,该列应该可以正常工作