如何将 ObservableCollection 与 datagrid WPF 绑定

Posted

技术标签:

【中文标题】如何将 ObservableCollection 与 datagrid WPF 绑定【英文标题】:How to bind ObservableCollection with datagrid WPF 【发布时间】:2016-09-01 11:15:38 【问题描述】:

我已经检查了这些链接,但没有解决我的问题。

How to bind WPF DataGrid to ObservableCollection

Bind an ObservableCollection to a wpf datagrid : Grid stays empty

我有两个模型类(Order.csOrderItems.cs)和一个 View(Invoice.xaml)

Order 类中有 ObservableCollection(OrderItem),Invoice.xaml 中有一个数据网格。我需要将 ObservableCollection 绑定到数据网格。 问题是,当项目添加到 ObservableCollection 时,通过编写 xaml 代码进行绑定不会自动更新数据网格。

代码如下所示

订单类

public class Order

    public Order()
    
        OrderItems =new ObservableCollection<OrderItem>();
    

    public ObservableCollection<OrderItem> OrderItems  get; set; 

    public void GetOrderDetails(string customerId)
    
        // method for getting set of OrderItmes objects and add to the 
        // ObservableCollection<OrderItem>
    

OrderItem 类

public class OrderItem

    public OrderItem(string supplierId, string itemId, string    itemName,decimal weight)
    
        // some codes here
    
    public string SupplierId  get; set;  // Supplier's ID
    public string ItemId  get; set;  // Item ID
    public string ItemName  get; set; // Item Name
    public decimal Weight  get; set;  // weight of the item

Invoice.xaml 的 xaml 代码(为简单起见,仅显示必要的代码。Model 是 Order 和 OrderItem 类的包。

    xmlns:model="clr-namespace:Onion.Model"
<Window.Resources>
    <model:Order x:Key="Order"/>
</Window.Resources>

<DataGrid x:Name="dataGrid" AutoGenerateColumns="False" CanUserResizeRows="False" Grid.ColumnSpan="8"
            Margin="0,0,30.5,0" CanUserResizeColumns="False" CanUserReorderColumns="False"
            CanUserSortColumns="False" CanUserAddRows="False" IsReadOnly="True"
            DataContext="Binding Source=StaticResource Order" ItemsSource="Binding OrderItems">
            <DataGrid.Columns>
                <DataGridTextColumn Binding="Binding SupplierId" CanUserResize="False" FontSize="16"
                    Header="Supplier" Width="0.18*" />
                <DataGridTextColumn Binding="Binding ItemId" CanUserResize="False" FontSize="16"
                    Header="ItemID" Width="0.13*" />
                <DataGridTextColumn Binding="Binding ItemName" CanUserResize="False" FontSize="16"
                    Header="Item name" Width="0.2*" />
                <DataGridTextColumn Binding="Binding Weight" CanUserResize="False" FontSize="16" 
                    Header="Weight" Width="0.1*" />

 </DataGrid>

但我可以通过在必要的 Invoice.xaml.cs 类中编写代码来实现此目的,而无需编写 xaml 代码。

    private void txtBox_PreviewKeyDown(object sender, KeyEventArgs e)
    Order _order = new Order();
    _order.GetOrderDetails(customerId);// add OrderItems to the ObservableCollection

    // If this code is written some xaml codes are not needed (they are shown  below in the question
    dataGrid.ItemsSource = _order.OrderItems; // OrderItems is the ObservableCollection<OrderItem>  

(包括将每一列绑定到 OrderItem 中的一个属性)如果行 dataGrid.ItemsSource = _order.OrderItems; 则不需要以下代码被使用了。

xmlns:model="clr-namespace:Onion.Model"
<Window.Resources>
    <model:Order x:Key="Order"/>
 </Window.Resources>
 DataContext="Binding Source=StaticResource Order" ItemsSource="Binding OrderItems"

谁能告诉我如何克服这个问题。

【问题讨论】:

您绑定到的Order 与您在事件处理程序中修改的不是同一个。 您如何将 OrderItem 添加到您的订单中? @Nitin 通过 GetOrderDetails(string customerId) 方法将 OrderItems 添加到 ObservableCollection OrderItems @CharlesMager 在事件处理程序中修改是什么意思?在那里,我已将 ObservableCollection 分配给数据网格的项目源。没有这个界限,它是完美的工作我需要的是没有代码 datagrid.ItemSource = _order.OrderItems; 【参考方案1】:

您的网格绑定到Order 静态资源:

<Window.Resources>
    <model:Order x:Key="Order"/>
</Window.Resources>

<DataGrid DataContext="Binding Source=StaticResource Order" ...

在您的事件处理程序中,您正在创建一个新的 Order 实例:

Order _order = new Order();

然后您调用一个方法,您说,该方法将OrderItem 添加到_order 中的OrderItems 集合中。这不是您的DataGrid.ItemsSource 绑定到的OrderItems 集合。

一个简单的解决方法可能是在后面的代码中声明您的Order,并将其分配给构造函数中的DataContext

private readonly Order _order = new Order();

public WindowName()

    DataContext = _order;

然后从DataGrid 中删除DataContext 绑定(它将继承Window.DataContext)。然后,您可以从事件处理程序中删除 Order _order = new Order() 并改用实例字段 _order

理想情况下,不需要您的事件处理程序,并且您的Order 中会有一个ICommand,它将绑定到应该添加新订单的任何按钮。

【讨论】:

【参考方案2】:

当您填充数据时,您需要告诉框架数据已更新。

因此,从集合的 Setter 中的 Viewmodel 代码中,添加一行内容 RaisePropertyChanged("OrderItems") 这是您告诉网格的绑定源名称。

这个工作流程是:

    在您的 Xaml 中添加 ItemsSource="Binding Orders"。这将是 propertychanged 的​​名称,用于向框架发出信号已更改。 在您的视图模型代码中,当您对集合进行更改时,您将发出 RaisePropertyChanged("Orders") 信号,通知框架将数据编组到 UI 组件。 下一步将确定数据是从代码流向 UI,还是从 UI 流向代码,或者双向。因此,在您的 xaml ItemSource="Binding Orders, Mode=OneWay 中。当您在 Visual Studio 中时,它会弹出整个列表。在双向模式下,框架会将您的数据从 UI 编组到 observablecollection。

抱歉,我没有时间修改您的代码。希望这能很好地解释它。 干杯。

【讨论】:

以上是关于如何将 ObservableCollection 与 datagrid WPF 绑定的主要内容,如果未能解决你的问题,请参考以下文章

如何将 WPF DataGrid 绑定到 ObservableCollection

如何将 ObservableCollection 与 datagrid WPF 绑定

将 ObservableCollection 保存到文件 (.txt)

C#如何将实体框架实体与ObservableCollection一起使用

如何使 ObservableCollection 线程安全?

如何通过工作线程更新 ObservableCollection?