Reputation: 916
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
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
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 ComboBox
es:
<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 ComboBox
es 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