Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

WPF DataBinding ObservableCollection<T> to DataGrid

I'm trying to create DataGrid in a separate UserControl whose DataContext is a List of T.

In the code behind, I create a List, populate the list, then send it to the constructor for the UserControl on which I have the DataGrid I am trying to populate.

The UserControl class is as follows.

public partial class QuotePreview : UserControl
{
    private static SelectionList  previewList = new SelectionList();

    public SelectionList PreviewList
    {
        get { return previewList; }
    }

    public QuotePreview()
    {
        InitializeComponent();
    }

    public QuotePreview(SelectionList selectedOptions)
    {
        InitializeComponent();

        previewList = selectedOptions;

        QuotePreviewDataGrid.DataContext = previewList;
    }
}

And the Xaml looks like:

<DataGrid Name="QuotePreviewDataGrid"
          AutoGenerateColumns="False" 
          ItemsSource="{Binding}">
    <DataGrid.Columns>
        <DataGridTextColumn Header="Model Number" Binding="{Binding ModelNumber}"/>
        <DataGridTextColumn Header="Description" Binding="{Binding Description}"/>
        <DataGridTextColumn Header="List Price per Unit" Binding="{Binding Price}"/>
    </DataGrid.Columns>
</DataGrid>

I've tried setting the ItemSource as well using

QuotePreviewDataGrid.ItemsSource = PreviewList;

I've also tried setting both the data context and the itemsource as well as refreshing:

QuotePreviewDataGrid.Items.Refresh();

The databinding I have set to listboxes in the rest of my application works perfectly. In the list boxes I have the itemsource set to {Binding} and the ListItems binding set to {Binding Property}. The datacontext for the listboxes set in the code behind.

My datagrid here is setup in the same manner, yet for some reason nothing is being displayed inside the grid.

When I go through the debugger and watch the flow of information, I can see the List of T, SelectionsList being created and passed to the constructor for the user control where the data grid lies. I can see that the DataContext is indeed being set and shows the items in the list, but when I go back to my appication and try to view the data grid, it's blank.

Any help would be greatly appreciated. I've been trying to wrap my mind around this problem for the last day and a half. Thanks!

UPDATE

The SelectionList is setup like:

public class SelectionList : List<Selection>
{
    public List<Selection> availableSelections = new List<Selection>();

    public List<Selection> AvailableSelections
    {
        get { return availableSelections; }
    }
}

and a Selection is then defined by:

public class Selection : DependencyObject
{
    public bool IsChecked { get; set; }
    public string ModelNumber { get; set; }
    public string Description { get; set; }
    public string Price { get; set; }
}

When the application starts, I build a catalog of existing products (Selections). On different tabs, one for each product family, the datacontext for the products list box is initialized with with available products that it grabs from the catalog. Then pending which product a user selects, the available options or child selections associated with that product are populated into the appropriate list boxes, accessories and warranties.

Once a user selects the options they want, a button is clicked to preview the selected items which is supposed to populate the data grid explained above.

I can build the list of selected options, however when I try to set the data context of the data grid, nothing appears. The Lists for available selections are built and set to the appropriate data context the same way I am trying to do it for the data grid, however the data grid doesn't want to display my information.

UPDATE

So after some more debugging, I've narrowed the problem down a bit. The data binding works as it should. I have no real problems there, I don't think. However, the issue I'm running into now is what I believe to be 2 different instances of my User Control, but only the original is being displayed, not the updated copy.

Here's a copy of the class from about with a couple lines I added to help debug the problem.

public partial class QuotePreview : UserControl
{
    private SelectionList _selectionList;
    private SelectionList temp;

    public QuotePreview()
    {
        InitializeComponent();
        _selectionList = (SelectionList)this.DataContext;
    }

    private void QuotePreview_Loaded(object sender, RoutedEventArgs e)
    {
        _selectionList.SelectedOptions.Add(
            new Selection
            {
                ModelNumber = "this",
                Description = "really",
                Price = "sucks"
            });
    }

    public QuotePreview(SelectionList selectedOptions)
    {
        InitializeComponent();
        _selectionList = (SelectionList)this.DataContext;

        temp = selectedOptions;

        _selectionList.AddRange(selectedOptions);

        QuotePreview_Loaded();
    }

    private void QuotePreview_Loaded()
    {
        foreach (var options in temp.SelectedOptions)
        {
            _selectionList.SelectedOptions.Add(options);
        }

        QuotePreviewDataGrid.ItemsSource = _selectionList.SelectedOptions;
    }
}

The implementation of the default constructor, is called every time the user control / tab, is clicked on. When that happens, _selectionList is set to the data context of the user control, followed by the Loaded Event which adds a line to my data grid.

In another user control where I select the options I want to add to my data grid user control, I click a button that creates a list of the options I want to be added and calls the custom constructor I wrote. Once the constructor finishes, it calls a custom Loaded Event method that I created for shits and giggles, that adds the selected options to my _selectionList.

Now once I click on the data grid user control again, it goes through the whole default process, and adds another default line.

If I go back a tab and say I want these options again and go back to the data grid, it again goes through the default process and adds another default line.

Whats most intriguing though is that I can see both of the selectionLists build since I dont clear the in between processes. I see a list build of the options i want to display and a list build of the default options build...

Oh, also, SelectionList does implement ObservableCollection.

like image 242
Chutes Avatar asked Feb 27 '13 21:02

Chutes


1 Answers

I finally came up with a solution to the problem.

public static class QuotePreview
{
    public static ObservableCollection<PurchasableItem> LineItems { get; private set; }

    static QuotePreview()
    {
        LineItems = new ObservableCollection<PurchasableItem>();
    }

    public static void Add(List<PurchasableItems> selections)
    {
        foreach (var selection in selections)
        {
            LineItems.Add(selection);
        }
    }

    public static void Clear()
    {
        LineItems.Clear();
    }
}

public class QuoteTab : TabItem
{
    public ObservableCollection<PurchasableItem> PreviewItems { get; private set; }

    public QuoteTab()
    {          
        Initialize()

        PreviewItems = QuotePreview.LineItems;

        DataGrid.ItemSource = PreviewItems
    }
}
like image 130
Chutes Avatar answered Nov 13 '22 10:11

Chutes