1
votes

I have a DataGridTemplateColumn combobox that binds to a separate ItemsSource It seems by binding this combobox to another source it changes the DataContext.

So I'm having issues binding the value of the selected item in the combobox to the DataContext of the selected row in the DataGrid.

XAML:

<DataGrid HorizontalAlignment="Left"  ItemsSource="{Binding Path=WorldDataList}"  SelectedItem="{Binding SelectedWorldData}">           
    <DataGridTemplateColumn Header="Country" >
        <DataGridTemplateColumn.CellTemplate >
            <DataTemplate>
                <ComboBox ItemsSource="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type StackPanel}},Path=DataContext.Countries}" 
                          SelectedItem="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type DataGrid}}, Path=SelectedItem.Country}" 
                          SelectedIndex="0"/>  
            </DataTemplate>
            </DataGridTemplateColumn.CellTemplate>
    </DataGridTemplateColumn>
</DataGrid>

C#:

class WorldDataViewModel : ObservableObject
{
    private ObservableCollection<WorldData> _worldDataList = new ObservableCollection<WorldData>();
    public ObservableCollection<WorldData> WorldDataList
    {
        get { return _worldDataList; }
        set
        {
            Set(ref _worldDataList, value);
        }
    }

    public List<string> Countries {get;set;}

    private WorldData worldData;
    private WorldData SelectedWorldData
    {
        get{return worldData;}
        set
        {
            Set(ref worldData, value);
        }
    }
}

class WorldData : ObservableObject
{
    private string country;
    public string Country
    {
        get{return country;} 
        set
        {
            Set(ref country, value);
        }  
}

I get the exception:

System.Windows.Data Error: 23 : Cannot convert '{NewItemPlaceholder}' from type 'NamedObject' to type 'WorldData' for 'en-US' culture with default conversions; consider using Converter property of Binding. NotSupportedException:'System.NotSupportedException: TypeConverter cannot convert from MS.Internal.NamedObject. at System.ComponentModel.TypeConverter.GetConvertFromException(Object value) at System.ComponentModel.TypeConverter.ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, Object value) at MS.Internal.Data.DefaultValueConverter.ConvertHelper(Object o, Type destinationType, DependencyObject targetElement, CultureInfo culture, Boolean isForward)' Exception thrown: 'System.NotSupportedException' in PresentationFramework.dll

It seems like I should use a type converter but it seems I shouldn't do this from the very little I've been able to find on SO

I think for now I'm just going to give up and add a separate box for the combobox and bind to the selected item of the Datagrid. I don't find it as intuitive so please if you have any clever ideas.

1

1 Answers

1
votes

Here is my full test app that save back the selected Country to the WorldData view model. Without the UpdateSourceTrigger at the SelectedItem it doesn't work.

<Window
    x:Class="ComboboxInDataGrid.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"
    Title="MainWindow"
    Width="525"
    Height="350"
    mc:Ignorable="d">
    <Grid>
        <DataGrid x:Name="me"
            HorizontalAlignment="Left"
            AutoGenerateColumns="False"
            CanUserAddRows="False"
            ItemsSource="{Binding Path=WorldDataList}"
            SelectedItem="{Binding SelectedWorldData}">
            <DataGrid.Columns>
                <DataGridTemplateColumn Header="Country">
                    <DataGridTemplateColumn.CellTemplate>
                        <DataTemplate>
                            <Grid>
                                <ComboBox ItemsSource="{Binding RelativeSource={RelativeSource FindAncestor, 
                                                                                               AncestorType={x:Type DataGrid}},
                                                                Path=DataContext.Countries}"
                                          SelectedItem="{Binding Path=Country, 
                                                                 Mode=TwoWay,
                                                                 UpdateSourceTrigger=PropertyChanged}" />
                            </Grid>
                        </DataTemplate>
                    </DataGridTemplateColumn.CellTemplate>
                </DataGridTemplateColumn>
            </DataGrid.Columns>
        </DataGrid>
    </Grid>
</Window>


using System.Collections.Generic;
using System.Windows;

namespace ComboboxInDataGrid
{
    public partial class MainWindow : Window
    {
        public MainWindow ()
        {
            DataContext = new WorldDataViewModel ();
            InitializeComponent ();
        }
    }

    class WorldDataViewModel
    {
        public WorldDataViewModel ()
        {
            var c1 = "USA";
            var c2 = "Canada";
            var c3 = "Brasil";
            var c4 = "Brasfsdfsil";

            Countries = new List<string> ();
            Countries.Add (c1);
            Countries.Add (c2);
            Countries.Add (c3);
            Countries.Add (c4);

            _worldDataList.Add (new WorldData { Index = 1, Country = c2 });
            _worldDataList.Add (new WorldData { Index = 2, Country = c3 });
            _worldDataList.Add (new WorldData { Index = 3, Country = c4 });
        }

        private List<WorldData> _worldDataList = new List<WorldData> ();
        public List<WorldData> WorldDataList
        {
            get
            {
                return _worldDataList;
            }
            set
            {
                _worldDataList = value;

            }
        }

        public List<string> Countries { get; set; }

        private WorldData worldData;
        public WorldData SelectedWorldData
        {
            get
            {
                return worldData;
            }

            set
            {
                worldData = value;
            }
        }
    }

    public class WorldData
    {
        public int Index { get; set; }

        private string country;
        public string Country
        {
            get { return country; }
            set
            {
                country = value;
            }
        }
    }
}