0
votes

I've already checked these links but didn't solve my problem.

I have two model classes(Order.cs and OrderItems.cs) and a View(Invoice.xaml)

There is ObservableCollection(OrderItem) in Order class and a datagrid in the Invoice.xaml. I need to bind ObservableCollection to the datagrid. Problem is, binding by writing xaml codes does not automatically update the datagrid when items are added to the ObservableCollection.

Codes are shown below

Order Class

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 Class

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
}

xaml code of the Invoice.xaml (for the simplicity only the necessary codes are shown. Model is the package of the Order and OrderItem classes.

    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>

But I can achieve this without writing the xaml codes by writting the code in the Invoice.xaml.cs class where it is necessary.

    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>  
}

(including Binding each column to a property in OrderItem) Following codes are not necessary if the line dataGrid.ItemsSource = _order.OrderItems; is used.

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

Can anyone point me how to overcome this problem.

2
The Order you're bound to is not the same one you're modifying in your event handler.Charles Mager
how are you adding OrderItem to your Order?Nitin
@Nitin By GetOrderDetails(string customerId) method OrderItems are added to the ObservableCollection<OrderItem> OrderItemsLahiru Jayathilake
@CharlesMager What do you mean by modifying in the event handler? There I have assigned the ObservableCollection to the item source of the datagrid. Without that bound it is perfectly working What I need is to do it without the code datagrid.ItemSource = _order.OrderItems;Lahiru Jayathilake

2 Answers

1
votes

Your grid is bound to the Order static resource:

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

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

In your event handler, you are creating a new Order instance:

Order _order = new Order();

You are then calling a method that, you say, adds an OrderItem to the OrderItems collection in _order. This is not the OrderItems collection your DataGrid.ItemsSource is bound to.

A simple fix might be to declare your Order in the in the code behind and assign it to the DataContext in the constructor:

private readonly Order _order = new Order();

public WindowName()
{
    DataContext = _order;
}

Then remove the DataContext binding from your DataGrid (it will inherit the Window.DataContext). Then you can remove Order _order = new Order() from your event handler and use the instance field _order instead.

Ideally, your event handler wouldn't be required and there would be an ICommand in your Order that would be bound to whatever button should add a new order.

1
votes

When you populate your data, you then need to tell the framework that the data has been updated.

So from the Viewmodel code in your Setter of the collection, add a line that says RaisePropertyChanged("OrderItems") which is the Binding Source name you told the grid.

The workflow for this is:

  1. In your Xaml add the ItemsSource="{Binding Orders}". This will be the propertychanged name to use to signal the framework that something has changed.
  2. In your view model code when you make changes to the collection you'll RaisePropertyChanged("Orders") which signals the framework to marshal the data to the UI components.
  3. your next step will figure out if the data flows one way from the code to the UI, or UI to the code, or Both ways. So in your xaml ItemSource="{Binding Orders, Mode=OneWay} . When you're in Visual Studio it will pop up the entire list. In twoway mode the framework will marshal your data from the UI to the observablecollection.

Sorry I didn't have time to adapt your code. Hopefully this explains it well enough. Cheers.