Pergunta

I don't know how to properly return value from ComboboxColumn cell after selection. My ComboboxColum looks like this:

<DataGridComboBoxColumn CanUserSort="False" 
                        x:Name="cbcList" 
                        DisplayMemberPath="{Binding Person, Converter={StaticResource converter}}" 
                        Header="Person"/>

ItemsSource is set in the code behind as list of Person objects. Now, how I can get list of Person objects made from all selections in this column? I tried to make new list of Person obejcts and bind it using SelectedItemBinding, but it's either wrong way to do this or I made some mistakes.

Foi útil?

Solução

The SelectedItem does not have a property setter which means you cannot assign a binding to it. We can, however, track multiple selections via the SelectionChanged event.

Assumption: You have an ObservableCollection in the ViewModel called People.

Create a Collection property called SelectedPeople in the ViewModel

Public Collection<Person> SelectedPeople { get; set; }

Implement the SelectionChanged event in the XAML.

<DataGrid ItemsSource="{Binding Path=People}" SelectionChanged="Selector_OnSelectionChanged" />

The SelectionChanged handler in the code behind will look something like this.

private void Selector_OnSelectionChanged(object sender, SelectionChangedEventArgs e)
{
    if (e.AddedItems != null)
    {
        e.AddedItems.OfType<Person>()
            .ToList()
            .ForEach(ViewModel.SelectedPeople.Add);
    }

    if (e.RemovedItems != null)
    {
        e.RemovedItems.OfType<Person>()
            .ToList()
            .ForEach(p => ViewModel.SelectedPeople.Remove(p));
    }
}

I have removed exception management for brevity.

Edit - The above is about handling multiple selections from a DataGrid. I have renamed the PersonModel above to Person. It is the model that exposes data to the view. The ViewModel is the class that manages the Model(s) and functionality used to manipulate the Model(s). For further information, google MVVM pattern.

With regards to your original question, handling the binding between a DataGridComboBoxColumn and the DataGrid, I have created an example. The code that follows can be copied into a new project.

The Person model is

public class Person
{
    public string FirstName { get; set; } 
    public string Surname { get; set; }
    public string MiddleName { get; set; }
    public int Age { get; set; }
}

And the ViewModel is

public class MyViewModel
{
    public MyViewModel()
    {
        this.People = new ObservableCollection<Person>()
        {
            new Person() { FirstName = "A", Surname = "B", MiddleName = "C", Age = 1},
            new Person() { FirstName = "D", Surname = "E", MiddleName = "F", Age = 2},
            new Person() { FirstName = "G", Surname = "H", MiddleName = "I", Age = 3},
            new Person() { FirstName = "J", Surname = "K", MiddleName = "L", Age = 4},
            new Person() { FirstName = "M", Surname = "N", MiddleName = "O", Age = 5}
        };

        this.Items = new ObservableCollection<GridItem>()
        {
            new GridItem() { Person = this.People[0]},
            new GridItem() { Person = this.People[1]},
            new GridItem() { Person = this.People[2]},
            new GridItem() { Person = this.People[3]}
        };
    }

    public ObservableCollection<Person> People { get; set; }

    public ObservableCollection<GridItem> Items { get; set; }

}

The Code behind the View simply creates and exposes the ViewModel.

public partial class MainWindow : Window
{
    public MainWindow()
    {
        ViewModel = new MyViewModel();
        InitializeComponent();
    }

    public MyViewModel ViewModel { get; set; }
}

Leaving all the fun in the Xaml.

<Window x:Class="StackOverflow._20902950.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:this="clr-namespace:StackOverflow._20902950"
        DataContext="{Binding RelativeSource={RelativeSource Self}, Path=ViewModel}"
        Title="MainWindow" Height="350" Width="525">
    <Grid>
        <DataGrid ItemsSource="{Binding Path=Items}" AutoGenerateColumns="False">
            <DataGrid.Columns>
                <DataGridComboBoxColumn Header="Person" Width="100" DisplayMemberPath="FirstName" SelectedItemBinding="{Binding Path=Person}">
                    <DataGridComboBoxColumn.ElementStyle>
                        <Style TargetType="{x:Type ComboBox}">
                            <Setter Property="ItemsSource" Value="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type this:MainWindow}}, Path=ViewModel.People}" />
                        </Style>
                    </DataGridComboBoxColumn.ElementStyle>
                    <DataGridComboBoxColumn.EditingElementStyle>
                        <Style TargetType="{x:Type ComboBox}">
                            <Setter Property="ItemsSource" Value="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type this:MainWindow}}, Path=ViewModel.People}" />
                        </Style>
                    </DataGridComboBoxColumn.EditingElementStyle>
                </DataGridComboBoxColumn>
            </DataGrid.Columns>
        </DataGrid>
    </Grid>
</Window>

The this namespace will need to be changes to the namespace of your project.

I hope this helps.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top