How can I bind the same collection to a DG's ItemsSource and a DG cell's ComboBox (without crashing)?

Jan 11, 2010 at 9:32 PM

I have a DataGrid that's bound to a collection of items. One of the datagrid's columns is a template column, whose CellEditingTemplate is a ComboBox. That ComboBox's ItemsSource is bound to the same collection. Unfortunately, when I try to click on the cell to expand the combo box, I get an InvalidOperationException from DataGridColumn:BeingEdit, line 733, indicating that 'DeferRefresh' is not allowed during an AddNew or EditItem transaction. I'm trying to understand why this is happening and is there someway to avoid/workaround it.

<Window 
    x:Class="DataGridTest.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:Controls="clr-namespace:Microsoft.Windows.Controls;assembly=WPFToolkit"
    Title="Window1" 
    Height="300" 
    Width="300"
    x:Name="window"
    >
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="*"/>     
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="*"/>
        </Grid.ColumnDefinitions>
        <Controls:DataGrid
            Grid.Row="0"
            Grid.Column="0"
            AutoGenerateColumns="False"
            ItemsSource="{Binding ElementName=window, Path=Sam.Bobs}"
            SelectionMode="Single"
            SelectionUnit="Cell"
            >
            <Controls:DataGrid.Columns>
                <Controls:DataGridTextColumn
                    Header="Name"
                    Binding="{Binding Name, Mode=TwoWay}"
                    Width="*"
                    />
                <Controls:DataGridTemplateColumn
                    Header="Parent Bob"
                    Width="*"
                    >
                    <Controls:DataGridTemplateColumn.CellTemplate>
                        <DataTemplate>
                            <TextBlock Text="{Binding ParentBob.Name}"/>
                        </DataTemplate>
                    </Controls:DataGridTemplateColumn.CellTemplate>
                    <Controls:DataGridTemplateColumn.CellEditingTemplate>
                        <DataTemplate>
                            <ComboBox
                                DisplayMemberPath="Name"
                                ItemsSource="{Binding Parent.Bobs}"
                                SelectedItem="{Binding ParentBob, Mode=TwoWay}"
                                />
                        </DataTemplate>
                    </Controls:DataGridTemplateColumn.CellEditingTemplate>
                </Controls:DataGridTemplateColumn>
            </Controls:DataGrid.Columns>  
        </Controls:DataGrid>      
    </Grid>
</Window>
    public partial class Window1 : Window
    {
        public Window1()
        {
            Sam = new Sam();
            InitializeComponent();
        }

        public Sam Sam
        {
            get;
            private set;
        }
    }

    public class Sam
    {
        public Sam()
        {
            Bobs = new ObservableCollection<Bob>();
            Bobs.Add(new Bob { Name = "Bob1", Parent = this });
            Bobs.Add(new Bob { Name = "Bob2", Parent = this });
            Bobs.Add(new Bob { Name = "Bob3", Parent = this });
        }

        public ObservableCollection<Bob> Bobs
        {
            get;
            private set;
        }
    }

    public class Bob
    {
        public string Name
        {
            get;
            set;
        }

        public Bob ParentBob
        {
            get; 
            set;
        }

        public Sam Parent
        {
            get;
            set;
        }
    }
Although my real code uses view models, the sample above is simpler. Any help would be appreciated.
Thanks,
-Craig