question

SupunDev-2596 avatar image
0 Votes"
SupunDev-2596 asked HuiLiu-MSFT edited

My WPF DataGrid not displaying the Combobox

Hi Everyone I'm trying to generate a combox column from code behind for my datagrid.

XAML
```
<DataGrid
x:Name="ParaGrid"
Margin="12,240,12,12"
AutoGenerateColumns="True"
BorderBrush="Black"
BorderThickness="1"
IsReadOnly="False" />
```

CodeBehind

DataGridComboBoxColumn styleList1 = new DataGridComboBoxColumn();
styleList1.Header = "Tags";            
styleList1.ItemsSource = StyleHandler.GetParaList.ToArray<object>();
styleList1.IsReadOnly = false;
ParaGrid.Columns.Add(styleList1);


I can see the header is generated but no Combobox. What is the reason for this?

Any help is very much appreciated. Thank you very much in advance

dotnet-csharpwindows-wpfdotnet-wpf-xaml
5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

LloydSheen-3317 avatar image
0 Votes"
LloydSheen-3317 answered SupunDev-2596 commented

You have indicated that the DataGrid will create it's own columns. The header is simply the property name. All columns will be by default a DataGridTextColumn. If you want other column types you will need to generate your own columns in XAML for the DataGrid.

· 1
5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

Hi @LloydSheen-3317

Thank you very much for your advice.

I changed the code as follows:

<DataGrid
                x:Name="ParaGrid"
                Margin="12,220,12,12"
                AutoGenerateColumns="False"
                BorderBrush="Black"
                BorderThickness="1"
                IsReadOnly="False"
                SelectedIndex="1"
                SelectionMode="Single">
                <DataGrid.Columns>
                    <DataGridComboBoxColumn
                        x:Name="Tags"
                        Header="Tags" />
                </DataGrid.Columns>
            </DataGrid>


Code Behind

Tags.ItemsSource = StyleHandler.GetParaList.ToArray<object>();


Still not working. Is this method wrong ?

0 Votes 0 ·
LloydSheen-3317 avatar image
0 Votes"
LloydSheen-3317 answered

In the DataGridComboBoxColumn you need to indicate the collection that populates the ComboBox and the Selected item in the collection. I find that DataGridComboBoxColumn is difficult to work with. I would suggest a DataGridTemplateColumn with the CellTemplate a standard ComboBox with binding for the collection of items to choose from and the SelectedItem to get the selected item in the ComboBox.

5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

HuiLiu-MSFT avatar image
0 Votes"
HuiLiu-MSFT answered HuiLiu-MSFT edited

For binding the collection to the Combobox in the DataGrid, you could refer to the following example. When editing the last row of cells to add a new row in the DataGrid, what you can do is:

  1. Make sure your DataGrid has CanUserAddRows=True.

  2. Make sure the class in the collectiuon that you are binding has a default constructor (no parameters).

  3. Make sure the collection type is not readonly.

For more information, you can refer here.

The code of xaml:

 <Window.DataContext>
         <local:ViewModel></local:ViewModel>
     </Window.DataContext>
     <Grid Background="AliceBlue" >
         <DataGrid Name="dataGrid" ItemsSource="{Binding MyCollection}"  BorderBrush="Black"
                 BorderThickness="1" AutoGenerateColumns="False"  CanUserAddRows="True" >
             <DataGrid.Columns>
                 <DataGridTextColumn Binding="{Binding Name}" Header="Name of person"/>
                 <DataGridTemplateColumn Header="Age of person" >
                     <DataGridTemplateColumn.CellTemplate>
                         <DataTemplate>
                                
                             <ComboBox ItemsSource="{Binding Path=DataContext.Source1, RelativeSource={RelativeSource Mode=FindAncestor,AncestorType=Window}}"
                               IsSynchronizedWithCurrentItem="False" IsHitTestVisible="False"  SelectedValue="{Binding Age}"  SelectedValuePath="Number"  DisplayMemberPath="Number"/>
                         </DataTemplate>
                     </DataGridTemplateColumn.CellTemplate>
                     <DataGridTemplateColumn.CellEditingTemplate>
                         <DataTemplate>
                             <StackPanel>
                                 <ComboBox ItemsSource="{Binding Path=DataContext.Source1, RelativeSource={RelativeSource Mode=FindAncestor,AncestorType=Window}}"
                                SelectedValue="{Binding Age}"  SelectedValuePath="Number"  DisplayMemberPath="Number"
                                           IsSynchronizedWithCurrentItem="False" IsEditable="True"/>
                             </StackPanel>
                         </DataTemplate>
                     </DataGridTemplateColumn.CellEditingTemplate>
                 </DataGridTemplateColumn>
                 <DataGridTextColumn Binding="{Binding Salary}" Header="Persons salary"/>
             </DataGrid.Columns>
         </DataGrid>
     </Grid>

