0

I have this XAML

<DataGrid ItemsSource="{Binding Users}"
          CanUserAddRows="False"
          SelectedItem="{Binding SelectedUser}"
          AutoGenerateColumns="False"
          Grid.Column="0">
    <DataGrid.Columns>
        <DataGridTextColumn Header="First name" Binding ="{Binding FirstName}"/>
        <DataGridTextColumn Header="Last name" Binding ="{Binding LastName}"/>
        <DataGridComboBoxColumn Width="*" Header="Catégorie" 
            SelectedItemBinding="{Binding Role}">
            <DataGridComboBoxColumn.ElementStyle>
                <Style>
                     <Setter Property="ComboBox.ItemsSource"
                             Value="{Binding Path=DataContext.ComboBox_Roles, 
                             RelativeSource={RelativeSource 
                             FindAncestor, AncestorType={x:Type UserControl}}}" />
                </Style>
                </DataGridComboBoxColumn.ElementStyle>
                    <DataGridComboBoxColumn.EditingElementStyle>
                        <Style>
                            <Setter Property="ComboBox.ItemsSource" Value="{Binding 
                             Path=DataContext.ComboBox_Roles, RelativeSource={RelativeSource 
                             FindAncestor, AncestorType={x:Type UserControl}}}" />
                        </Style>
                    </DataGridComboBoxColumn.EditingElementStyle>
                </DataGridComboBoxColumn>             
    </DataGrid.Columns>
</DataGrid>

I want combobox to bind to a my roles collection
My model

public class User
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public string Role { get; set; }
}

And in my view model:

public ManageUsersViewModel()
{
    _users = new ObservableCollection<User>
    {
        new User { FirstName = "First1", LastName = "Last1", Role = "Admin" },
        new User { FirstName = "Last2", LastName = "Last2", Role ="User" },
    };

    ComboBox_Roles = new ObservableCollection<string> { "ABC", "BCD", "ASDSAD" };
}

public ObservableCollection<User> Users
{
    get => _users;
    set
    {
        _users = value;
    }
}

public ObservableCollection<string> ComboBox_Roles { get; set; }

How can i bind this items? Seems like the problem is that i can't bind that way to a collection inside a collection. The thing i want to implement that is i have a combobox with a role list in it, and i can change my user's role by selecting one of the values of combobox. Upd: updated code because i realised i was doing.

Nicefsf
  • 140
  • 1
  • 1
  • 9
  • Would you please clarify your goal in greater detail? Do you wish to display all values provided in the list? – Drreamer Apr 30 '20 at 09:02
  • Does this answer your question? [Binding DataGridComboBoxColumn](https://stackoverflow.com/questions/16303114/binding-datagridcomboboxcolumn) – Pavel Anikhouski Apr 30 '20 at 09:05
  • @Drreamer i have list of users, each user has his own collection of his roles (strings). I want to display those roles using combobox – Nicefsf Apr 30 '20 at 09:31
  • @PavelAnikhouski seems like it's not, i already tried this, and it didn't help me – Nicefsf Apr 30 '20 at 09:32
  • The ComboBox is not meant to displaying a list of values. It allows displaying/selecting one of the items from the list. If you wish to display multiple values at once, then it is better to use a simple text column and define a converter to merge all values in a single string. Eg. as shown here https://stackoverflow.com/a/345515/12797700 – Drreamer Apr 30 '20 at 09:44
  • The thing i want to implement is i have a combobox with a role list in it, and i can change my user's role by selecting one of the values of combobox. I think i will update my question to make it's clearer – Nicefsf Apr 30 '20 at 09:48
  • Thank you for your update. Your new code version works mostly well. I have only update binding in the https://github.com/Drreamer/GridComboBox example to use this solution. I suggest you check the Debug -> Window -> Output to see whether some binding works incorrectly in your project. – Drreamer Apr 30 '20 at 10:27
  • @Drreamer your example works like a charm, thanks a lot, i'll try this. – Nicefsf Apr 30 '20 at 11:06
  • @Drreamer you should add your code snippet as a answer so i can mark it as a solution – Nicefsf Apr 30 '20 at 11:16
  • You are welcome, @Nicefsf. Glad to here that my assistance was helpful. – Drreamer Apr 30 '20 at 12:05

2 Answers2

2

The following code demonstrates a possible way to bind a DataGridComboBoxColumn

<DataGrid ItemsSource="{Binding Users}" SelectedItem="{Binding SelectedUser}" AutoGenerateColumns="False">
   <DataGrid.Columns>
      <DataGridTextColumn Header="First name" Binding ="{Binding FirstName}"/>
      <DataGridTextColumn Header="Last name" Binding ="{Binding LastName}"/>
      <DataGridComboBoxColumn Width="*" Header="Catégorie" SelectedItemBinding="{Binding Role}">
         <DataGridComboBoxColumn.ElementStyle>
            <Style>
               <Setter Property="ComboBox.ItemsSource"
                        Value="{Binding Path=DataContext.ComboBox_Roles, 
                        RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type DataGrid}}}" />
            </Style>
         </DataGridComboBoxColumn.ElementStyle>
         <DataGridComboBoxColumn.EditingElementStyle>
            <Style>
               <Setter Property="ComboBox.ItemsSource" 
                        Value="{Binding Path=DataContext.ComboBox_Roles, 
                        RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type DataGrid}}}" />
            </Style>
         </DataGridComboBoxColumn.EditingElementStyle>
      </DataGridComboBoxColumn>
   </DataGrid.Columns>
