如何在 DataGrid RowDetailsTemplate 中显示 DataGrid?



我想在另一个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中),只需使用转换器将数据上下文绑定到嵌套DataGridItemsSource。这样,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更好的方法来表示数据,这似乎不合适,并且在这种情况下无法提供良好的用户体验。

相关内容

  • 没有找到相关文章

最新更新