将附加列与数据网格 WPF 中的任何控件绑定

Binding additional column with any control in datagrid WPF

我有一项要求使用 WPF C# 在数据网格内的“listview”或“datagrid”中绑定附加列。

我的基本数据网格如下

<table border="1" width="100%">
    <tr>
     <td>Item Id</td>
     <td>Item Name</td>
     <td>Quantity</td>
     <td>Price</td>
    </tr>
    <tr>
     <td>500</td>
     <td>Sanwich</td>
     <td>2</td>
     <td>10</td>
    </tr>
</table>

以上datagrid我的XAML代码如下

<DataGrid Grid.Column="1" Margin="8,60,8,16"AutoGenerateColumns="False" Height="350"
     HorizontalAlignment="Left" Name="gridOrderDetails" VerticalAlignment="Top" Width="450" >
    <DataGrid.Columns>
        <DataGridTextColumn Header="Item ID" Binding="{Binding itemId}" />                                        

        <DataGridTextColumn Header="Quantity" Binding="{Binding quantity}" />
        <DataGridTextColumn Header="Item Name" Binding="{Binding comments}" />
        <DataGridTextColumn Header="Item Price" Binding="{Binding ItemPrice}" />
    </DataGrid.Columns>
</DataGrid>

我的代码隐藏在按钮点击事件中的代码如下:

private void Button_Click(object sender, RoutedEventArgs e)
{
    try
    {
        DBDataContext dbContext = new DBDataContext();
        SP_Get_OrderItemResult orderRow = gridOrder.SelectedItem as SP_Get_OrderItemResult;

        gridOrderDetails.ItemsSource = dbContext.SP_Get_ItemList(orderRow.orderid);
    }
    catch (Exception Ex)
    {
        MessageBox.Show(Ex.Message);
        return;
    }
}

我想要的输出如下

<table border="1" width="100%">
    <tr>
     <td>Item Id</td>
     <td>Item Name</td>
     <td>Additionals</td>
     <td>Quantity</td>
     <td>Price</td>
    </tr>
    <tr>
     <td>500</td>
     <td>Sanwich</td>
     <td>Egg<p class="MsoNormal" style="margin-left:0in">Ketchup</p>
     <p>
     <span style="font-size: 11.0pt; line-height: 115%; font-family: Calibri,sans-serif">
     Salad</span></td>
     <td>2</td>
     <td>10</td>
    </tr>
</table>

为了实现这个 datagrid 我使用 DataGridTemplateColumn.

编写了我的 XAML 代码如下
<DataGrid Grid.Column="1" Margin="8,60,8,16"AutoGenerateColumns="False" Height="350"
    HorizontalAlignment="Left" Name="gridOrderDetails" VerticalAlignment="Top" Width="450" LoadingRow="gridOrderDetails_LoadingRow">
    <DataGrid.Columns>
        <DataGridTextColumn Header="Item ID" Binding="{Binding itemId}" />
        <DataGridTextColumn Header="Item Name" Binding="{Binding ItemName}" />
        <DataGridTemplateColumn Header="Addtionals">
            <DataGridTemplateColumn.CellTemplate>
                <DataTemplate>
                    <DataGrid AutoGenerateColumns="False" Name="gridAdditionals" >
                        <DataGridTextColumn Header="Additional" Binding="Additionals"></DataGridTextColumn>
                    </DataGrid>
                </DataTemplate>
            </DataGridTemplateColumn.CellTemplate>
        </DataGridTemplateColumn>         
    <DataGridTextColumn Header="Quantity" Binding="{Binding quantity}" />
        <DataGridTextColumn Header="Comments" Binding="{Binding comments}" />
        <DataGridTextColumn Header="Item Price" Binding="{Binding ItemPrice}" />
    </DataGrid.Columns>
</DataGrid>

在后面的代码中,我尝试使用 LoadingRow 事件,但无法从单元格值传递相应的 ItemID

private void gridOrderDetails_LoadingRow(object sender, DataGridRowEventArgs e)
{
    DCAPPDBDataContext dbContext = new DCAPPDBDataContext();

    DataGrid grid = FindChild<DataGrid>(gridOrderDetails, "gridAdditionals");
    grid.ItemsSource = dbContext.SP_Get_AdditionalsList(500);
} 

我猜我使用的逻辑是错误的。这可以使用 Asp.net C# 中的 ItemDataBound 来实现。 任何人都可以帮助我如何在 WPF C# 中执行此操作。

使用 WPF 时,应遵循 MVVM 模式。无论哪种方式,您都应该为 Order(包含 Id、Name、Quantity 等属性)定义一个合适的 class(即视图模型)。此 class 还应该有一个 属性 用于您的 Aditionals(例如 strings 的集合)。然后通过使用适当的 DataBindings 您将实现您想要的功能。

这是一个可以给您提供思路的工作示例:

订单class:

public class Order : INotifyPropertyChanged
{
    #region INotifyPropertyChanged
    public event PropertyChangedEventHandler PropertyChanged;

