Patrick Vogt
Patrick Vogt

Reputation: 916

Retrieve values from many dynamically added comboboxes

I have to implement an application which the user is able to select many different values from a unknown amout of comboboxes. If the user click on the "plus" button, a new row with five comboboxes appear. If the "minus" button is pressed, the last row disappears.

XAML:

<WrapPanel Margin="6,6,0,3">
    <Button Command="{Binding AddTextBoxRowCommand}">
        <Image Source="pack://application:,,,/Images/Dialogs/FI_Hinzufuegen_16x16.png" Width="16" Height="16" />
    </Button>
    <Button IsEnabled="{Binding IsRemoveButtonEnabled}" Command="{Binding RemoveTextBoxRowCommand}" Margin="6,0,0,0">
        <Image Source="pack://application:,,,/Images/Dialogs/FI_Loeschen_16x16.png" Width="16" Height="16" />
    </Button>
</WrapPanel>

<!-- Segment und Feld auswahl -->
<ItemsControl ItemsSource="{Binding TextBoxRowCollection}">
    <ItemsControl.ItemTemplate>
        <DataTemplate>
            <WrapPanel>
                <ComboBox SelectedItem="SelectedSegmentList1" ItemsSource="{Binding Path=SegmentList1}" DisplayMemberPath="SegmentName" SelectedValuePath="SegmentFile" />
                <ComboBox SelectedItem="SelectedFieldList1" ItemsSource="{Binding Path=FieldList1}" DisplayMemberPath="FieldName" SelectedValuePath="Type" />
                <ComboBox SelectedItem="SelectedOperationList" ItemsSource="{Binding Path=DZOperationList}" DisplayMemberPath="OpName" SelectedValue="OpType" />
                <ComboBox SelectedItem="SelectedSegmentList2"  ItemsSource="{Binding Path=SegmentList2}" DisplayMemberPath="SegmentName" SelectedValuePath="SegmentFile" />
                <ComboBox SelectedItem="SelectedFieldList2" ItemsSource="{Binding Path=FieldList2}" DisplayMemberPath="FieldName" SelectedValuePath="Type" />
            </WrapPanel>
        </DataTemplate>
    </ItemsControl.ItemTemplate>
</ItemsControl>

ViewModel:

using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Linq;
using System.Windows.Input;
using DataAccessLayer.DirectoryParser;
using DataAccessLayer.Settings;
using Model;
using ViewModelBase;

namespace ViewModel
{
    public class ModalDialogValueViewModel : ViewModelBase.ViewModelBase
    {
        private RelayCommand addTextBoxRowCommand;
        private RelayCommand removeTextBoxRowCommand;

        private bool isRemoveButtonEnabled;

        private OperationModel opModel;
        private Settings settings;
        private List<Segment> segments;
        private List<Field> fields;

        /// <summary>
        /// Initialisiert das ModalDialogValueViewModel
        /// </summary>
        public ModalDialogValueViewModel()
        {
            settings = new Settings();
            opModel = new OperationModel();

            Segments = PKSegmentParser.GetSegments(settings.PKDirectory, "PROD");

            TextBoxRowCollection = new ObservableCollection<ObjectStructureHelper>();
            TextBoxRowCollection.Add(new ObjectStructureHelper(Segments, Fields, opModel.OpList, Segments, Fields));

            this.PropertyChanged += new PropertyChangedEventHandler(modalDialogValueViewModel_PropertyChanged);
        }

        public bool IsRemoveButtonEnabled
        {
            get { return isRemoveButtonEnabled; }
            set
            {
                if (isRemoveButtonEnabled != value)
                {
                    isRemoveButtonEnabled = value;
                    OnPropertyChanged("IsRemoveButtonEnabled");
                }
            }
        }

        public ObservableCollection<ObjectStructureHelper> TextBoxRowCollection { get; set; }
        public List<Segment> Segments
        {
            get { return segments; }
            set
            {
                if ((segments == null && value != null) || !segments.SequenceEqual(value))
                {
                    segments = value;
                    OnPropertyChanged("Segments");
                }
            }
        }

        public List<Field> Fields
        {
            get { return fields; }
            set
            {
                if ((fields == null && value != null) || !fields.SequenceEqual(value))
                {
                    fields = value;
                    OnPropertyChanged("Fields");
                }
            }
        }

        public ICommand AddTextBoxRowCommand
        {
            get
            {
                if (addTextBoxRowCommand == null)
                    addTextBoxRowCommand = new RelayCommand(p => ExecuteAddFieldRowCommand());

                return addTextBoxRowCommand;
            }
        }

        public ICommand RemoveTextBoxRowCommand
        {
            get
            {
               if (removeTextBoxRowCommand == null)
                   removeTextBoxRowCommand = new RelayCommand(p => ExecuteRemoveTextBoxRowCommand());

               return removeTextBoxRowCommand;
            }
        }

