1

I'm trying to have a combobox field in my WPF datagrid with the options in the combobox coming from a SharePoint list. I have managed to get the options into the combo box OK, but it's not listening to the SelectedItemBinding setting and the values are showing as blank for each item. The data for the DataGrid is also coming from a SharePoint list but it has been cast to an ObservableCollection. Here's the XAML:

<DataGrid Name="dgVendorSchedule" Grid.Column="1" Grid.Row="2" Grid.ColumnSpan="3" 
              AutoGenerateColumns="False"
              SelectionChanged="dgVendorSchedule_SelectionChanged"
              EnableRowVirtualization="True" 
              IsReadOnly="False" 
             >
        <DataGrid.Columns>
            <DataGridTextColumn Header="Title" Binding="{Binding title, Mode=TwoWay}" />
            <!-- <DataGridTextColumn Header="Vendor" Binding="{Binding vendorName, Mode=TwoWay}" />-->
            <DataGridComboBoxColumn x:Name="cmbVendor" 
                                    Header="Vendor"
                                    SelectedValueBinding="{Binding vendorName}"
                                    DisplayMemberPath="Title">
            </DataGridComboBoxColumn>
            <DataGridTextColumn Header="Billing Date" Binding="{Binding billingDate, Mode=TwoWay}" />
            <DataGridTextColumn Header="Payment" Binding="{Binding paymentTitle, Mode=TwoWay}"/>
            <DataGridTextColumn Header="Invoice" Binding="{Binding invoiceTitle, Mode=TwoWay}"/>
        </DataGrid.Columns>
    </DataGrid>

and here's the code behind:

        var lstVendors = (from i in colVendorSched.AsEnumerable<SP.ListItem>()
                          select new vendor
                          {
                              vendorName = ((SP.FieldLookupValue)i["Vendor"]).LookupValue,
                              billingDate = ((DateTime)i["Billing_x0020_Date_x0020__x0028_"]).ToLocalTime(),
                              itemID = (int)i["ID"],
                              title = (string)i["Title"],
                              //using the ? operator to trap null values on the lookup field before retrieving the lookupvalue property 
                              invoiceTitle = i["Invoice"] == null ? "" : ((SP.FieldLookupValue)i["Invoice"]).LookupValue,
                              paymentTitle = i["Payment"] == null ? "" : ((SP.FieldLookupValue)i["Payment"]).LookupValue
                          });

        var lstVendorList = (from i in colVendorList.AsEnumerable<SP.ListItem>()
                             select new
                             {
                                 Title = i["Title"],
                                 ID = i["ID"]
                             });

        cmbVendor.ItemsSource = lstVendorList;

        ObservableCollection<vendor> obsVendors = new ObservableCollection<vendor>(lstVendors);

        dgVendorSchedule.ItemsSource = obsVendors;

I'm fairly new to working with WPF and frankly this binding stuff is making my head hurt. I'd appreciate any pointers.

EDIT: for posterity... The solution turned out to be creating a class for the vendorItem and having that be a member of the vendor class like so:

public class vendor
{
    public VendorItem vendorName {get; set;}
    public DateTime billingDate {get; set;} 
    public int itemID {get; set;}
    public string title {get; set;} 
    public string invoiceTitle  {get; set;}
    public string paymentTitle { get; set; }
}

public class VendorItem
{
    public string Title { get; set; }
    public int ID { get; set; }
}

This made it possible to set the selectedValuePath, and have the binding work properly. Here's the working XAML for the column:

<DataGridComboBoxColumn x:Name="cmbVendor" 
                                    Header="Vendor"
                                    SelectedValueBinding="{Binding vendorName.ID}"
                                    SelectedValuePath="ID"
                                    DisplayMemberPath="Title"                                        >
            </DataGridComboBoxColumn>
steam23
  • 69
  • 7
  • You are not showing the combobox code nor the handling of selection changed. Without this, I cannot help. – Joel Bourbonnais Oct 16 '18 at 18:56
  • The combobox code is in the datagrid section here: ` ` I haven't dealt with the selection changed event yet. That's tomorrow's job :) – steam23 Oct 16 '18 at 19:03
  • Wait... now i see you might be talking about the SelectionChanged event on the datagrid "dvVendorSchedule_SelectionChanged." That event is unrelated to the comboboxcolumn. It sets some details on another pane of the page. – steam23 Oct 16 '18 at 19:12

1 Answers1

0

SelectedValueBinding & SelectedItemBinding are there to bind back to the back end. It will set the selected to a variable in the back (UI --> Back-end).

Your problem here is probably with the DisplayMemberPath not working with anonymous object. Could you try wrapping that in a class:

var lstVendorList = (from i in colVendorList.AsEnumerable<SP.ListItem>()
                     select new Vendor
                     {
                         Title = i["Title"],
                         ID = i["ID"]
                     });

public class Vendor
{
    public string Title { get; set; }
    public string ID { get; set; }
}

In this situation, you could also get rid of the DisplayMemberPath and just override the ToString() of the Vendor class.

To better understand comboboxes, you should take a look here. In this case, you must be missing the SelectedValuePath

Joel Bourbonnais
  • 2,618
  • 3
  • 27
  • 44
  • That was a good idea. Still getting the same result though. The combobox is populated with the items from the list, but the value for that column is not being displayed. – steam23 Oct 16 '18 at 19:22
  • Oh but then you are going at this wrongly. Are you trying to use the combobox to list the possible vendor but have it already selected based on the line it is shown on? – Joel Bourbonnais Oct 16 '18 at 19:25
  • Yes.. that's what i'm trying to do. here's a ![screenshot](https://i.imgur.com/nRs0xr3.png) that shows two columns for Vendor. The first is the original DataGridTextColumn that has the VendorName in it. That data is drawn from a sharepoint lookup field. I now want to change that to be a DataGridComboBoxColumn so if you want to edit the field you can do so with a dropdown list. That means it should be a combobox with the existing value selected. – steam23 Oct 16 '18 at 21:17
  • I appreciate the link, however I think that we may be talking about different things. So far I haven't had any problems with comboboxes. I've used them several times and was able to set their itemssource, selectedvaluepath and displaymember path just fine. In fact, that is why I'm finding my problem with setting this **DataGridComboBoxColumn** so vexing. As opposed to a regular binding a regular ComboBox, the combobox as embedded in a datagrid seems to work differently. I have tried setting the SelectedValuePath both in the Xaml and in code behind without any result. – steam23 Oct 17 '18 at 12:36
  • I guess you should go with a custom datagrid column as described here: https://www.wpf-tutorial.com/datagrid-control/custom-columns/. – Joel Bourbonnais Oct 17 '18 at 12:38
  • 1
    OK! I got it! it turned out that getting rid of the anonymous type was half the battle. Once I did that, i was able to include that type in my vendor list type and set both an ID and title for that column, which in turn meant that I could set the SelectedValuePath to the ID and it is now working. thanks for pointing me in the correct direction. – steam23 Oct 17 '18 at 13:54