Home > Net >  GridTemplateColumn databinding to complex properties
GridTemplateColumn databinding to complex properties

Time:06-02

I have 3 model classes as follows (Vegetable, Fruit and ItemInBasket):

public class Vegetable
    {
        string name;
        public string Name
        {
        get { return name; }
        set { name = value; }
    }


    public Vegetable(string _Name)
    {
        this.Name = _Name;
    }
}

public class Fruit
{
    string name;
    public string Name
    {
        get { return name; }
        set { name = value; }
    }


    public Fruit(string _Name)
    {
        this.Name = _Name;
    }
}

public class ItemInBasket
{
    string name;
    public string Name
    {
        get { return name; }
        set { name = value; }
    }

    object fruitorvegetable;
    public object FruitOrVegetable
    {
        get { return fruitorvegetable; }
        set { fruitorvegetable = value; }
    }

    int quantity;
    public int Quantity
    {
        get { return quantity; }
        set { quantity = value; }
    }

    public ItemInBasket(string _Name, object _FruitOrVegetable, int _Quantity)
    {
        this.Name = _Name;
        this.FruitOrVegetable = _FruitOrVegetable;
        this.quantity = _Quantity;
    }
}

My ViewModel is:

public class ViewModel
    {
    private ObservableCollection<object> _availableItems;
    public ObservableCollection<object> AvailableItems
    {
        get { return _availableItems; }
        set { _availableItems = value; }
    }

    private ObservableCollection<ItemInBasket> _itemsInBasket;
    public ObservableCollection<ItemInBasket> ItemsInBasket
    {
        get { return _itemsInBasket; }
        set { _itemsInBasket = value; }
    }

    public ViewModel()
    {
        _availableItems = new ObservableCollection<object>();
        _itemsInBasket = new ObservableCollection<ItemInBasket>();
        this.GenerateAvailableItems();
        this.GenerateItemsInBasket();
    }

    private void GenerateAvailableItems()
    {
        _availableItems.Add(new Vegetable("Broccoli"));         // index 0
        _availableItems.Add(new Vegetable("Kale"));             // index 1
        _availableItems.Add(new Vegetable("Spinach"));          // index 2
        _availableItems.Add(new Vegetable("Carrots"));          // index 3
        _availableItems.Add(new Vegetable("Garlic"));           // index 4

        _availableItems.Add(new Fruit("Apple"));                // index 5
        _availableItems.Add(new Fruit("Orange"));               // index 6
        _availableItems.Add(new Fruit("Pear"));                 // index 7
        _availableItems.Add(new Fruit("Cherry"));               // index 8
        _availableItems.Add(new Fruit("Grape"));                // index 9
    }

    private void GenerateItemsInBasket()
    {
        _itemsInBasket.Add(new ItemInBasket("Apples",_availableItems[5],3));
        _itemsInBasket.Add(new ItemInBasket("Kale", _availableItems[1], 10));
        _itemsInBasket.Add(new ItemInBasket("Grape", _availableItems[9], 2));
        _itemsInBasket.Add(new ItemInBasket("Carrots", _availableItems[3], 1));
    }
}

I am trying to be able to modify the FruitOrVegetable inside of each ItemInBasket displayed in the datagrid but I have an issue with the data binding. I am using Syncfusion datagrid but I think it shouldnt affect anything.

    <syncfusion:SfDataGrid AutoGenerateColumns="False" SelectionMode="Single"
                    AllowEditing="True" AllowDeleting="True" ItemsSource="{Binding ItemsInBasket,Source={StaticResource viewModel}}">
        <syncfusion:SfDataGrid.Columns>

            <syncfusion:GridTemplateColumn MappingName="FruitOrVegetable" HeaderText="Order">
                <syncfusion:GridTemplateColumn.EditTemplate>
                    <DataTemplate>
                        <ComboBox IsEditable="True" DisplayMemberPath="Name"  SelectedValuePath="Name"
                                  Text="{Binding FruitOrVegetable.Name, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
                                  ItemsSource="{Binding AvailableItems, Source={StaticResource viewModel}}"/>
                    </DataTemplate>
                </syncfusion:GridTemplateColumn.EditTemplate>
                <syncfusion:GridTemplateColumn.CellTemplate>
                    <DataTemplate>
                        <TextBlock Text="{Binding Name}" />
                    </DataTemplate>
                </syncfusion:GridTemplateColumn.CellTemplate>
            </syncfusion:GridTemplateColumn>

            <syncfusion:GridNumericColumn HeaderText="Quantity" MappingName ="Quantity"/>

        </syncfusion:SfDataGrid.Columns>
    </syncfusion:SfDataGrid>

CodePudding user response:

Your requirement to display the modified value of the FruitOrVegetable in SfDataGrid can be achieved by binding the SelectedValue property of ComboBox. Please refer to the below code snippet,

                        <ComboBox IsEditable="True" DisplayMemberPath="Name"  SelectedValuePath="Name"
                                  SelectedValue="{Binding Name}"
                                  Text="{Binding FruitOrVegetable.Name, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
                                  ItemsSource="{Binding AvailableItems, Source={StaticResource viewModel}}"/>



                   

CodePudding user response:

This is where what we call an "interface" comes in handy. This gives you the surety that the properties are indeed present on this object. Consider it a contract between the class and interface to always include some properties.
You can learn more about it here

You can define an interface like this

public interface INamedItem
{
    string Name {get;set;}   
}

Now instead of the object type use this interface(first implement them in your vegetable and fruit class) so that you can easily bind to it(and many other benefits)

public class Vegetable : INamedItem
    {
        string name;
        public string Name
        {
        get { return name; }
        set { name = value; }
    }


    public Vegetable(string _Name)
    {
        this.Name = _Name;
    }
}

public class Fruit: INamedItem
{
    string name;
    public string Name
    {
        get { return name; }
        set { name = value; }
    }


    public Fruit(string _Name)
    {
        this.Name = _Name;
    }
}

public class ItemInBasket
{
    string name;
    public string Name
    {
        get { return name; }
        set { name = value; }
    }

    INamedItem fruitorvegetable;
    public object FruitOrVegetable
    {
        get { return fruitorvegetable; }
        set { fruitorvegetable = value; }
    }

    int quantity;
    public int Quantity
    {
        get { return quantity; }
        set { quantity = value; }
    }

    public ItemInBasket(string _Name, INamedItem _FruitOrVegetable, int _Quantity)
    {
        this.Name = _Name;
        this.FruitOrVegetable = _FruitOrVegetable;
        this.quantity = _Quantity;
    }
}

For your available items it becomes:

private ObservableCollection<INamedItem> _availableItems;
    public ObservableCollection<INamedItem> AvailableItems
    {
        get { return _availableItems; }
        set { _availableItems = value; }
    }

Now add normally as you have in your code so no more changes to that and check if it works :)

  • Related