    void OnPropertyChanged(string propertyName)
    {
        if (PropertyChanged != null)
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
    }
    #endregion

    public Order(int id)
    {
        DBDataContext dbContext = new DBDataContext();
        DCAPPDBDataContext dbContext2 = new DCAPPDBDataContext();

        var itemsSource = dbContext.SP_Get_ItemList(id);
        var additionals = dbContext2.SP_Get_AdditionalsList(id);

        Id = id;
        Name = itemsSource.name;
        Quantity = itemsSource.quantity;
        // other properties ...

        Additionals = new ObservableCollection<string>();
        foreach (var item in additionals)
        {
            Additionals.Add(item);
        }
    }

    private int _id;
    public int Id
    {
        get
        {
            return _id;
        }
        set
        {
            _id = value;
            OnPropertyChanged("Id");
        }
    }

    // define other properties e.g. Name, Quantity, Price, etc.
    // the same way as Id.

    public ObservableCollection<string> Additionals {get;set;}
}

Xaml:

<Grid>
    <Grid.RowDefinitions>
        <RowDefinition Height="*"/>
        <RowDefinition Height="Auto"/>
    </Grid.RowDefinitions>
    <DataGrid Grid.Row="0" AutoGenerateColumns="False"
          ItemsSource="{Binding Orders}" 
          SelectedItem="{Binding SelectedOrder}">
    <DataGrid.Columns>
        <DataGridTextColumn Header="Item ID" Binding="{Binding Id}" />
        <DataGridTextColumn Header="Item Name" Binding="{Binding Name}" />
        <DataGridTemplateColumn Header="Addtionals">
            <DataGridTemplateColumn.CellTemplate>
                <DataTemplate>
                        <ItemsControl ItemsSource="{Binding Additionals}">
                            <ItemsControl.ItemTemplate>
                                <DataTemplate>
                                    <TextBlock Text="{Binding}"/>
                                </DataTemplate>
                            </ItemsControl.ItemTemplate>
                        </ItemsControl>
                </DataTemplate>
            </DataGridTemplateColumn.CellTemplate>
        </DataGridTemplateColumn>
        <DataGridTextColumn Header="Quantity" Binding="{Binding Quantity}" />
        <DataGridTextColumn Header="Item Price" Binding="{Binding Price}" />
    </DataGrid.Columns>
</DataGrid>
<Button  Grid.Row="1" Content="New Order" Click="Order_Click"/>
</Grid>

MainWindow.cs:

    public ObservableCollection<Order> Orders { get; set; }

    public Order SelectedOrder { get; set; }

    public MainWindow()
    {
        InitializeComponent();
        DataContext = this;

        Orders = new ObservableCollection<Order>();

    }

    private void Order_Click(object sender, RoutedEventArgs e)
    {
        SP_Get_OrderItemResult orderRow = gridOrder.SelectedItem as SP_Get_OrderItemResult;
        Orders.Add(new Order(orderRow.orderid));
    }

在 Bahman_Aries post 和一些小东西的帮助下,我正在 post 找到精确的解决方案。 这是我想要的精确解决方案。

订单class:

public class Order : INotifyPropertyChanged
{
    #region INotifyPropertyChanged
    public event PropertyChangedEventHandler PropertyChanged;

    void OnPropertyChanged(string propertyName)
    {
        if (PropertyChanged != null)
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
    }
    #endregion

    public Order(SP_Get_ItemListResult itemResult)
    {
        DBDataContext dbContext = new DBDataContext();                


         orderItemID = itemResult.orderItemID;
        itemName = itemResult.ItemName;
        quantity = itemResult.quantity;           
        // other properties ...

      var additionals = dbContext.SP_Get_AdditionalsList(orderItemID);

        Additionals = new ObservableCollection<string>();
        foreach (var item in additionals)
        {
            Additionals.Add(item.Additionals);
        }
    }

    private int _id;
    public int Id
    {
        get
        {
            return _id;
        }
        set
        {
            _id = value;
            OnPropertyChanged("Id");
        }
    }

    // define other properties e.g. Name, Quantity, Price, etc.
    // the same way as Id.

    public ObservableCollection<string> Additionals {get;set;}
}

XAML 代码无变化。

MainWindow.cs:

public ObservableCollection<Order> Orders { get; set; }

public Order SelectedOrder { get; set; }

public MainWindow()
{
    InitializeComponent();
    DataContext = this;

    Orders = new ObservableCollection<Order>();

}

private void Order_Click(object sender, RoutedEventArgs e)
{
    SP_Get_OrderItemResult orderRow = gridOrder.SelectedItem as SP_Get_OrderItemResult;
      List<SP_Get_ItemListResult> itemsSource = dbContext.SP_Get_ItemList(orderRow.orderid).ToList();
            for (int i = 0; i < itemsSource.Count(); i++)
            {
                Orders.Add(new Order(itemsSource[i]));
            }         
}