【发布时间】:2018-01-18 10:09:24
【问题描述】:
我的数据网格中有一个奇怪的效果。在此示例中,数据网格有 200 行,第一列有一个递增索引。数据网格有一个 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.");
}
}
【问题讨论】:
-
如果我使用我在调试器中看到的 DataGridTextColumn,滚动绑定后所有可见行都会调用,但如果我使用 DataGridTemplateColumn,这不会发生。
标签: c# wpf scroll datagrid datagridtemplatecolumn