我想在另一个DataGrid
行详细信息模板中添加单行DataGrid
。
这是我的 XAML:
<DataGrid x:Name="dataGrid" Margin="10,100,10,96" PreviewKeyDown="dataGrid_PreviewKeyDown" AutoGenerateColumns="False" ItemsSource="{Binding }" AlternatingRowBackground="AliceBlue" CellEditEnding="onCellEditEnding" SelectedItem="{Binding SelectedItem}" >
<DataGrid.Columns>
<DataGridTextColumn Width="*" Header="No" Binding= "{Binding Path=Id, Mode=TwoWay}" IsReadOnly="True" />
<DataGridTextColumn Width="*" Header="Barcode" Binding= "{Binding Path=Barcode, Mode=TwoWay}" />
<DataGridTextColumn Width="*" Header="Item" Binding= "{Binding Path=Item, Mode=TwoWay}" IsReadOnly="True"/>
<DataGridTextColumn Width="*" Header="Qty" Binding= "{Binding Path=Qty, Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"/>
<DataGridTextColumn Width="*" Header="Mrp" Binding= "{Binding Path=Mrp, Mode=TwoWay}" IsReadOnly="True"/>
<DataGridTextColumn Width="*" Header="Discount" Binding= "{Binding Path=Discount, Mode=TwoWay}" IsReadOnly="True"/>
<DataGridTextColumn Width="*" Header="Cgst" Binding= "{Binding Path=Cgst, Mode=TwoWay}" IsReadOnly="True"/>
<DataGridTextColumn Width="*" Header="Sgst" Binding= "{Binding Path=Sgst, Mode=TwoWay}" IsReadOnly="True"/>
<DataGridTextColumn Width="*" Header="Amount" Binding= "{Binding Path=Amount, Mode=OneWay ,UpdateSourceTrigger=PropertyChanged}" IsReadOnly="True"/>
<DataGridTextColumn Width="*" Header="Salesman" Binding= "{Binding Path=Salesman, Mode=TwoWay}" IsReadOnly="True"/>
<DataGridTemplateColumn Header="Delete">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Button Content="X" Click="Button_Click"/>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
<DataGrid.RowDetailsTemplate >
<DataTemplate>
<DataGrid x:Name="RowDetailsDataGrid" AutoGenerateColumns="False">
<DataGrid.Columns>
<DataGridTextColumn Width="*" Binding="{Binding Details}" />
<DataGridTextColumn Width="*" Binding="{Binding CgstDetails}" />
<DataGridTextColumn Width="*" Binding="{Binding SgstDetails}" />
<DataGridTextColumn Width="*" Binding="{Binding DiscountDetails}"/>
</DataGrid.Columns>
</DataGrid>
</DataTemplate>
</DataGrid.RowDetailsTemplate>
</DataGrid>
这是(大致)我的代码隐藏:
ObservableCollection<TableData> tableData = new ObservableCollection<TableData>();
public MainWindow()
{
InitializeComponent();
dataGrid.DataContext = tableData;
}
public class TableData : INotifyPropertyChanged
{
public int Id { get; set; }
public int No { get; set; }
public string Details { get; set; }
public string CgstDetails { get; set; }
public string SgstDetails { get; set; }
public string DiscountDetails { get; set; }
public string Barcode { get; set; }
public string Item { get; set; }
private double qty;
public double Qty {
get { return qty; }
set
{
qty = value;
OnPropertyChanged("Qty");
}
}
public double Mrp { get; set; }
public double Discount { get; set; }
public double Cgst { get; set; }
public double Sgst { get; set; }
private double amount; // field
public double Amount
{
get { return amount; }
set {
amount = (Qty * Mrp) + ((Cgst / 100) * (Mrp * Qty)) + ((Sgst / 100) * (Mrp * Qty));
OnPropertyChanged("Amount");
}
}
public int Salesman { get; set; }
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged(String propertyName)
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
public bool RowAdded{ get; set; }
}
private void onCellEditEnding(object sender, DataGridCellEditEndingEventArgs e)
{
var rowFetched = new TableData()
{
Id = currentRowIndex + 1,
No = currentRowIndex + 1,
Barcode = item.Barcode,
Qty = item.Qty,
Mrp = item.Mrp,
Item = item.Item,
Discount = item.Discount,
Cgst = item.Cgst,
Sgst = item.Cgst,
Amount = item.Amount,
Salesman = item.Salesman,
Details = item.Details,
DiscountDetails = item.DiscountDetails,
CgstDetails = item.CgstDetails,
SgstDetails = item.SgstDetails,
RowAdded = true
};
tableData.Insert(currentRowIndex, rowFetched);
}
这是行不通的。我只是在WrapPanel
中放了一个TextBlock
而不是DataGrid
(请参阅下面的代码),数据绑定工作正常,数据显示在行详细信息中,但我希望它是一行(DataGrid
)而不是WrapPanel
。
<DataGrid.RowDetailsTemplate >
<DataTemplate>
<WrapPanel Background="LightGray">
<Border BorderBrush="Black" BorderThickness="1" Width="355" Padding="40 0 0 0" >
<TextBlock FontSize="16" Foreground="MidnightBlue" Text="{Binding Details}" VerticalAlignment="Center" />
</Border>
<Border BorderBrush="Black" BorderThickness="1" Width="71">
<TextBlock FontSize="16" Foreground="MidnightBlue" Text="{Binding CgstDetails}" VerticalAlignment="Center" />
</Border>
<Border BorderBrush="Black" BorderThickness="1" Width="71">
<TextBlock FontSize="16" Foreground="MidnightBlue" Text="{Binding SgstDetails}" VerticalAlignment="Center" />
</Border>
<Border BorderBrush="Black" BorderThickness="1" Width="71">
<TextBlock FontSize="16" Foreground="MidnightBlue" Text="{Binding DiscountDetails}" VerticalAlignment="Center" />
</Border>
<Border BorderBrush="Black" BorderThickness="1" Width="188">
<TextBlock FontSize="16" Foreground="MidnightBlue" VerticalAlignment="Center" />
</Border>
</WrapPanel>
</DataTemplate>
</DataGrid.RowDetailsTemplate>
如果有人可以帮忙?
我认为将嵌套DataGrid
放入行详细信息模板中只是为了显示一行并不是一个好主意,但如果这是您唯一的选择,您可以按照以下步骤操作。
DataGrid
需要集合类型的ItemsSource
,更具体地说是IEnumerable
。您尝试做的是直接绑定DataContext
本身的属性,这不起作用。您必须至少有两个选项才能使其工作,这两个选项本质上都提供了单个项目的集合,ItemsSource
嵌套DataGrid
。
创建一个值转换器,将
TableData
项包装在集合中(此处为数组)。public class ItemToCollectionConverter : IValueConverter { public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { return value is null ? null : new[] { value }; } public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) { throw new InvalidOperationException(); } }
在 XAML 中创建转换器的实例(例如,在
DataGrid.Resources
中),只需使用转换器将数据上下文绑定到嵌套DataGrid
的ItemsSource
。这样,TableData
项将包装在集合中,并被视为单个项集合,因此列绑定将正常工作。<DataGrid x:Name="dataGrid" Margin="10,100,10,96" PreviewKeyDown="dataGrid_PreviewKeyDown" AutoGenerateColumns="False" ItemsSource="{Binding}" AlternatingRowBackground="AliceBlue" CellEditEnding="onCellEditEnding" SelectedItem="{Binding SelectedItem}" > <DataGrid.Resources> <local:ItemToCollectionConverter x:Key="ItemToCollectionConverter"/> </DataGrid.Resources> <DataGrid.Columns> <DataGridTextColumn Width="*" Header="No" Binding= "{Binding Path=Id, Mode=TwoWay}" IsReadOnly="True" /> <DataGridTextColumn Width="*" Header="Barcode" Binding= "{Binding Path=Barcode, Mode=TwoWay}" /> <DataGridTextColumn Width="*" Header="Item" Binding= "{Binding Path=Item, Mode=TwoWay}" IsReadOnly="True"/> <DataGridTextColumn Width="*" Header="Qty" Binding= "{Binding Path=Qty, Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"/> <DataGridTextColumn Width="*" Header="Mrp" Binding= "{Binding Path=Mrp, Mode=TwoWay}" IsReadOnly="True"/> <DataGridTextColumn Width="*" Header="Discount" Binding= "{Binding Path=Discount, Mode=TwoWay}" IsReadOnly="True"/> <DataGridTextColumn Width="*" Header="Cgst" Binding= "{Binding Path=Cgst, Mode=TwoWay}" IsReadOnly="True"/> <DataGridTextColumn Width="*" Header="Sgst" Binding= "{Binding Path=Sgst, Mode=TwoWay}" IsReadOnly="True"/> <DataGridTextColumn Width="*" Header="Amount" Binding= "{Binding Path=Amount, Mode=OneWay ,UpdateSourceTrigger=PropertyChanged}" IsReadOnly="True"/> <DataGridTextColumn Width="*" Header="Salesman" Binding= "{Binding Path=Salesman, Mode=TwoWay}" IsReadOnly="True"/> <DataGridTemplateColumn Header="Delete"> <DataGridTemplateColumn.CellTemplate> <DataTemplate> <Button Content="X" Click="Button_Click"/> </DataTemplate> </DataGridTemplateColumn.CellTemplate> </DataGridTemplateColumn> </DataGrid.Columns> <DataGrid.RowDetailsTemplate> <DataTemplate> <DataGrid x:Name="RowDetailsDataGrid" AutoGenerateColumns="False" ItemsSource="{Binding Converter={StaticResource ItemToCollectionConverter}}"> <DataGrid.Columns> <DataGridTextColumn Width="*" Binding="{Binding Details}" /> <DataGridTextColumn Width="*" Binding="{Binding CgstDetails}" /> <DataGridTextColumn Width="*" Binding="{Binding SgstDetails}" /> <DataGridTextColumn Width="*" Binding="{Binding DiscountDetails}"/> </DataGrid.Columns> </DataGrid> </DataTemplate> </DataGrid.RowDetailsTemplate> </DataGrid>
从包含子类型的单个项或仅包含详细信息属性的帮助程序类型的
TableData
类型公开集合属性。public class TableDetailsData { public string Details { get; set; } public string CgstDetails { get; set; } public string SgstDetails { get; set; } public string DiscountDetails { get; set; } }
public class TableData : INotifyPropertyChanged { private TableDetailsData _detailsData; public TableDetailsData DetailsData { get => _detailsData; set { _detailsData = value; DetailsDataCollection = new List<TableDetailsData> { _detailsData }; OnPropertyChanged(nameof(DetailsDataCollection)); } } public IEnumerable<TableDetailsData> DetailsDataCollection { get; private set; } // ...other code. }
当
DetailsData
更改时,DetailsDataCollection
始终更新。无论您是像这样创建集合并将DetailsData
公开为对象还是属性取决于您,都有很多可能性,这只是为了了解该怎么做。现在,您可以将此集合绑定为嵌套DataGrid
中的ItemsSource
。<DataGrid x:Name="RowDetailsDataGrid" AutoGenerateColumns="False" ItemsSource="{Binding DetailsDataCollection}" CanUserAddRows="False">
就个人而言,我更喜欢值转换器解决方案,因为您不必公开冗余集合属性并污染您的代码,因为它不是一个非常干净的解决方案。我建议您创建一个适当的详细信息类型,并考虑一种比单行DataGrid
更好的方法来表示数据,这似乎不合适,并且在这种情况下无法提供良好的用户体验。