WPF- Add change event to autogenerated DataGridComboBoxColumn

1.3k views Asked by At

I have a datagrid and in the DataGrid.AutoGeneratingColumn Event I change some of the columns to DataGridComboBoxColumns.

At the same time I also want to add a selection changed event to that new combobox, but can't figure out how to get access to the combobox control within the DataGridComboBoxColumn.

    private void dgGrid_AutogeneratingColumns(object sender, DataGridAutoGeneratingColumnEventArgs e)
    {
        var cb = new DataGridComboBoxColumn();
        switch (e.PropertyName)
        {
            case "name":

                using (Entities context = new Entities())
                {
                    List<object> fNames = (from x in context.view
                        select new object {objectname = x.objectname}).ToList<object>();

                    cb.Header = "xxx";
                    cb.ItemsSource = xxx;
                    cb.SelectedItemBinding = new Binding("xxx");
                    e.Column = cb;

                    //Get reference to combobox in this new column
                    //Add event to it
                    //?????

                }
                break;
            //more ....
        }
    }
2

There are 2 answers

0
Stipo On BEST ANSWER

You cannot access ComboBox instance from DataGrid.AutoGeneratingColumn event handler, because ComBox is created only when a cell from that column goes into edit mode and new ComboBox instance is created every time that cell goes into edit mode.

Here is a sample code how to do what you want via DataGridComboBoxColumn.EditingElementStyle property by setting EventSetter for Selector.SelectionChangedEvent (ComboBox inherits from Selector):

private void dgGrid_AutogeneratingColumns(object sender, DataGridAutoGeneratingColumnEventArgs e)
{
    switch (e.PropertyName)
    {
        case "name":

            var cb = new DataGridComboBoxColumn();

            // Old...
            cb.Header = "Name";
            cb.ItemsSource = new List<string>() { "Option1", "Option2", "Option3" };
            cb.SelectedItemBinding = new Binding("name");

            // NEW
            cb.EditingElementStyle = new Style(typeof(ComboBox))
            {
                Setters =
                {
                    new EventSetter(Selector.SelectionChangedEvent, new SelectionChangedEventHandler(OnComboBoxSelectionChanged))
                }
            };

            e.Column = cb;
            break;
    }
}

private static void OnComboBoxSelectionChanged(object sender, SelectionChangedEventArgs e)
{
    // We must check that both RemovedItems and AddedItems are not empty,
    // because this event also fires when ComboBox is initialized (when entering edit mode), but then RemovedItems is empty.
    if (e.RemovedItems.Count > 0 && e.AddedItems.Count > 0)
    {
        var newlySelectedName = (string)e.AddedItems[0];
    }
}
2
Michael G On

Why not declare the columns in xaml, and provide the column template for each column? You could then subscribe to the selection changed event. Or, Bind to the "SelectedItem" combobox property instead.

For example, you can provide a DataTemplate that is for ProductA, that contains the datagrid, and specific columns for ProductA; likewise for ProductB.

<DataTemplate DataType="{x:Type model:ProductA}">
    <DataGrid AutoGenerateColumns="False"
              ItemsSource="{Binding Products}">
        <DataGrid.Columns>
            <DataGridTextColumn Binding="{Binding ProductName}"
                                Header="ProductName"
                                IsReadOnly="True"></DataGridTextColumn>

            <DataGridTemplateColumn Header="Category">
                <DataGridTemplateColumn.CellTemplate>
                    <DataTemplate>
                        <TextBlock Text="{Binding CategoryName}" />
                    </DataTemplate>
                </DataGridTemplateColumn.CellTemplate>

                <DataGridTemplateColumn.CellEditingTemplate>
                    <DataTemplate>
                        <ComboBox ItemsSource="{Binding Categories}"
                                  SelectedItem="{Binding SelectedCategory"}
                                  IsSynchronizedWithCurrentItem="True" />
                    </DataTemplate>
                </DataGridTemplateColumn.CellEditingTemplate>
            </DataGridTemplateColumn>
        </DataGrid.Columns>
    </DataGrid>
</DataTemplate>

Then to use the datatemplate, you would use a ContentPresenter which would resolve the correct datatemplate, based on the SelectedProduct type.

<ContentPresenter Content="{Binding SelectedProductType}" />