Reputation: 811
I have a list (ItemsControl
) of questions. Each question has a a combo box, all combo boxes are identical, idea is to implement matching questions.
What I want is to be able to bind selected item and selected question, so I know which combo box was used. I cant figure out how to do that with Combo Box as it doesnt take commands that could be used for other controls.
<ItemsControl ItemsSource="{Binding Path=Question.QuestionResponses}" Grid.Row="1">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"></ColumnDefinition>
<ColumnDefinition Width="Auto"></ColumnDefinition>
</Grid.ColumnDefinitions>
<WebBrowser Margin="0,6,0,6"
Grid.Column="0"
Unloaded="WebBrowserUnload"
util:WebBrowserBehaviors.Body="{Binding QuestionResponse.AnswerText}"></WebBrowser>
<ComboBox Margin="0,6,0,6"
Grid.Column="1"
ItemsSource="{Binding RelativeSource={RelativeSource AncestorType=UserControl},Path=DataContext.Question.MatchesModel.Answers, Mode=OneWay}"
DisplayMemberPath="Answer">
<ComboBox.SelectedItem>
<MultiBinding Converter="{StaticResource MatchConverter}">
<Binding Path="."></Binding>
<Binding Path="."></Binding>
</MultiBinding>
</ComboBox.SelectedItem>
</ComboBox>
</Grid>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
In short, I want to pass two objects to my model/viewModel, so I can process selection. I've tried use converter to construct combined object, but I have no idea how to define target for <ComboBox.SelectedItem>
when multi binding is used. Any help appreciated, I could not find anything online.
Edit I have a list of Combo Boxes, it can be 2 or 20 of them, depending on list size. Each combo box has same item source. I can bind selected item for each combo box, but I have no way to know which text box was used to select item. I need to know id of control that holds the combo box to identify it. I can get selected item and I can get object that holds combo box, what I can't do is to pass those 2 values to my model/viewmodel so I can bind selection with appropriate owner id. Content of combo boxes or their owner is completely irrelevant I just want to identity which combo box was used. I realize I can do this via code behind, but I prefer mvvm way, I could aslo replicate item source and contain control in it, that is a lot of duplicate data, but might make it easier to persist selected answers.
Upvotes: 0
Views: 1555
Reputation: 811
If anyone else get stuck on similar problem like this where you want selected statements to match selection from multiple combo boxes and you're wondering how to identity which combo box was used. I've overcame this by having a list of models for each combo box. This way you can store ID of the statement, it also allows to easier store selected items should you ever want to load selection from the database instead of only storing it.
public class QuestionMatchesModel :BaseModel
{
public ObservableCollection<MatchOptions> Answers { get; set; }
private MatchOptions _selected;
public MatchOptions Selected
{
get => _selected;
set
{
_selected = value;
RaisePropertyChanged("Selection");
}
}
}
public class MatchOptions : BaseModel
{
public long ResponseId { get; set; }
public long MatchId { get; set; }
public string Answer { get; set; }
}
}
Example Model that can be used, create a list out of this for each statement in your main model.
Upvotes: 1
Reputation: 13438
Lets suppose you have a list of items of type MatchItemViewModel
and for each item, you have a description text SomeText
and the user should select a matching question/answer/whatever from a combobox into property SelectedFromCombobox
. The match items and the possible values to be displayed in the comboboxes are placed in a parent viewmodel ViewModel
:
public class ViewModel
{
private ObservableCollection<MatchItemViewModel> _ListItems = new ObservableCollection<MatchItemViewModel>();
public ObservableCollection<MatchItemViewModel> ListItems
{
get { return _ListItems; }
}
private ObservableCollection<string> _ComboboxItems = new ObservableCollection<string>();
public ObservableCollection<string> ComboboxItems
{
get { return _ComboboxItems; }
}
}
public class MatchItemViewModel : INotifyPropertyChanged
{
private string _SomeText;
public string SomeText
{
get { return _SomeText; }
set { _SomeText = value; RaisePropertyChangedEvent(); }
}
private string _SelectedFromCombobox;
public string SelectedFromCombobox
{
get { return _SelectedFromCombobox; }
set { _SelectedFromCombobox = value; RaisePropertyChangedEvent(); }
}
public event PropertyChangedEventHandler PropertyChanged;
protected void RaisePropertyChangedEvent([CallerMemberName]string prop = null)
{
var handler = PropertyChanged;
if (handler != null) handler(this, new PropertyChangedEventArgs(prop));
}
}
For my tests, I initialized the data in my window constructor as follows:
public MainWindow()
{
InitializeComponent();
var vm = new ViewModel();
vm.ListItems.Add(new MatchItemViewModel() { SomeText = "Red dogs are strange" });
vm.ListItems.Add(new MatchItemViewModel() { SomeText = "I'm hungry" });
vm.ComboboxItems.Add("What do you think of red dogs?");
vm.ComboboxItems.Add("Current state of mind");
grid1.DataContext = vm;
}
And this is the window content XAML:
<Grid x:Name="grid1" Margin="2">
<Grid.Resources>
<CollectionViewSource x:Key="ComboBoxItemsSource" Source="{Binding ComboboxItems}"/>
</Grid.Resources>
<ItemsControl ItemsSource="{Binding ListItems}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"></ColumnDefinition>
<ColumnDefinition Width="Auto"></ColumnDefinition>
</Grid.ColumnDefinitions>
<TextBlock Text="{Binding SomeText}" MinWidth="100" VerticalAlignment="Center"/>
<ComboBox Margin="0,6,0,6"
Grid.Column="1"
ItemsSource="{Binding Source={StaticResource ComboBoxItemsSource}}"
IsSynchronizedWithCurrentItem="False"
SelectedItem="{Binding SelectedFromCombobox}">
</ComboBox>
</Grid>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Grid>
The important part is, in order to make the combobox items available to each list item, I create a CollectionViewSource
named ComboBoxItemsSource
outside the list and I reference this collection by {StaticResource ComboBoxItemsSource}
in each list item. Also it's important to set IsSynchronizedWithCurrentItem="False"
in the comboboxes, because otherwise all of them would always update to the same selected item.
Upvotes: 0