The code of xaml.cs:

 using System.Windows;
 using System.Collections.ObjectModel;
 using System.ComponentModel;
 using System;
 using System.Windows.Controls;
    
 namespace DataGridCombobox
 {
   public partial class MainWindow : Window
   {
     private bool _justCreatedNewItem;
     public MainWindow()
     {
       InitializeComponent();
       dataGrid.BeginningEdit += (o, e) =>
       {
         if (_justCreatedNewItem)
         {
           dataGrid.CommitEdit(DataGridEditingUnit.Row, true);
           _justCreatedNewItem = false;
         }
       };
       dataGrid.InitializingNewItem += (o, e) => { _justCreatedNewItem = true; };
     }
   }
   public class ViewModel : INotifyPropertyChanged
   {
     public event PropertyChangedEventHandler PropertyChanged ;
    
     private void NotifyPropertyChanged(String info)
     {
       if (PropertyChanged != null)
       {
         PropertyChanged(this, new PropertyChangedEventArgs(info));
       }
     }
     private ObservableCollection<MyClass> _myCollection { get; set; }
    
     public ObservableCollection<MyClass> MyCollection
     {
       get { return _myCollection; }
       set
       {
         _myCollection = value;
         NotifyPropertyChanged(nameof(MyCollection));
       }
     }
     private ObservableCollection<Source1> _source1 { get; set; }
     public ObservableCollection<Source1> Source1
     {
       get { return _source1; }
       set { _source1 = value; NotifyPropertyChanged(nameof(Source1)); }
     }
     public ViewModel()
     {
       _source1 = new ObservableCollection<Source1>();
       _myCollection = new ObservableCollection<MyClass>();
       SetupSource();
    
     }
     private void SetupSource()
     {
       _source1.Add(new Source1(2));
       _source1.Add(new Source1(3));
       _source1.Add(new Source1(5));
       _source1.Add(new Source1(8));
       _myCollection.Add(new MyClass("name1",12,30.3));
       _myCollection.Add(new MyClass("name2",22,30.3));
       _myCollection.Add(new MyClass("name3",32,30.3));
       _myCollection.Add(new MyClass("name3",32,30.3));
     }
    
    
   }
   public class Source1
   {
     public int Number { get; set; }
     public Source1(int n)
     {
       Number = n;
     }
   }
   public class MyClass
   {
     public string Name { get; set; }
     public int Age { get; set; }
     public double Salary { get; set; }
     public MyClass()
     {
    
     }
     public MyClass(string n, int a, double s)
     {
       Name = n;
       Age = a;
       Salary = s;
     }
   }
 }

The picture of result:
137617-5.gif


If the response is helpful, please click "Accept Answer" and upvote it.
Note: Please follow the steps in our documentation to enable e-mail notifications if you want to receive the related email notification for this thread.


4.gif (36.8 KiB)
5.gif (77.6 KiB)
· 2
5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

Hi @HuiLiu-MSFT

Thank you very much for your input. My requirement is a bit different. Really I'm trying to mimic the functionality of a WinForms app that I have created. In WinForms, I used a data grid to load lists to Combobox and added a button column to initiate a functionality. There is no existing data(rows). I don't use this to show existing data. I just need this list to be populated into the Combobox. As you can see in the following GIF once the user selected an item from the combo and populated the grid row new row will automatically be added to the latter.

In WPF I tried to follow the same thing but from the looks of it, there are huge differences with WinForm Data grids. If this is not ideal is there any other way to create this functionality with WPF?

137350-ssssss.gif


0 Votes 0 ·
ssssss.gif (78.5 KiB)

Hi,@SupunDev-2596. May I know if you have got any chance to check my answer? I am glad to help if you have any other questions.

0 Votes 0 ·
LloydSheen-3317 avatar image
0 Votes"
LloydSheen-3317 answered

Not about your problem in general but I would suggest if you are going to use WPF to learn XAML and data binding. When I switched from WinForms to WPF it was to "make a better looking app". I spent as you are doing lots of time trying to simulate what was happening in WinForms in WPF. This caused lots of problems as you have found and can be solved by using WPF in the WPF way.

Learn MVVM and you will have the basis for solving most of your WPF problems.

5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.