Click here to Skip to main content
15,891,033 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
See more:
I have a combobox that has data that is populated from Database. I can use the binding of combobox into text box like :


But when the same is applied as the 1st column, the combobox feature is not firing, it behaves just as another textbox

What I have tried:

<DataGridTemplateColumn Header="ProductName" ClipboardContentBinding="{Binding ProductName}">
                            <DataGridTemplateColumn.CellTemplate >
                                <DataTemplate >
                                 <TextBox Text="{Binding  ProductName, NotifyOnTargetUpdated=True,  UpdateSourceTrigger=PropertyChanged}" >                                   </TextBox>
                                   
                                </DataTemplate>
                            </DataGridTemplateColumn.CellTemplate>
                            <DataGridTemplateColumn.CellEditingTemplate>
                                <DataTemplate>
                                    <ComboBox IsEditable="True" Name="cmbProductName"  ItemsSource="{StaticResource ProductNames}" SelectedItem="{Binding ProductName ,  Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" IsDropDownOpen="False" >

                                    </ComboBox>
                                </DataTemplate>
                            </DataGridTemplateColumn.CellEditingTemplate>
                        </DataGridTemplateColumn>
Posted
Updated 6-Sep-18 12:35pm

1 solution

Here is a working example for you...

First, a base class for INotifyPropertyChanged for DataBinding notifications:
C#
public abstract class ObservableBase : INotifyPropertyChanged
{
    public void Set<TValue>(ref TValue field, TValue newValue,
                            [CallerMemberName] string propertyName = "")
    {
        if (EqualityComparer<TValue>.Default.Equals(field, default(TValue))
            || !field.Equals(newValue))
        {
            field = newValue;
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;
}

Next we need a data model to hold each row for editing:
C#
public class PersonModel : ObservableBase
{
    private string name;
    public string Name
    {
        get { return name; }
        set { Set(ref name, value); }
    }

    private int age;
    public int Age
    {
        get { return age; }
        set { Set(ref age, value); }
    }

    private int income;
    public int Income
        {
        get { return income; }
        set { Set(ref income, value); }
    }
}

Next we need to have a ViewModel to link our data to the view:
C#
class MainViewModel
{
    public MainViewModel()
    {
        Mock();
    }

    private void Mock()
    {
        for (int i = 20; i < 120; i++)
        {
            AgeRange.Add(i);
        }

        for (int i = 0; i < 100; i++)
        {
            IncomeRange.Add(10000 + 10 * i);
        }

        for (int i = 0; i < 100; i++)
        {
            People.Add(new PersonModel
            {
                Name = $"Person {i}",
                Age = AgeRange[rand.Next(0, AgeRange.Count - 1)],
                Income = IncomeRange[rand.Next(0, IncomeRange.Count - 1)]
            });
        }
    }

    private Random rand = new Random();

    public ObservableCollection<PersonModel> People { get; }
        = new ObservableCollection<PersonModel>();

    public ObservableCollection<int> AgeRange { get; }
        = new ObservableCollection<int>();

    public ObservableCollection<int> IncomeRange { get; }
        = new ObservableCollection<int>();
}

Now we can do the View:
XML
<Window x:Class="DataGridColumnComboBox.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:DataGridColumnComboBox"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800">
    <Window.DataContext>
        <local:MainViewModel/>
    </Window.DataContext>
    <DataGrid ItemsSource="{Binding People}"
              AutoGenerateColumns="False"
              GridLinesVisibility="None" Margin="10">
        <DataGrid.Columns>
            <DataGridTextColumn Header="Name" Binding="{Binding Name}" Width="200"/>

            <DataGridComboBoxColumn Header="Age" Width="75"
                                    SelectedItemBinding="{Binding Age}">
                <DataGridComboBoxColumn.ElementStyle>
                    <Style TargetType="ComboBox">
                        <Setter Property="ItemsSource"
                                Value="{Binding RelativeSource={RelativeSource
                                    FindAncestor, 
                                    AncestorType={x:Type Window}},
                                    Path=DataContext.AgeRange}"/>
                    </Style>
                </DataGridComboBoxColumn.ElementStyle>
                <DataGridComboBoxColumn.EditingElementStyle>
                    <Style TargetType="ComboBox">
                        <Setter Property="ItemsSource"
                                Value="{Binding RelativeSource={RelativeSource
                                    FindAncestor,
                                    AncestorType={x:Type Window}},
                                    Path=DataContext.AgeRange}"/>
                    </Style>
                </DataGridComboBoxColumn.EditingElementStyle>
            </DataGridComboBoxColumn>

            <DataGridComboBoxColumn Header="Income" Width="150"
                                    SelectedItemBinding="{Binding Income}">
                <DataGridComboBoxColumn.ElementStyle>
                    <Style TargetType="ComboBox">
                        <Setter Property="ItemsSource"
                                Value="{Binding RelativeSource={RelativeSource
                                    FindAncestor, 
                                    AncestorType={x:Type Window}},
                                    Path=DataContext.IncomeRange}"/>
                    </Style>
                </DataGridComboBoxColumn.ElementStyle>
                <DataGridComboBoxColumn.EditingElementStyle>
                    <Style TargetType="ComboBox">
                        <Setter Property="ItemsSource"
                                Value="{Binding RelativeSource={RelativeSource
                                    FindAncestor,
                                    AncestorType={x:Type Window}},
                                    Path=DataContext.IncomeRange}"/>
                    </Style>
                </DataGridComboBoxColumn.EditingElementStyle>
            </DataGridComboBoxColumn>
        </DataGrid.Columns>
    </DataGrid>
</Window>