</DataGrid>

And the ViewModel

public class User {
   public string FirstName { get; set; }
   public string LastName { get; set; }
   public string Role { get; set; }
}
public class ManageUsersViewModel {
   public ManageUsersViewModel() {
      Users = new ObservableCollection<User>      {
                  new User { FirstName = "First1", LastName = "Last1", Role = "Admin" },
                  new User { FirstName = "Last2", LastName = "Last2", Role ="User" }};
      ComboBox_Roles = new ObservableCollection<string> { "Admin", "User", "Other" };
   }
   public ObservableCollection<User> Users { get; set; }
   public ObservableCollection<string> ComboBox_Roles { get; set; }
}

A test project: https://github.com/Drreamer/GridComboBox

Drreamer
  • 332
  • 1
  • 10
1

You need to define your DataGridComboBoxColumn like :

<DataGridComboBoxColumn Width="*" Header="Catégorie" 
                        SelectedItemBinding="{Binding Roles}">
  <DataGridComboBoxColumn.ElementStyle>
    <Style>
      <Setter Property="ComboBox.ItemsSource" Value="{Binding 
                   Path=DataContext.ComboBox_Roles, RelativeSource={RelativeSource 
                   FindAncestor, AncestorType={x:Type UserControl}}}" />
    </Style>
  </DataGridComboBoxColumn.ElementStyle>
  <DataGridComboBoxColumn.EditingElementStyle>
    <Style>
      <Setter Property="ComboBox.ItemsSource" Value="{Binding 
                   Path=DataContext.ComboBox_Roles, RelativeSource={RelativeSource 
                   FindAncestor, AncestorType={x:Type UserControl}}}" />
    </Style>
  </DataGridComboBoxColumn.EditingElementStyle>
</DataGridComboBoxColumn>

With (In your VM):

public ManageUsersViewModel()
{
    ComboBox_Roles= new ObservableCollection<string>(getCategoryListeSource());

    _users = new ObservableCollection<User>
    {
        new User { FirstName = "First1", LastName = "Last1", Roles = "Admin", },
        new User { FirstName = "Last2", LastName = "Last2", Roles = "User", },
    }; // populating to test
}

#region Properties
public ObservableCollection<string> Roles { get; set; }

private ObservableCollection<User> _users;
public ObservableCollection<User> Users
{
    get => _users;
    set
    {
        _users = value;
    }
}
#endregion Properties

#region Private Method
private List<string> getCategoryListeSource()
{
    List<string> list = new List<string>();

    liste.Add("User");
    liste.Add("Admin");

    return list;
}
#endregion Private Method

Class : User.cs

public class User
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
    //public ObservableCollection<string> Roles { get; set; } REMOVE THIS
}

Then, you can use your SelectedUser property to return data from your datagrid.

Zeratec
  • 13
  • 8
  • So i'm defined public property ComboBox_Roles, and initilized it, but when i'm opening my combobox, it still has no items. – Nicefsf Apr 30 '20 at 09:42
  • I modified my answer. I redefined your two ObservableCollection in the VM. I didn't compile this code. – Zeratec Apr 30 '20 at 10:10
  • I did some updations as i mentioned in updated question. Your approach were right, but for some reason didn't work for me. But your code helped me figure out my binding problems, thanks. – Nicefsf Apr 30 '20 at 11:15