注意:问题与Bind Objects with generic list to wpf datagrid相同(未回答),该问题要求提供涉及CellTemplates的解决方案,并且不包含任何解决方法。我愿意接受任何解决方案,并且有一个可行的(但非理想的)解决方案。
设置是我有一个对象列表(人),每个对象列表都包含一个数据对象列表。
class Person : List<DataObject>
{
public string id { get; set; }
}
class DataObject
{
public string columnName { get; set;}
public string value { get; set;}
}
columnNames基于用户输入,但是每个人在其DataObjects列表中都具有相同的columnNames(即,它们都具有firstName列,lastName列,dateOfBirth列,均具有不同的值)。
我想以DataGrid格式显示这些值,以便用户可以编辑这些值。
我目前正在使用的是网格(editGrid),并为每个列标题添加子TextBlocks,然后循环遍历各项以为每个单元格添加TextBoxes。这适用于少量数字,但是当我有成千上万的人时,由于创建的TextBox和TextBlocks数量庞大,程序会滞后。
List<People> items;
List<string> columnHeaders;
Grid editGrid;
// Generate column headers
editGrid.RowDefinitions.Add(new RowDefinition() { Height = GridLength.Auto });
var columns = items.SelectMany(o => o.Select(a => a.columnName)).Distinct(StringComparer.OrdinalIgnoreCase);
foreach (string text in columns)
{
TextBlock headerText = new TextBlock();
headerText.Text = text;
Grid.SetColumn(headerText, editGrid.ColumnDefinitions.Count());
editGrid.ColumnDefinitions.Add(new ColumnDefinition() { Width = GridLength.Auto });
columnHeaders.Add(text);
editGrid.Children.Add(headerText);
}
// Create rows
foreach (var item in items)
{
foreach (var dataObject in item)
{
var columnNum = columnHeaders.IndexOf(dataObject.columnName);
if (columnNum != -1)
{
TextBox valueBox = new TextBox();
Binding bind = new Binding();
bind.Source = dataObject;
bind.Mode = BindingMode.TwoWay;
bind.Path = new PropertyPath("value");
BindingOperations.SetBinding(valueBox , TextBox.TextProperty, bind);
Grid.SetColumn(valueBox, columnNum);
Grid.SetRow(valueBox, editGrid.RowDefinitions.Count);
editGrid.Children.Add(valueBox);
}
}
editGrid.RowDefinitions.Add(new RowDefinition() { Height = GridLength.Auto });
}
答案 0 :(得分:1)
您是否考虑过使用ItemsControl创建DataGrid效果?像这样:
<ItemsControl ItemsSource="{Binding}" Name="IC1" VirtualizingStackPanel.IsVirtualizing="True" ScrollViewer.CanContentScroll="True">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<VirtualizingStackPanel />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.Template>
<ControlTemplate>
<Border
BorderThickness="{TemplateBinding Border.BorderThickness}"
Padding="{TemplateBinding Control.Padding}"
BorderBrush="{TemplateBinding Border.BorderBrush}"
Background="{TemplateBinding Panel.Background}"
SnapsToDevicePixels="True">
<ScrollViewer
Padding="{TemplateBinding Control.Padding}"
Focusable="False">
<ItemsPresenter
SnapsToDevicePixels="{TemplateBinding UIElement.SnapsToDevicePixels}" />
</ScrollViewer>
</Border>
</ControlTemplate>
</ItemsControl.Template>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="1*" />
<ColumnDefinition Width="9*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<TextBlock Text="ID" Grid.Column="0" Grid.Row="0"/>
<TextBlock Grid.Column="0" Grid.Row="1" Text="{Binding Path=id}"/>
<ItemsControl Grid.Column="1" Grid.Row="0" Grid.RowSpan="2" ItemsSource="{Binding}" >
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<StackPanel>
<TextBlock Text="{Binding Path=columnName}" Width="100" />
<TextBox Text="{Binding Path=value}" Width="100" />
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Grid>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
我填充了一些测试数据(很抱歉,但在VB中):
Property PersonList As New ObservableCollection(Of Person)
Private Sub MainWindow_Loaded(sender As Object, e As RoutedEventArgs) Handles Me.Loaded
For x As Integer = 1 To 500
Dim P1 As New Person With {.id = "SE" & x}
P1.Add(New DataObject With {.columnName = "First Name", .value = "Simon"})
P1.Add(New DataObject With {.columnName = "Last Name", .value = "Evans"})
P1.Add(New DataObject With {.columnName = "DOB", .value = "03/03/1980"})
Dim P2 As New Person With {.id = "RE" & x}
P2.Add(New DataObject With {.columnName = "First Name", .value = "Ruth"})
P2.Add(New DataObject With {.columnName = "Last Name", .value = "Evans"})
P2.Add(New DataObject With {.columnName = "DOB", .value = "11/02/1979"})
PersonList.Add(P1)
PersonList.Add(P2)
Next
IC1.DataContext = PersonList
End Sub
那是1,000行,但是因为控件使用虚拟化,所以没有延迟。
编辑
不知道这是否是最好的方法,但是我建议向您的DataObject类添加一个Int width属性,并将第二个ItemsControl中的TextBlocks和TextBoxes的宽度绑定到此。
>然后使用下面的代码片段计算所需的最大宽度(对WPF equivalent to TextRenderer表示敬意):
public static Size MeasureTextSize(string text, FontFamily fontFamily, FontStyle fontStyle, FontWeight fontWeight, FontStretch fontStretch, double fontSize)
{
FormattedText ft = new FormattedText(text,
CultureInfo.CurrentCulture,
FlowDirection.LeftToRight,
new Typeface(fontFamily, fontStyle, fontWeight, fontStretch),
fontSize,
Brushes.Black);
return new Size(ft.Width, ft.Height);
}
(我使用了Window的字体详细信息,但是,如果要设置文本框的样式,当然可以指定其他详细信息。)
然后我写了一点以浏览数据并设置宽度(对不起,回到VB):
If PersonList.Count > 0 Then
Dim MaxLengths(PersonList(0).Count - 1) As Integer
For i As Integer = 0 To MaxLengths.Count - 1
MaxLengths(i) = 70 'Set Minimum width to accomodate Headers
Next
For Each P As Person In PersonList
For i As Integer = 0 To P.Count - 1
Dim BoxSize As Size = MeasureTextSize(P(i).value, FontFamily, FontStyle, FontWeight, FontStretch, FontSize)
If BoxSize.Width > MaxLengths(i) Then MaxLengths(i) = BoxSize.Width + 6 'to allow for padding
Next
Next
For Each P As Person In PersonList
For i As Integer = 0 To P.Count - 1
P(i).width = MaxLengths(i)
Next
Next
End If