The view is quite verbose. You can simplify the code and reduce the typos by using styles:
XML
<DataGrid ItemsSource="{Binding People}"
          AutoGenerateColumns="False"
          GridLinesVisibility="None" Margin="10">
    <DataGrid.Resources>
        <Style TargetType="ComboBox" x:Key="AgeRangeStyle">
            <Setter Property="ItemsSource"
                    Value="{Binding RelativeSource={RelativeSource
                                FindAncestor, 
                                AncestorType={x:Type Window}},
                                Path=DataContext.AgeRange}"/>
        </Style>
        <Style TargetType="ComboBox" x:Key="IncomeRangeStyle">
            <Setter Property="ItemsSource"
                    Value="{Binding RelativeSource={RelativeSource
                                FindAncestor, 
                                AncestorType={x:Type Window}},
                                Path=DataContext.IncomeRange}"/>
        </Style>
    </DataGrid.Resources>
    <DataGrid.Columns>
        <DataGridTextColumn Header="Name" Binding="{Binding Name}" Width="200"/>

        <DataGridComboBoxColumn Header="Age" Width="75"
                                SelectedItemBinding="{Binding Age}"
                                ElementStyle="{StaticResource AgeRangeStyle}"
                                EditingElementStyle="{StaticResource AgeRangeStyle}"/>

        <DataGridComboBoxColumn Header="Income" Width="75"
                                SelectedItemBinding="{Binding Income}"
                                ElementStyle="{StaticResource IncomeRangeStyle}"
                                EditingElementStyle="{StaticResource
                                                                  IncomeRangeStyle}"/>

    </DataGrid.Columns>
</DataGrid>

Enjoy!

UPDATE: Changed first column to use a ComboBox editor... see OP comments below.

MainViewModel:
C#
class MainViewModel
{
    public MainViewModel()
    {
        Mock();
    }

    private void Mock()
    {
        for (int i = 20; i < 120; i++)
        {
            AgeRange.Add(i);
        }

        for (int i = 0; i < 100; i++)
        {
            IncomeRange.Add(10000 + 10 * i);
        }

        for (int i = 0; i < 100; i++)
        {
            People.Add(new PersonModel
            {
                Name = $"Person {i}",
                Age = AgeRange[rand.Next(0, AgeRange.Count - 1)],
                Income = IncomeRange[rand.Next(0, IncomeRange.Count - 1)]
            });
        }

        Names = new ObservableCollection<string>(People.Select(x => x.Name));
    }

    private Random rand = new Random();

    public ObservableCollection<PersonModel> People { get; }
        = new ObservableCollection<PersonModel>();

    public ObservableCollection<int> AgeRange { get; }
        = new ObservableCollection<int>();

    public ObservableCollection<int> IncomeRange { get; }
        = new ObservableCollection<int>();

    public ObservableCollection<string> Names { get; private set; }
}

And the View's DataGrid:
XML
<DataGrid ItemsSource="{Binding People}"
          AutoGenerateColumns="False"
          GridLinesVisibility="None" Margin="10">
    <DataGrid.Resources>
        <Style TargetType="ComboBox" x:Key="NamesStyle">
            <Setter Property="ItemsSource"
                    Value="{Binding RelativeSource={RelativeSource
                                FindAncestor, 
                                AncestorType={x:Type Window}},
                                Path=DataContext.Names}"/>
        </Style>
        <Style TargetType="ComboBox" x:Key="AgeRangeStyle">
            <Setter Property="ItemsSource"
                    Value="{Binding RelativeSource={RelativeSource
                                FindAncestor, 
                                AncestorType={x:Type Window}},
                                Path=DataContext.AgeRange}"/>
        </Style>
        <Style TargetType="ComboBox" x:Key="IncomeRangeStyle">
            <Setter Property="ItemsSource"
                    Value="{Binding RelativeSource={RelativeSource
                                FindAncestor, 
                                AncestorType={x:Type Window}},
                                Path=DataContext.IncomeRange}"/>
        </Style>
    </DataGrid.Resources>
    <DataGrid.Columns>
        <!--<DataGridTextColumn Header="Name" Binding="{Binding Name}" Width="200"/>-->

        <DataGridComboBoxColumn Header="Name" Width="75"
                                SelectedItemBinding="{Binding Name}"
                                ElementStyle="{StaticResource NamesStyle}"
                                EditingElementStyle="{StaticResource NamesStyle}"/>

        <DataGridComboBoxColumn Header="Age" Width="75"
                                SelectedItemBinding="{Binding Age}"
                                ElementStyle="{StaticResource AgeRangeStyle}"
                                EditingElementStyle="{StaticResource AgeRangeStyle}"/>

        <DataGridComboBoxColumn Header="Income" Width="75"
                                SelectedItemBinding="{Binding Income}"
                                ElementStyle="{StaticResource IncomeRangeStyle}"
                                EditingElementStyle="{StaticResource IncomeRangeStyle}"/>

    </DataGrid.Columns>
</DataGrid>

ComboBox selection works fine for the first column... Enjoy!
 
Share this answer
 
v2
Comments
Member 13796002 7-Sep-18 1:54am    
Hi Graeme_Grant, Thanks for the reply. But in the example shared by you, the combobox column is the second column. It works fine when its a second column, but not as the first column. As I need to fetch the data on other columns based on the combobox selection
Graeme_Grant 7-Sep-18 4:37am    
I don't think that you tried my solution... it will work with any column. I'll update the solution to show you...
Dennis W. M. 1-Jan-20 22:53pm    
This example got my solution working. Thanks!
Graeme_Grant 11-Jan-20 20:42pm    
Glad to hear that it helped!
abdou_31 25-Nov-20 11:08am    
This is so complicated

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900