1

I'm pretty new to WPF and MVVM, so I might be missing some basic understanding.

I am trying to build a list of feed that can be ordered. Every order demands the name, an amount and a unit.

enter image description here

The units should be placed in a combobox, and that's the problem. Depending on the method, the combobox doesn't appear, or is just plain empty.

The following is the XAML.

<UserControl x:Class="TestProject.View.FruitFoodList"
         DataContext="{Binding Test, Source={StaticResource Locator}}">
<Grid>
    <DataGrid ItemsSource="{Binding DummyFruitList}" IsReadOnly="True" Name="dgFeedList" AutoGenerateColumns="False">
        <DataGrid.Columns>
            <DataGridTextColumn Header="Feed" Binding="{Binding Name}" Width="*"/>
            <DataGridTemplateColumn Header="Amount">
                <DataGridTemplateColumn.CellTemplate>
                    <DataTemplate>
                        <!-- Code for amount here -->
                    </DataTemplate>
                </DataGridTemplateColumn.CellTemplate>
            </DataGridTemplateColumn>
            <DataGridComboBoxColumn Header="Unit">
                <!--Combobox for units here-->
            </DataGridComboBoxColumn>
        </DataGrid.Columns>
    </DataGrid>
</Grid>

Here's the viewmodel:

public class DummyViewModel : ViewModelBase
{
    private List<DummyProduct> _dummyFruit = new List<DummyProduct>();

    public List<DummyProduct> DummyFruitList
    {
        get { return _dummyFruit; }
        set { _dummyFruit = value; }
    }

    public List<Unit> DummyUnitList = new List<Unit> {
        new Unit { Name = "kg"},
        new Unit { Name = "piece(s)" },
        new Unit { Name = "box(es)" }
    };

    public DummyViewModel()
    {
        string[] lines = File.ReadAllLines("../../DummyFruit.txt", Encoding.UTF7);
        foreach (string product in lines)
        {
            DummyProduct dummyProduct = new DummyProduct(product);
            dummyProduct.Units = DummyUnitList;
            DummyFruitList.Add(dummyProduct);
        }
    }
}

And DummyProduct:

public class DummyProduct
{
    public DummyProduct(string product)
    {
        Name = product;
    }

    public string Name { get; set; }
    public List<Unit> Units;
}

The units might not be the same for every product. I have, without luck, tried the following solutions: Binding WPF ComboBox to a Custom List Binding ItemsSource of a ComboBoxColumn in WPF DataGrid

The above solutions didn't show a combobox at all for me. But again, I might be doing it wrong.

Making a stackpanel with a combobox in a datagridtemplate has so far been the only solution that got a combobox to appear, but the bindings makes no sense here.

T.Palludan
  • 176
  • 1
  • 2
  • 13
  • U forgot your items source as binding – Ugur Dec 07 '17 at 10:10
  • In the DataGridComboBoxColoumn? Adding the binding (to DummyFruitList I suppose) does nothing. – T.Palludan Dec 07 '17 at 10:16
  • I posted the answer. You can have a look. And use ObservableCollection instead of list. – Ugur Dec 07 '17 at 10:20
  • Yeah, use OCs and always make your collection properties read only. –  Dec 07 '17 at 16:08
  • I actually ended up doing it with a DataGridTemplateColumn as proposed in this answer: https://stackoverflow.com/questions/7088284/wpf-datagridtemplatecolumn-with-combobox-binding-mvvm-pattern as none of the solutions provided let me see any combobox, so I didn't have any chance to properly test the answers. What would be the proper response to this answer? – T.Palludan Dec 08 '17 at 09:00

2 Answers2

0

ItemsSource of ComboBox is missing and please use ObservableCollection instead of List. That should work;

   <DataGridComboBoxColumn Header="Unit" >
                <DataGridComboBoxColumn.ElementStyle>
                    <Style TargetType="ComboBox">
                        <Setter Property="ItemsSource" Value="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}, Path=DataContext.DummyUnitList}"/>
                    </Style>
                </DataGridComboBoxColumn.ElementStyle>
            </DataGridComboBoxColumn>
Ugur
  • 1,257
  • 2
  • 20
  • 30
0

XAML for your DataGrid Combobox Column

<DataGridComboBoxColumn Header="Unit" DisplayMemberPath="Name"  SelectedValuePath="Id" SelectedValueBinding="{Binding UnitId, UpdateSourceTrigger=PropertyChanged}"   MinWidth="280" Width="Auto" IsReadOnly="False">
    <DataGridComboBoxColumn.ElementStyle>
        <Style TargetType="ComboBox">
            <Setter Property="ItemsSource" Value="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type DataGrid}}, Path=DataContext.DummyUnitList, UpdateSourceTrigger=PropertyChanged}"/>
            <Setter Property="Width" Value="280" />
        </Style>
    </DataGridComboBoxColumn.ElementStyle>
    <DataGridComboBoxColumn.EditingElementStyle>
        <Style TargetType="ComboBox">
            <Setter Property="ItemsSource" Value="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type DataGrid}}, Path=DataContext.DummyUnitList, UpdateSourceTrigger=PropertyChanged}"/>
        </Style>
    </DataGridComboBoxColumn.EditingElementStyle>
</DataGridComboBoxColumn>

SelectedValueBinding="{Binding UnitId, UpdateSourceTrigger=PropertyChanged}" where UnitId is an element of you DataGrid ItemsSource, this is your selected value to store in your data base (or read from it)

DisplayMemberPath="Name" SelectedValuePath="Id" where Id and Name are properties of Unit class

DummyUnitList should be ObservableCollection<> instead of List<>

public ObservableCollection<Unit> DummyUnitList 
{
    get => _dummyUnitList ;
    set { _dummyUnitList = value; OnPropertyChanged(nameof(DummyUnitList)); }
}
Celso Lívero
  • 716
  • 2
  • 14
  • 18