I have one ObservableCollection<M> fooBar {get;set;}. The class M.cs looks like this:
public class M{
private int _ID;
public int ID {
get {return this._ID;}
set {this._ID = value;}
}
private string _number;
public int Number {
get {return this._number;}
set {this._number = value;}
}
private string _power;
public int Power {
get {return this._power;}
set {this._power = value;}
}
/*
...
*/
}
Now I want to bind the names of these 3 propertys to a ComboBox. I don't want to do it like this:
<ComboBox>
<ComboBoxItem>ID</ComboBoxItem>
<ComboBoxItem>Number</ComboBoxItem>
<ComboBoxItem>Power</ComboBoxItem>
</ComboBox>
Is there a more comfortable way?
Based on the choose of the first ComboBox I want to fill the second ComboBox. As example I choose in the first ComboBox the property Numberthen the second ComboBox should look like this
<ComboBox
SelectedValue="{Binding ???}"
ItemsSource="{Binding fooBar}"
SelectedValuePath="Number"
DisplayMemberPath="Number"
/>
Maybe someone of you can help me, because I have no idea how to connect both comboboxes.
This is how I would do it:
Make a property on the view model which exposes the properties on the model (class M) which can be selected. This way you explicitly control which properties can be selected.
Make a property to hold the selected value of each combo box.
DisplayMemberPath/SelectedValuePath in ComboBox2 binds to the SelectedValue of ComboBox1.
ViewModel:
// ComboBox 1
public Dictionary<string, string> SelectableProperties = new Dictionary<string, string>()
{
{ nameof (M.ID), "ID" }
{ nameof (M.Number), "Nummer" }
{ nameof (M.Power), "Potenz" }
}
// Selection in combobox 1 (not strictly necessary as it can be handled in view, but you may need to know what SelectedValue represents)
private string _selectedValueMember = String.Empty;
public string SelectedValueMember
{
get { return _selectedValueMember; }
set { _selectedValueMember = value; }
}
// Selection in combobox 2 (object just in case there could be other values than int)
private object _selectedValue = null;
public object SelectedValue
{
get { return _selectedValue; }
set { _selectedValue = value; }
}
public ObservableCollection<M> FooBar{ get; set; }
View:
<ComboBox x:Name="ComboBox1"
Width="100"
Margin="5"
SelectedValuePath="Key"
DisplayMemberPath="Value"
SelectedValue="{Binding SelectedValueMember}"
ItemsSource="{Binding SelectableProperties}">
</ComboBox>
<ComboBox Width="100"
Margin="5"
DisplayMemberPath="{Binding ElementName=ComboBox1, Path=SelectedValue}"
SelectedValuePath="{Binding ElementName=ComboBox1, Path=SelectedValue}"
SelectedValue="{Binding SelectedValue}"
ItemsSource="{Binding FooBar}">
</ComboBox>
For the 1st ComboBox: Use Reflection to get the names of all the properties of class M and put those into the ComboBox.
For the 2nd ComboBox: When selection changes in the 1st one, you get the property name. Now set the SelectedValue binding to the property that was selected in the 1st ComboBox.
Related
I have a combobox with the following options: "HardDelete", "SoftDelete", "MoveToDeletedItems"
I want the default selection to match with the following property of an EmailAction object:
public DeleteMode DeleteMode { get; set; }
Here is the line of code I'm using to try to set this:
cmboDelMode.SelectedItem = emailActionInstance.DeleteMode.ToString();
Related XAML:
<ComboBox x:Name="cmboDelMode" HorizontalAlignment="Left" Margin="149,218,0,0" VerticalAlignment="Top" Width="120">
<ComboBoxItem Content="HardDelete" HorizontalAlignment="Left" Width="118"/>
<ComboBoxItem Content="SoftDelete" HorizontalAlignment="Left" Width="118"/>
<ComboBoxItem Content="MoveToDeletedItems" HorizontalAlignment="Left" Width="118"/>
</ComboBox>
Currently the combobox is defaulting to being empty so is not working as expected. I am able to use "emailActionInstance.DeleteMode.ToString();" to view the data in a text box, so it seems I might just be setting the selected item incorrectly?
The issue is that setting ComboBox.SelectedItem doesn't work unless the ComboBox contains the item you are setting it to. In your case your ComboBox is filled with three ComboBoxItem objects which have their Content property set to a string. So ComboBox.SelectedItem is a ComboBoxItem. You are trying to set the ComboBox.SelectedItem to a string, which will not equal any of the objects contained in the ComboBox. Therefore, nothing happens.
I would suggest setting up Binding for your ComboBox like here:
<ComboBox ItemsSource="{Binding DeleteModes}" SelectedItem="{Binding SelectedDeleteMode}" />
And then create a ViewModel to bind to. If you bind an Enum to a ComboBox it will display correctly so you won't need to call DeleteMode.ToString():
public class ViewModel : INotifyPropertyChanged
{
public ViewModel()
{
DeleteModes = new ObservableCollection<DeleteMode>
{ DeleteMode.HardDelete, DeleteMode.SoftDelete,
DeleteMode.MoveToDeletedItems };
}
public event PropertyChangedEventHandler PropertyChanged;
DeleteMode _selected_delete_mode;
public DeleteMode SelectedDeleteMode {
get { return _selected_delete_mode; }
set {
_selected_delete_mode = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("SelectedDeleteMode"));
}
}
ObservableCollection<DeleteMode> _delete_modes;
public ObservableCollection<DeleteMode> DeleteModes {
get { return _delete_modes; }
set {
_delete_modes = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("DeleteModes"));
}
}
public void update_mode(DeleteMode mode) => SelectedDeleteMode = mode;
}
public class Rma
{
public int Id { get; set; }
}
and this property:
public static readonly DependencyProperty ActRmaProperty =
DependencyProperty.Register("ActRma", typeof(Rma), typeof(MainWindow),new PropertyMetadata(null));
public Rma ActRma
{
get { return (Rma)GetValue(ActRmaProperty); }
set { SetValue(ActRmaProperty, value); OnPropertyChanged("ActRma"); }
}
public static readonly DependencyProperty ItemsByIdProperty =
DependencyProperty.Register("ItemsById", typeof(ObservableCollection<int>), typeof(MainWindow), new PropertyMetadata(null));
public ObservableCollection<int> ItemsById
{
get { return (ObservableCollection<int>)GetValue(ItemsByIdProperty); }
set { SetValue(ItemsByIdProperty, value); OnPropertyChanged("ItemsById"); }
}
and the combobox in xaml:
<ComboBox ItemsSource="{Binding ItemsById}" DisplayMemberPath="Id"
SelectedValuePath="Id" SelectedValue="{Binding ActRma.Id , UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}"
SelectionChanged="ComboBox_SelectionChanged"
Margin="3"
AlternationCount="1"/>
thewhen I change via code behind the value of Id the copmbobox not show the value .
e.g:
ItemsById = new ItemById();
ItemsById.Add(1);
ItemsById.Add(2);
ActRma.Id = 2;
To expand on XAMlMAX's answer- unless you've set your datacontext to itself in the codebehind, you'll need to do in the xaml itself- define x:name and use ElementName in the binding definition-
ItemsSource="{Binding ItemsById,ElementName=_this}"...
From what I can see in your example you are using DependencyProperty for your items in your Window. ComboBox is designed to work with collections so let's use it in MvvM (Model-View-ViewModel).
ViewModel.cs:
private List<int> _cmbList;
public List<int> CmbList//this is the collection that we will use to hold values
{
get { return _cmbList; }
set { _cmbList = value; OnPropertyChanged("CmbList"); }
}
//with additional property
private int _ActRma;
public int ActRma
{
get { return _ActRma; }
set { _ActRma = value; OnPropertyChanged(nameof(ActRma)); }// In here you can handle the changed value of your ComboBox. No need for event handler in this case as setter is called everytime you change selected item in UI.
}
Your view model is then referenced in your MainWindow.xaml:
xmlns:vm="clr-namespace:VM;assembly=VM"
This then should be setting the DataContext of your MainWindow.xaml like so:
<Window.DataContext>
<vm:MainViewModel/>
</Window.DataContext>
At this point your window and all of the elements declared in it will inherit the DataContext object which is our ViewModel.
Then to use the Collection in our ComboBox you can use it like this:
<ComboBox ItemsSource="{Binding CmbItems}" SelectedItem="{Binding ActRmaId}" AlternationCount="1"/><!-- here we hold the Id of the selected item, we don't need to set the Display path as we are binding to the int and this being primitive type doesn't have any properties! -->
I have a combobox binded to a table called Tenderness through MVVM. I'm using Entity Framework.It displays all the records properly, but I need to add another functionality to it. Suppose the user types in text which is not contained inside the combobox's Itemssource, I want to be able to add it directly to the table and then update the Itemssource as well. Now I have been able to do this without MVVM, I would want to know, how to achieve it using MVVM.
Just do what you did previously in the LostFocus event handler in the setter of a source property that you bind to the Text property of the ComboBox.
View Model:
public ObservableCollection<string> Items { get; } = new ObservableCollection<string>() { "a", "b", "c" };
private string _text;
public string Text
{
get { return _text; }
set
{
_text = value;
OnPropertyChanged(nameof(Text));
//add the missing value...
if (!Items.Contains(_text))
Items.Add(_text);
}
}
private string _selectedItem;
public string SelectedItem
{
get { return _selectedItem; }
set
{
_selectedItem = value;
OnPropertyChanged(nameof(SelectedItem));
}
}
View:
<ComboBox IsEditable="True" Text="{Binding Text, UpdateSourceTrigger=LostFocus}" ItemsSource="{Binding Items}"
SelectedItem="{Binding SelectedItem}" />
I want to databind the selected item of a combobox to a c# property. When i do the following, the property get the value "Suite.Module.RateExperiment.ViewModels.ChamberViewModel"(which is not the value of the selected item in the combobox):
<ComboBox DisplayMemberPath="ChamberName" Grid.Column="0" Grid.Row="1" Height="20" VerticalAlignment="Top" ItemsSource="{Binding ChamberCollection}" SelectedValue="{Binding SelectedChamber}">
</ComboBox>
And c#:
public string SelectedChamber
{
get { return _selectedChamber; }
set
{
_selectedChamber = value;
UpdateChart();
}
}
Am i binding wrong since this property gets this value?
SelectedChamber property should be of type ChamberViewModel, try changing it as below:
public ChamberViewModel SelectedChamber
{
get { return _selectedChamber; }
set
{
_selectedChamber = value;
UpdateChart();
}
}
I am not able to find out Why is combo box binding not working?
I have a view model which looks like (2 properties)
public ProcessMaintenanceDataObject CurrentProcess
{
get
{
return _CurrentProcess;
}
set
{
_CurrentProcess = value;
OnPropertyChanged("CurrentProcess");
}
}
public ObservableCollection<ProcessMaintenanceDataObject > Processes
{
get
{
return _Processes;
}
set
{
_Processes = value;
OnPropertyChanged("Processes");
}
}
public ObservableCollection<FolderInfo> Folders
{
get
{
return _folders;
}
set
{
_folders = value;
OnPropertyChanged("Folders");
}
}
The following is the ProcessMaintenanceDataObject definition
[DataMember]
public string ProcessName
{
get
{
return _ProcessName;
}
set
{
_ProcessName = value;
OnPropertyChanged("ProcessName");
}
}
[DataMember]
public string Id
{
get
{
return _Id;
}
set
{
_Id = value;
OnPropertyChanged("Id");
}
}
[DataMember]
public string FolderId
{
get
{
return _FolderId;
}
set
{
_FolderId = value;
OnPropertyChanged("FolderId");
}
}
[DataMember]
public FolderInfo Folder
{
get
{
return _Folder;
}
set
{
_Folder = value;
if (_Folder != null)
FolderId = _Folder.FolderId;
OnPropertyChanged("Folder");
}
}
The FolderInfo class has FolderName and FolderId Property.
I have a method in viewmodel which fills the Processes.
In my view I have structure something like, I have a treeview which will be bound to Processes and while selecting any of the item from the treeview, i need to allow user to edit that entity.
In the view the combo box binding is as:
<ComboBox ItemsSource="{Binding Path=Folders, Mode=OneWay}"
DisplayMemberPath="FolderName"
SelectedItem="{Binding Source={StaticResource viewModel}, Path=CurrentProcess.Folder, Mode=TwoWay}">
...
This binding doesn't work I mean when I select any object from the tree it fills other information like ProcesName in the textBox but it doesn't make the Folder object as the selected item in combobox, however the combo box will be filled.
Any suggestion.
Do refer this:
If you want to bind a ComboBox to your folders property in two way mode with edit support,
Then you should define data template for your combo box and then bind properties of FolderInfo class to those text boxes
Binding display member path will not solve your problem
I'd suggest you to change DisplayMemberPath with appropriate DataTemplate:
<DataTemplate>
<StackPanel>
<TextBlock Text="{Binding FolderName}">
</StackPanel>
<DataTemplate>
This will fix SelectedItem context.
Maybe just maybe, your Folderinfo class is not a notificationObject. If it is the case make sure it implements INotifyPropertyChange.
you have to use SelectedValuePath and SelectedValue instead of SelectedItem like below,
<ComboBox ItemsSource="{Binding Path=Folders, Mode=OneWay}"
DisplayMemberPath="FolderName"
SelectedValuePath="FolderId"
SelectedValue="{Binding Path=FolderId, Mode=TwoWay}">
SelectedItem binds the whole object whereas SelectedValue binds only particular properties of the object.