        /// <summary>
        /// Fügt eine Zeile mit für weitere Feld-Verknüpfungen hinzu
        /// </summary>
        private void ExecuteAddFieldRowCommand()
        {
            TextBoxRowCollection.Add(new ObjectStructureHelper(Segments, Fields, opModel.OpList, Segments, Fields));
            if (TextBoxRowCollection.Count > 1)
                IsRemoveButtonEnabled = true;
        }

        /// <summary>
        /// Entfernt eine Zeile von Feld-Verknüpfungen
        /// </summary>
        private void ExecuteRemoveTextBoxRowCommand()
        {
            var count = TextBoxRowCollection.Count;
            if (count > 1)
                TextBoxRowCollection.RemoveAt(count - 1);

            if (count == 2)
                IsRemoveButtonEnabled = false;
        }

        /// <summary>
        /// ModalDialogValueViewModel PropertyChanged EventHandler
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void modalDialogValueViewModel_PropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            if (e.PropertyName == "")
            {

            }
        }
    }
}

ObjectStructureHelper class

using System.Collections.Generic;
using DataAccessLayer;
using DataAccessLayer.DirectoryParser;

namespace Model
{
    public class ObjectStructureHelper
    {
        public ObjectStructureHelper(List<Segment> sList1, List<Field> fList1, List<DZOperation> opList, List<Segment> sList2, List<Field> fList2)
        {
            SegmentList1 = sList1;
            FieldList1 = fList1;
            DZOperationList = opList;
            SegmentList2 = sList2;
            FieldList2 = fList2;
        }

        public List<Segment> SegmentList1 { get; set; }
        public List<Field> FieldList1 { get; set; }
        public List<DZOperation> DZOperationList { get; set; }
        public List<Segment> SegmentList2 { get; set; }
        public List<Field> FieldList2 { get; set; }
    }
}

With this code samples I am able to add dynamically comboboxes but I don't have any idea how I could retrieve the selected values of each combobox. Has anyone an idea to solve my problem?

Upvotes: 0

Views: 106

Answers (2)

Roel van Westerop
Roel van Westerop

Reputation: 1440

If you would derive your ObjectStructureHelper from ViewModelBase.ViewModelBase, add the Properties for the ComboBoxes to bind to via the SelectedItem.

public class ObjectStructureHelper : ViewModelBase.ViewModelBase
{
    public Segment     SelectedSegmentList1  // property implementation with propertychanged
    public Field       SelectedFieldList1    // property implementation with propertychanged
    public DZOperation SelectedOperationList // property implementation with propertychanged
    public Segment     SelectedSegmentList2  // property implementation with propertychanged
    public Field       SelectedFieldList2    // property implementation with propertychanged
}

and update your template like this:

<DataTemplate>
    <WrapPanel>
         <ComboBox SelectedItem="{Binding SelectedSegmentList1}" ItemsSource="{Binding Path=SegmentList1}" DisplayMemberPath="SegmentName" />
         <ComboBox SelectedItem="{Binding SelectedFieldList1}" ItemsSource="{Binding Path=FieldList1}" DisplayMemberPath="FieldName" />
         <ComboBox SelectedItem="{Binding SelectedOperationList}" ItemsSource="{Binding Path=DZOperationList}" DisplayMemberPath="OpName" />
         <ComboBox SelectedItem="{Binding SelectedSegmentList2}"  ItemsSource="{Binding Path=SegmentList2}" DisplayMemberPath="SegmentName" />
         <ComboBox SelectedItem="{Binding SelectedFieldList2}" ItemsSource="{Binding Path=FieldList2}" DisplayMemberPath="FieldName" />
    </WrapPanel>
</DataTemplate>

Upvotes: 1

Sheridan
Sheridan

Reputation: 69979

In WPF, we generally work with data elements rather than UI elements. Therefore, instead of writing code to dynamically add ComboBox elements, make your code add data elements instead and then provide a DataTemplate that contains the ComboBox instead.

If you declare a custom class that contains all of the relevant properties required to populate a ComboBox and manage its selected value, then you can declare a DataTemplate for that type that will render a ComboBox each time it comes across one of your class instances:

<DataTemplate DataType="{x:Type YourPrefix:YourClass}">
    <ComboBox ItemsSource="{Binding Items}" SelectedItem="{Binding SelectedItem}" />
</DataTemplate>

Then you can add some of these custom class instances into a collection and data bind that to an ItemsControl.ItemsSource property and they will be rendered as a group of ComboBoxes:

<ItemsControl ItemsSource="{Binding CollectionOfCustomClassInstances}" />

Organising your project like this will mean that you just need to add instances of your class to the collection, rather than actual ComboBoxes and therefore, when you want to look at the results, you already have all of the data at your access... just look at the values of the SelectedItem property in your class instances to find out which values were selected in each ComboBox.

Please see the Data Binding Overview page on MSDN for further help.

Upvotes: 1

Related Questions